4

这是参考此问题中的评论:

Java 中的这段代码生成 12.100000000000001,这是使用 64 位双精度数,可以精确地呈现 12.1。– 热解

这是真的?我觉得由于浮点数表示为 2 的幂的和,所以无论你有多少位,你都不能准确地表示 12.1。但是,当我实现了这两种算法并打印了使用具有许多有效数字的 (12.1, 3) 调用它们的结果时,我分别得到了他和我的结果:

12.10000000000000000000000000000000000000000000000000000000000000000000000000 12.10000000000000100000000000000000000000000000000000000000000000000000000000

我使用String.format("%76f"). 我知道这比必要的零多,但我在 12.1 中看不到任何舍入。

4

9 回答 9

15

不。正如其他人在他的评论的后续文章中指出的那样,(有限数量的)2 的幂的总和永远不会恰好等于 12.1。就像你不能精确地表示以十为底的 1/3,无论你在小数点后使用多少位。

于 2009-12-14T23:43:26.373 回答
12

在二进制中,12.1 是:

1100.000110011001100110011...

由于这不会终止,因此它不能用 double 或任何其他有限宽度二进制浮点类型的 53 个有效位精确表示。

于 2009-12-14T23:47:13.940 回答
9

尝试用二进制表示 0.1:
0.5 太大
0.25 太大
0.125 太大
0.0625 适合,剩下 0.0375
0.03125 适合,剩下 0.00625
0.015625 太大
0.0078125 太大
0.00390625 适合,然后离开余数为 0.00234375
0.001953125 适合,余数为 0.000390625

它将无限期地重复,创建一个 0.00011001100 的基数 2 值......

不,它不能精确地用双精度表示。如果 Java 支持 BCD 或定点十进制,那将完全有效。

于 2009-12-14T23:51:50.897 回答
3

不是二进制的,不。如果您允许我幻想,您可以使用“浮点二进制编码的十进制”(据我所知,从未实现过):

12.1 = 0000 . 0001 0010 0001 * (10^2)

在二进制中,所有非零值的形式都是1.xyz * m,而 IEEE 形式利用这一点来省略前导 1。我不确定 FP-BCD 的等价物是什么,所以我选择了形式的0.xyz * m值.

于 2009-12-14T23:59:02.650 回答
2

我建议阅读每个计算机科学家应该知道的关于浮点运算的知识。那你就肯定知道了。:)

于 2009-12-15T00:05:27.793 回答
2

一种查看 double 究竟是什么的方法是将其转换为 BigDecimal。

// prints 12.0999999999999996447286321199499070644378662109375
System.out.println(new BigDecimal(12.1));
于 2009-12-15T19:24:04.063 回答
2

是的,您可以用浮点数精确表示 12.1。您只需要十进制浮点表示,而不是二进制表示。

使用 BigDecimal 类型,您将准确地表示它!

于 2014-01-28T18:43:05.640 回答
2

不,十进制数12.1不能表示为有限(终止)二进制浮点数。

记住那12.1是有理数121/10。请注意,这个分数是最低的(不能通过去除分子和分母的共同因素来减少)。

假设(为了达到矛盾)121/10也可以写成n / (2**k)wherenk是一些正整数,并且2**k表示k2 的 th 次方。我们将有一个唯一分解的反例。尤其

10 * n == 2**k * 121

其中左侧可以被 5 整除,而右侧则不能。

于 2014-11-05T14:18:19.803 回答
0

您可以使用的一种选择是不存储 v=0.1,而是存储 v10=1。只需在需要时除以 10(除法会在您的结果中产生截断错误,但 v 仍然可以)

在这种情况下,您基本上是在进行定点破解,但将数字保持在浮点数中。但它通常不值得这样做,除非你真的必须这样做。

于 2009-12-15T00:00:54.147 回答