浮动到双重赋值

时间:2010-11-11 12:36:32

标签: 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 + " dbl: " + dblPrecision + " dbl2: " + dblPrecision2);

我得到的输出是

num : 281.583 amount: 28158 rounded: 281.58 dbl: 281.5799865722656 dbl2: 281.5830078125

为什么在将浮点数分配给双变量时有近似值?

6 个答案:

答案 0 :(得分:6)

将小数部分转换为float时实际发生近似值。我可能会对您感到惊讶,但281.583无法在PC中表示完全作为浮点数。这是因为浮点数表示为PC中二进制分数的总和。 0.50.250.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。所有发生的事情是它们在打印时会有不同的四舍五入(浮点数被舍入到比双精度数更少的数字)。