请考虑以下代码段
float num = 281.583f;
int amount = (int) Math.round(num*100f);
float rounded = amount/100.0f;
double dblPrecision = rounded;
double dblPrecision2 = num;
System.out.println("num : " + num + " amount: " + amount + " rounded: " + rounded + " dbl: " + dblPrecision + " dbl2: " + dblPrecision2);
我得到的输出是
num : 281.583 amount: 28158 rounded: 281.58 dbl: 281.5799865722656 dbl2: 281.5830078125
为什么在将浮点数分配给双变量时有近似值?
答案 0 :(得分:6)
将小数部分转换为float
时实际发生近似值。我可能会对您感到惊讶,但281.583
无法在PC中表示完全作为浮点数。这是因为浮点数表示为PC中二进制分数的总和。 0.5
,0.25
和0.125
可以精确转换,但不能转换0.583
。
浮点数(和双精度数)表示为Σ( 1/2^i*Bi )
,其中Bi
是第i位(0|1)
。例如0.625 = 1/2 + 1/4
。问题是并非所有小数部分都可以转换为 finitie 二进制分数之和。
以下是此数字的转换方式(第一行是列定义)。
i| *2 and trim| Bit value| (2^-1)*bit
0,583
1 1,166 1 0,5
2 0,332 0 0
3 0,664 0 0
4 1,328 1 0,0625
5 0,656 0 0
6 1,312 1 0,015625
7 0,624 0 0
8 1,248 1 0,00390625
9 0,496 0 0
10 0,992 0 0
11 1,984 1 0,000488281
12 1,968 1 0,000244141
13 1,936 1 0,00012207
14 1,872 1 6,10352E-05
15 1,744 1 3,05176E-05
16 1,488 1 1,52588E-05
17 0,976 0 0
18 1,952 1 3,8147E-06
19 1,904 1 1,90735E-06
SUM= 0,582998276
答案 1 :(得分:4)
因为浮点数是二进制分数,因此只能代表您的十进制数。当源代码中的文字281.583f
被解析为IEEE 754浮点值时,就会发生近似。
对于花车本身,这是因为println
prints
尽可能多,但只有更多,更多的数字 如需要唯一区分 来自邻近的参数值 float类型的值。
在许多情况下,这意味着将打印文字的十进制值。但是,当您将值分配给double
时,“double类型的相邻值”通常比类型float
更接近,因此您可以看到近似值的真实值浮。
有关详细信息,请阅读The Floating-Point Guide。
答案 2 :(得分:0)
近似值是整个时间。只是碰巧双重提供了额外的东西才能显示额外的东西。
281.583,例如二进制(对于很多数字,但小于双精度): 100011001.1001_0101_0011_1111_0111_1100_1110_1101_1001 ...
Float允许大约23位,而double允许大约52位。 (不记得确切) 100011001.1001_0101_0011_11,小数点是281.582946777。
作为参考,单精度存储到大约7个十进制数字,双精度存储到大约16个十进制数字。这包括所有数字,所以你的数字只比浮点数的精度小1位数。
答案 3 :(得分:0)
据我所知,你关心的是,为什么这段代码......
float f = 281.583f;
System.out.println(f);
System.out.println((double) f);
...打印
281.583
281.5830078125
(嘿,double提供更多精度!)
这就是为什么......
将438ccaa0
(代表281.583f
的位的十六进制格式,由Integer.toHexString(Float.floatToRawIntBits(281.583f))
提供)输入here格式。你会看到浮动实际表示为281.58301
。 (@Michael Borgwardt回答为什么它不是那样印刷的。)
因此,当281.583
表示为浮动时,281.58301
正在打印281.58301
。但是,当您将281.58301
转换为双倍时,实际上可以更接近到281.583
而不是281.58300781250000
!
查看上述网页的计算结果,您可以尽可能接近281.5830078125
,这就是为什么您会看到正在打印的值{{1}}。
答案 4 :(得分:0)
简而言之,除非你真的需要,否则不要使用浮动。你将失去精确度,并可能节省很少。使用双倍,你将为自己节省很多悲伤。
double num = 281.583;
long amount = (long) (num*100);
double rounded = (double) amount/100;
double dblPrecision = rounded;
double dblPrecision2 = num;
打印
num : 281.583 amount: 28158 rounded: 281.58 dbl: 281.58 dbl2: 281.583
答案 5 :(得分:0)
浮动和双打在内部实际上具有相同的值;它们的打印方式不同。将这些行添加到程序中以十六进制查看它们:
System.out.printf("num: %a\n",num);
System.out.printf("dblPrecision2: %a\n",dblPrecision2);
System.out.printf("rounded: %a\n",rounded);
System.out.printf("dblPrecision: %a\n",dblPrecision);
打印
num: 0x1.19954p8
dblPrecision2: 0x1.19954p8
rounded: 0x1.19947ap8
dblPrecision: 0x1.19947ap8
num = dblPrecision2 and rounded = dblPrecision。
现在0x1.19954p8 = 100011001.100101010100 = 281.5830078125,和0x1.19947ap8 = 100011001.1001010001111010 = 281.579986572265625。所有发生的事情是它们在打印时会有不同的四舍五入(浮点数被舍入到比双精度数更少的数字)。