12.1可以完全表示为浮点数吗?

时间:2009-12-14 23:41:08

标签: java math floating-point numbers floating-accuracy

这是参考this question中的评论:

  

Java中的这段代码产生12.100000000000001,这是使用64位双精度,它可以精确地呈现12.1。 - Pyrolistical

这是真的吗?我觉得因为浮点数表示为2的幂的总和,所以无论你有多少位,你都不能完全代表12.1。然而,当我实现这两个算法并打印出使用(12.1,3)调用它们的结果时,我得到了许多有效数字,我得到了他和我的分别:

12.10000000000000000000000000000000000000000000000000000000000000000000000000 12.10000000000000100000000000000000000000000000000000000000000000000000000000

我使用String.format("%76f")打印出来。我知道这比所需要的更多零,但我没有看到12.1中的任何四舍五入。

9 个答案:

答案 0 :(得分:15)

没有。正如其他人在他的评论的后续文章中所指出的那样,两个(有限数量)两个幂的总和不能恰好相加到12.1。就像你不能在十进制中完全代表1/3,无论你在小数点后使用多少位数。

答案 1 :(得分:12)

在二进制中,12.1是:

1100.000110011001100110011...

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

答案 2 :(得分: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

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

不,它不能用双精确表示。如果Java支持BCD或定点十进制,那将完全正常工作。

答案 3 :(得分:3)

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

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

在二进制中,所有非零值都是1.xyz * m形式,IEEE形式利用这个来省略前导1.我不确定FP-BCD的等效值是什么,所以我'已经改为0.xyz * m形式的值。

答案 4 :(得分:2)

我建议阅读What Every Computer Scientist Should Know About Floating Point Arithmetic。然后你肯定会知道的。 :)

答案 5 :(得分:2)

一种方法可以看出双精确到底是什么,将它转换为BigDecimal。

// prints 12.0999999999999996447286321199499070644378662109375
System.out.println(new BigDecimal(12.1));

答案 6 :(得分:2)

是的,你可以用浮点表示12.1。 您只需要一个十进制浮点表示,而不是二进制浮点表示。

使用BigDecimal类型,您将完全代表它!

答案 7 :(得分:2)

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

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

假设(为了达到矛盾),121/10也可以写成n / (2**k),其中nk是一些正整数,{{1} }表示两个2**k的幂。我们会有unique factorization的反例。特别是

k

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

答案 8 :(得分:0)

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

在这种情况下,你基本上是在做一个固定点黑客攻击,但是将数字保存在一个浮点数中。 但除非你真的需要,否则它通常不值得这样做。