明白了,但还想问yanhuaxie(IT Farmer)一个问题,您别笑我太苯啊~~在你的例子里: “double a = 3.0; double b =2.95. for (int i = 0; i < 15 ;i++) a-=0.01; if (a == b ) //通常认为肯定会相等,条件值肯定ture,但是实际运行却不是,当然 ...... //这不是你的错,是计算机的错.计算机结果是近似取近似值,而判断 ....//却是精确值” 如果在程序中真的需要A和B的比较得到一个布尔值,应该怎么做呢??
测试一下,就知道了class Test { public static void main(String[] args) {float a = 3f; for(int i=0;i<200;i++) a-=0.01; a = (int)a; System.out.println(a); } }
shichunzhidezhanghu()的问题:标准的float型与“零值”比较的 if 语句可以这样写: const float EPSINON = 0.00001; if ((x >= - EPSINON) && (x <= EPSINON) 注:不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式。类推一下a和b相比只要加个偏移就行了
就像DOUBLE的0。0无限接近于0一样
怎么会输出那么多次啊a = (int)a;
其中(int)a ==1 是可以确定了
为什么输出是1.0呢,是因为a是float型的
这句的效果就是 float a =1 一样
虽然(int)a=1,但a仍然是float的啊!所以输出为1.0
人类使用的是十进制,所以你觉得a的结果为1.0,但计算机用的是二进制啊,结果a等于1.0000009,就好比你没法用十进制精确得表示1/3一样!
for(int i=0;i<200;i++)
a-=0.01;
a = (int)a;
System.out.println(a);//为什么那么多人不理解结果是1.0呢??程序中的a是float类型,它是全局的,
a = (int)a;
实际上是:float a = (int)a;
等式右边强制类型转换(float-->int),所以结果是1,而等式左边,由于a是float类型,将int行赋值给float类型,就发生了自动类型(隐式类型转换)转换了(int-->float);所以结果是1.0;至于在计算过程中为什么出现;第 9 次=====2.9
第 10 次=====2.89
第 11 次=====2.88
第 12 次=====2.8700001
第 13 次=====2.8600001我也同意是计算机进制之间转换的问题
for(int i=0;i<200;i++)
a-=0.01;在这个计算过程中有没有方法测算出任一次循环后a的值呢?
for(int i=0;i<200;i++)
a-=0.01;
a = (int)a;
System.out.println(a);//楼主题目都写错了。。如果结果是你这样的话:
......
......
第 9 次=====2.9
第 10 次=====2.89
第 11 次=====2.88
第 12 次=====2.8700001
第 13 次=====2.8600001
.....那么就要注释这一句 //a = (int)a;
结果是1.000019
应该是十进制和二进制转换之间出现的问题哦。。
在这个计算过程中有没有方法测算出任一次循环后a的值呢?-------------------------------------------------------------晕。。要看的话就在FOR里面加条件咯
===================================================================================
怎么加?
......
......
第 9 次=====2.9
第 10 次=====2.89
第 11 次=====2.88
第 12 次=====2.8700001
第 13 次=====2.8600001
.....
这是我测试打印的中间值,大家都认为是"十进制和二进制转换之间出现的问题",是怎样的问题呢?如果在没运行程序前是否能判断出第97次后的值呢?
......
(a = (ing)a;) 和(float a = (int)a)
将结果float type casting int 再赋值给float type 。
结果是多少我就不想去计算了。。
double类型的输出结果:第 0 次 2.99
第 1 次 2.9800000000000004
第 2 次 2.9700000000000006
第 3 次 2.960000000000001
第 4 次 2.950000000000001
.......
.......
精度越大的输出的位数越多.什么原因,这就是double的精度比float高的原因.至于计算过程为什么会有2.950000000000001这种情况出现,我想无非就是上面我说的三种情况,其中最位关键的是第三种--计算机中的浮点数怎么表示的(这里我不再细细说明,想深入理解的话,可以去看 "计算机原理" 这门课程,或者去看看 "IEEE754标准" 中怎么定义的):java也是采用IEEE754标准来表示浮点数, 根据IEEE的标准,浮点数的定义如下:
在数字中,表示一个浮点数需要三要素:尾数(Mantissa)、指数(Exponent,又称为阶码)和基数(Base)。任意一个浮点数N可以表示成下列形式:N = M × BE,例如N(10) =1.234×10-6, N(2)= -0.001011×2011等.M和E决定了浮点数的精度(precision),E指明小数点在B进制数据中的位置,因而E和B决定了浮点数的表示范围(range),浮点数的符号(Sign)是单独考虑,表示为:
______________________________
|符号位(S) | 阶码(E) | 尾数(M)|
------------------------------
为便于软件的移植,浮点数的表示格式应该有统一标准。1985年IEEE(Institute of Electrical and Electronics Engineers)提出了IEEE754标准。该标准规定基数为2,阶码E用移码表示,尾数M用原码表示,根据原码的规格化方法,最高数字位总是1,该标准将这个1缺省存储,使得尾数的表示精度多了一位。实数的IEEE754标准的浮点数格式为:____________________________________________________________________________
| | 存储位数 | |偏移量 |
|类型 |---------------|------------|--------------|总位数 | offset |
| | 数位(S) | 指数位(E)| 小数部分(M) | | |
|------------------|---------------|------------|--------------|-------|--------|
|单精度浮点数float | 1 位 | 8位 | 23位 | 32 | 127 |
|------------------|---------------|------------|--------------|--------|--------|
|双精度浮点数double| 1 位 | 11 位| | 52位 | 64 | 1023 |
|----------------------------------|------------|--------------|--------|--------|
说明: 1) 约定小数点左边隐含有一位1,实际上使尾数的有效位数为24位,即尾数为1.M
2) 偏移值 = 2 ^ (尾数位数 - 1) – 1。必须从指数中减去偏移值,才能确定有符号指数的实际值。
3) 讨论float型:
E = 0, M = 0 , 若 S = 0, 则N = 0; S = 1, 则 N = -0。-0可以表示一个很小的数,小到在单精度格式中不能
用数字和指数来表示。尽管如此,它们然小于0。
E = 0, M ≠ 0, 则数是有效的,但不是规格化数, N = (-1) ^ S × 2 ^ ( - 127) × (0.M)
E = 255, M = 0, 则数为正或负无穷大, 这取决于S.
E = 255, M ≠ 0, 则N不是一个数, 表示为NaN.
E = 1 ~ 254, 则N = (-1) ^ S × 2 ^ (E - 127) × (1.M), 为规格化数.规格化表示
java中的浮点数采用的事IEEE Standard 754 Floating Point Numbers标准,
float占用4个字节,和int是一样,也就是32bit.
第1个bit表示符号,0表示正数,1表示负数,这个很好理解,不用多管.
第2-9个bit表示指数,一共8为(可以表示0-255),这里的底数是2,为了同时表示正数和负
数,这里要减去127的偏移量.这样的话范围就是(-127到128),另外全0和全1作为特
殊处理,所以直接表示-126到127. 剩下的23位表示小数部分,这里23位表示了24位的数字,因为有一个默认的前导1(只有二进制才有这个特性). 最后结果是:(-1)^(sign) * 1.f * 2^(exponent) 这里:sign是符号位,f是23bit的小数部分,exponent是指数部分,最后表示范围是(因为正负数是对称的,这里只关心正数)2^(-126) ~~ 2(1-2^(-24)) * 2^127这个还不是float的取值范围,因为标准中还规定了非规格化表示法,另外还有一些特殊规定.
非规格化表示:
当指数部分全0而且小数部分不全0时表示的是非规格化的浮点数,因为这里默认没有前导1,而是0. 取值位0.f * 2^(-126),表示范围位 2^(-149)~~ (1-2^(-23)) * 2^(-126) 这里没有考虑符号.这里为什么是-126而不是-127? 如果是-127的话,那么最大表示为2^(-127)-2^(-149),很显然2^(-127) ~~2^(-126) 就没法表示了. 其他特殊表示
1.当指数部分和小数部分全为0时,表示0值,有+0和-0之分(符号位决定),0x00000000表示正0,0x80000000表示负0.
2.指数部分全1,小数部分全0时,表示无穷大,有正无穷和负无穷,0x7f800000表示正无穷,0xff800000表示负无穷.
3.指数部分全1,小数部分不全0时,表示NaN,分为QNaN和SNaN,Java中都是NaN.------------------------------------------
建议在程序中,对浮点数进行判断时,如果有一值是通过运算得来的,最好不要用他们作为条件判断,否则你会得到异想不到的结果.
如
double a = 3.0;
double b =2.95.
for (int i = 0; i < 15 ;i++)
a-=0.01;
if (a == b ) //通常认为肯定会相等,条件值肯定ture,但是实际运行却不是,当然
...... //这不是你的错,是计算机的错.计算机结果是近似取近似值,而判断 ....//却是精确值
else
......
java的例子可能不好看,因为class文件不号看.我们就看看c环境下的一个程序:main()
{
float f=123.456;
printf("f=%f\n",f);
}一般认为都是输出123.456,实际是123.456001;这是c的最大精度吧,很久没有碰c了,c中float好像是双字节.
我们来看看是怎么得出的,当然是按我上面写的方法来了:
我们去看看编译后的文件,有一条汇编语句:00401028 mov dword ptr [ebp-4],42F6E979h
其中十六进制数42F6E979h就是我们程序中的123.456;
十六进制值42F6E979h由何而来?
十进制 二进制
N(10)=123.456=111011.01110100101111001= 1. 11101101110100101111001(...) * 2^6= N(2)
, 那么E – 127 = 6; E = 127 + 6 = 133(10) = 10000101(2),
M = 111 0110 1110 1001 0111 1001 (省略了最高数字位1, 共23bit)组合起来就是:
S E M
0 10000101 111 0110 1110 1001 0111 10014bit一间隔还成十六进制:
0100 0010 1111 0110 1110 1001 0111 1001
4 2 F 6 E 9 7 9 = 42F6E979H
再由42F6E979h还原为float型取出十六进制数42F6E979h, 化为二进制为
0*100 0010 1*111 0110 1110 1001 0111 1001(*为区分点)
s=0, E=133, M=(1/2+1/4+1/8+1/32+1/64+1/256+1/512+...)=0.92900002002716064453125N=1*64*(1+0.92900002002716064453125)=123.45600128173828125123.456 约等于 123.456001 约等于 123.456001 28173828125
“double a = 3.0;
double b =2.95.
for (int i = 0; i < 15 ;i++)
a-=0.01;
if (a == b ) //通常认为肯定会相等,条件值肯定ture,但是实际运行却不是,当然
...... //这不是你的错,是计算机的错.计算机结果是近似取近似值,而判断 ....//却是精确值”
如果在程序中真的需要A和B的比较得到一个布尔值,应该怎么做呢??
{
public static void main(String[] args)
{float a = 3f;
for(int i=0;i<200;i++)
a-=0.01;
a = (int)a;
System.out.println(a);
}
}
const float EPSINON = 0.00001;
if ((x >= - EPSINON) && (x <= EPSINON)
注:不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式。类推一下a和b相比只要加个偏移就行了