将浮点值分配给双精度值

9

我是参考这个Oracle文档的。在尝试执行以下操作时:

 public static void main(String args[]){

    float f = 1.1f;
    double df = 1.1f;

    System.out.println("f=" + f);
    System.out.println("df=" + df);

    f = 1.5f;
    df = 1.5f;
    System.out.println("f=" + f);
    System.out.println("df=" + df);
 }

输出结果为
f  = 1.1
df = 1.100000023841858
f  = 1.5
df = 1.5

第二行输出为什么显示的是近似值,但第四行不是呢?这个值是如何计算出来的?

顺便提一下,1.1f 是一个 float 字面量,将其赋值给 double 可能会产生误导。 - Eel Lee
第一个只是不向您显示其具有相同的近似值。http://floating-point-gui.de/ - zapl
2
df是这个1.500000000000000实际的值,零被省略了。 - mangusta
有关浮点数表示的更多信息,请参考IEEE 754标准。 - mangusta
@mangusta:感谢您提供IEEE 754的提示。http://babbage.cs.qc.cuny.edu/IEEE-754/ - Nidheesh
1
你的问题实际上是关于将单精度值打印为双精度值。简而言之,Java会打印足够的数字以确定单精度或双精度值的确切值。当你将1.1f打印为double时,类型具有更高的精度,因此需要更多的数字来使其不含糊地表示出所需的double。请参见https://dev59.com/HnNA5IYBdhLWcg3wjOpS。 - Pascal Cuoq
3个回答

4
区别在于 1.5 可以在双精度浮点数中准确表示,而 1.1 无法准确表示。这是因为循环小数的缘故,在分母中有一个质因数不属于该进制的任何一位时,任何(既约)分数都需要在某个位置之后重复周期性地使用无限数量的数字。例如,在十进制中,1/43/58/20 是有限的,因为 2510 的质因数。但是,1/32/31/75/6 都不是有限的,因为 37 不是 10 的因数。在分母中有一个质因数 5 的分数在基数为 10 时可以是有限的,但在基数为 2 时则不行——这是大多数新手使用浮点数时最容易混淆的地方。
挤压无限多的实数到有限数量的位需要一个近似表示。虽然有无限多个整数,但在大多数程序中,整数计算的结果可以存储在32位中。相比之下,对于任何固定数量的位,大多数实数计算产生的量都不能使用那么多位来精确表示。因此,浮点计算的结果通常必须舍入以适应其有限表示。这种舍入误差是浮点计算的特征。

更多详细信息请查看这里


这个近似值是如何计算的? - Nidheesh
但他两次都分配了1.1f(而不是1.1)。它不应该是相同的常量吗? - starmole
@starmole将1.1f赋值给double会导致一个不够精确的数字,当以双精度数打印时,它是如此不准确,以至于它打印了000023..部分,而直接以float打印则跳过了打印这种不准确性,因为它知道在某个点之后没有更多的值需要打印。如果您将1.1作为double赋值,您将更接近1.1,因为有更多的位可以使用。那将打印为“1.1”。 - zapl
3
Java默认的浮点数输出精度是仅打印足以唯一标识其类型的值的位数。在float中,“1.1”就足够了,因为1.1f(恰好为1.10000002384185791015625)比任何其他float更接近1.1。但在double中,“1.1”的精度不够,因为double值1.100000000000000088817841970012523233890533447265625比1.10000002384185791015625更接近1.1,因此需要更多的数字才能更接近1.10000002384185791015625的值。 - Eric Postpischil

3

示例

考虑二进制,特别是在处理小数位时的二进制。

4    2    1  .  1/2    1/4    1/8
0    0    1  .  1      0      0

如您所见,电脑可以轻松地表示这个数。现在让我们来看一下1.1

4    2   1   .  1/2    1/4    1/8    1/16
0    0   1   .  0      0      0      1

目前,我们有1.0625。可以想象,要精确地得到0.0475有些困难,但为了举例,我们可以继续尝试。
4    2   1   .  1/2    1/4    1/8    1/16    1/32     1/64     1/128
0    0   1   .  0      0      0      1       1        0        0

现在我们已经更新到了1.8版本,让我们继续前进吧。
4    2   1   .  1/2    1/4    1/8    1/16    1/32     1/64     1/128
0    0   1   .  0      0      0      1       1        1        0

我们必须达到 0.915625 的目标...

4    2   1   .  1/2    1/4    1/8    1/16    1/32     1/64     1/128
0    0   1   .  0      0      0      1       1        1        1

我们现在的数值为0.9234375

解释

我相信你能看出这个问题所在。在你想要表示的数字和二进制可以表示的数字之间总会存在误差。有时候会很顺利,比如说1.5,二进制可以完美地表示。但有时候也会遇到问题,比如说1.1,此时二进制最多只能尽可能地靠近目标数值。


1

正如我们所知,双精度浮点数表示的数字比单精度浮点数更准确。单精度浮点数用32位表示,而双精度浮点数用64位表示。因此,当将单精度浮点数分配给双精度浮点数时,数字从32位扩展到64位。然后,不准确的数字以准确的方式表示。所以,你现在明白了吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接