Java 浮点到双赋值
考虑下面的代码片段Java 浮点到双赋值,java,floating-accuracy,approximation,double-precision,Java,Floating Accuracy,Approximation,Double Precision,考虑下面的代码片段 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 + " d
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
当一个浮点数被分配给一个双变量时,为什么会有近似值呢?当您将小数转换为
浮点数时,实际上会出现近似值。我可能会让你感到惊讶,但是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
。问题是并非所有的十进制分数都能转换成二进制分数的有限和
下面是该数字的转换方式(第一行是列定义)
近似值始终存在。碰巧的是,double提供了足够多的额外比特,使得额外的东西显示出来 例如,281.583是二进制的(许多数字,但小于双精度): 100011001.1001\U 0101\U 0011\U 1111\U 0111\U 1100\U 1110\U 1101\U 1001 Float允许大约23位,double允许大约52位。(记不清了) 100011001.1001_0101_0011_11,十进制为281.582946777 作为参考,单精度存储约7位小数,双精度存储约16位小数。这包括了所有的数字,所以你的数字只比浮点数的精度低1位数。因为浮点数是二进制分数,因此只能近似地表示十进制数。当源代码中的文字
281.583f
被解析为IEEE 754浮点值时,就会出现近似值
对于浮动本身,这一点被掩盖了,因为
同样多,但只有同样多,更多的数字
作为唯一的区分所需要的
来自相邻参数的参数值
float类型的值
在许多情况下,这意味着将打印文本的十进制值。但是,当您将值分配给double
时,“double类型的相邻值”通常比float
类型的值更接近,因此您可以看到近似float的真实值
有关更多详细信息,请阅读。据我所知,您关心的是,为什么要使用此代码
float f = 281.583f;
System.out.println(f);
System.out.println((double) f);
…印刷品
281.583
281.5830078125
(嘿,double提供了更高的精度!)
这就是为什么
将438ccaa0
(表示281.583f
的位的十六进制格式,如Integer.tohextstring(Float.floatToRawIntBits(281.583f))
所示)输入到表单中。您将看到,浮点实际上表示为281.58301
。(@Michael Borgwardt回答了为什么它不是那样印刷的。)
因此,当表示为浮点数时,将为281.58301
打印281.583
。但是当你把281.58301
转换成双精度时,你实际上可以比281.583
更接近281.58301
查看上述网页的计算结果,您可以得到接近于281.58300781250000的值,这就是为什么您会看到值281.5830078125被打印出来的原因。简而言之,除非确实需要,否则不要使用float。您将失去精度,可能节省很少。使用双倍,你将避免很多悲伤
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
浮动和双精度在内部实际上具有相同的值;它们只是印刷方式不同而已。将这些行添加到您的程序中,以十六进制方式查看它们:
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,四舍五入=dblPrecision
现在0x1.19954p8=100011001.100101010100=281.5830078125,0x1.19947ap8=100011001.100101000111010=281.57998657226625。所发生的一切是,它们在打印时的取整方式不同(浮点数取整到的位数小于双精度浮点数)。是的,这是所有双精度浮点数的问题。这与作业无关。@Erick Robertson这就是我要解释的。将浮点转换为双精度并不能“让你更接近”精度的损失;你得到了同样的近似值(见我的答案)。@Rick,仔细阅读。它使您比为浮点表示打印的值更接近。但是您写道“但是当您将281.58301转换为双精度时,您实际上可以比281.583更接近281.58301”。关键是打印,而不是转换。如果你用“printf(%.17f”)”来打印,两者给出的答案都是一样的——281.5830078125000000。顺便说一句,我假设你是指问题中的浮点到双精度转换——281.583。你有没有提出一个不同的观点,关于直接给一个双人间分配一个不同的号码281.58301?如果是这样的话,那么就得到了281.583010000000001582520781084895133972176796875。
num: 0x1.19954p8
dblPrecision2: 0x1.19954p8
rounded: 0x1.19947ap8
dblPrecision: 0x1.19947ap8