6

考虑以下代码片段

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

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

4

6 回答 6

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例如。问题是并非所有小数都可以转换为二进制小数的有限和。

这是这个数字的转换方式(第一行是列定义)。

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
于 2010-11-11T12:42:39.300 回答
4

因为浮点数是二进制分数,因此只能近似表示您的十进制数。281.583f当源代码中的文字被解析为 IEEE 754 浮点值时,就会发生近似值。

使用花车本身,这被掩盖了,因为println打印

将参数值与浮点类型的相邻值唯一区分所需的位数。

在许多情况下,这意味着将打印文字的十进制值。但是,当您将值分配给 adouble时,“double 类型的相邻值”通常比 type 的值更接近float,因此您可以看到近似浮点的真实值。

有关更多详细信息,请阅读浮点指南

于 2010-11-11T12:59:08.083 回答
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 位。

于 2010-11-11T12:58:57.633 回答
0

据我了解,您担心的是,为什么此代码...

float f = 281.583f;
System.out.println(f);
System.out.println((double) f);

...印刷

281.583
281.5830078125

嘿,双精度更高! )

这就是为什么...

438ccaa0(表示 的位的十六进制格式,281.583f由 给出Integer.toHexString(Float.floatToRawIntBits(281.583f)))输入到此处的表格中。您将看到浮点数实际上表示为281.58301. (@Michael Borgwardt 回答了为什么不这样打印。)

当表示为浮点数时,正在281.583打印。281.58301但是当你转换281.58301为双精度时,你实际上可以接近281.58301than281.583

查看上述网页的计算,您可以得到尽可能接近的结果,281.58300781250000这就是您看到281.5830078125正在打印的值的原因。

于 2010-11-11T13:44:41.457 回答
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
于 2010-11-11T17:31:09.610 回答
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 和四舍五入 = dblPrecision。

现在 0x1.19954p8 = 100011001.100101010100 = 281.5830078125,并且 0x1.19947ap8 = 100011001.1001010001111010 = 281.579986572265625。正在发生的一切是它们在打印时四舍五入的方式不同(浮点数被四舍五入到比双精度数少的位数)。

于 2010-11-11T21:53:45.443 回答