为什么十进制数不能完全用二进制表示?

在SO上发布了几个关于浮点表示的问题。 例如,十进制数字0.1没有精确的二进制表示形式,因此使用==运算符将其与另一个浮点数字进行比较是危险的。 我理解浮点表示的原理。

我不明白的是,从数学的角度来看,为什么小数点右边的数字更加“特殊”,即左边的数字?

例如,数字61.0具有精确的二进制表示,因为任何数字的整数部分总是精确的。 但数字6.10并不确切。 我所做的只是将小数点后移一位,突然间我从Exactopia变成了Inexactville。 在数学上,这两个数字之间应该没有内在的区别 - 它们只是数字。

相比之下,如果我将小数位移到另一个方向以产生数字610,我仍然在Exactopia中。 我可以继续沿着这个方向前进(6100,610000000,610000000000000),他们仍然是确切的,确切的,确切的。 但是,一旦小数点超过某个阈值,数字就不再精确。

这是怎么回事?

编辑:为了澄清,我想远离关于IEEE等行业标准表示的讨论,并坚持我认为是数学“纯”的方式。 在基数10中,位置值是:

... 1000  100   10    1   1/10  1/100 ...

在二进制中,它们是:

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

这些数字也没有任何限制。 这些头寸无限地向左和向右增加。


如果您有足够的空间,则可以精确地表示十进制数字 - 而不是浮点二进制数字。 如果使用浮点小数点类型(例如.NET中的System.Decimal ),那么可以准确地表示大量无法完全用二进制浮点表示的值。

让我们以另一种方式来看待它 - 在你可能会感到满意的基础10中,你无法完全表达1/3。 它是0.3333333 ...(经常性)。 您无法将0.1表示为二进制浮点数的原因完全是由于相同的原因。 您可以完全表示3,9和27,但不能是1/3,1/9或1/27。

问题在于3是一个素数,不是10的因子。当你想将一个数乘以3时,这不是问题:你总是可以乘以一个整数而不会遇到问题。 但是,如果用一个数字作为素数而不是基数,那么你可能会遇到麻烦(如果你试图用这个数字除1)就会遇到麻烦。

尽管通常使用0.1作为精确十进制数的最简单示例,但不能准确表示二进制浮点数,可以说0.2是一个更简单的示例,因为它是1/5 - 而5是导致十进制和二进制之间的问题的主要示例。


处理有限表示问题的附注:

一些浮点小数点类型具有像System.Decimal一样的固定大小,其他像java.math.BigDecimal是“任意大的” - 但它们在某个点上会达到极限,无论是系统内存还是数组的理论最大大小。 然而,这与这个答案的主要内容完全不同。 即使你真的使用了大量的位,你仍然无法精确表示浮点二进制表示中的十进制0.1。 将其与其他方式进行比较:给定任意数量的小数位数,您可以精确地表示任何可精确表示为浮点二进制数的数字。


不准确的原因是数字基础的性质。 在基数10中,你不能完全代表1/3。 它变为0.333 ...但是,在基数3中,1/3用0.1精确表示,1/2是无限重复小数(tresimal?)。 可以有限地表示的值取决于基底的唯一素数因子的数量,因此基数30 [2 * 3 * 5]可以表示比基数2或基数10更多的分数。甚至更多基数为210 [2 * 3 * 5 * 7]。

这是与“浮点错误”分开的问题。 由于数十亿的价值分布在更大的范围内,因此不准确。 所以如果你有23位的有效位数,你只能表示大约830万个不同的值。 然后一个8位指数提供了256个选项来分配这些值。 这个方案允许最精确的小数位出现在0附近,所以你几乎可以代表0.1。


例如,数字61.0具有精确的二进制表示,因为任何数字的整数部分总是精确的。 但数字6.10并不确切。 我所做的只是将小数点后移一位,突然间我从Exactopia变成了Inexactville。 在数学上,这两个数字之间应该没有内在的区别 - 它们只是数字

让我们从基数10和2的详细情况中离开一会儿。让我们问一下 - 在基数b ,什么数字有终止表示,什么数字没有? 片刻的想法告诉我们,当且仅当存在一个整数n ,使得xb^n是一个整数时,数字x有一个终止b表示。

因此,例如, x = 11/500具有终止10-表示,因为我们可以选择n = 3 ,然后xb^n = 22是一个整数。 但是x = 1/3不对,因为无论n我们选择,我们将无法摆脱3。

第二个例子提示我们考虑因素,我们可以看到,对于任何有理x = p/q (假定为最低项),我们可以通过比较bq的素因子来回答这个问题。 如果q有任何素数因子不在b的素因子分解中,我们将永远无法找到合适的n来摆脱这些因素。

因此,对于基数10,其中q具有除2或5以外的素因子的任何p/q将不具有终止表示。

因此,现在回到10和2的基数,我们看到任何具有终止10表示的理性都恰好在q的质数因子分解中只有2 s和5 s时具有p/q的形式; 并且当q在其素数因子分解中仅有2 s时,该数字将具有终止2-表示。

但其中一种情况是另一种情况的一个子集! 每当

q的素因子化只有2 s

这显然也是如此

q在其素数因子分解中只有2 s和5 s

或者换句话说, 每当p/q具有终止2表示时, p/q具有终止10表示 。 然而,反过来并不成立 - 只要q在其素因子化中具有5,它将具有终止10表示,但不具有终止2表示。 这是其他答案提到的0.1例子。

所以我们有你的问题的答案 - 因为2的主要因素是10的主要因素的子集,所有2端接数字都是10端接数字,但反之亦然。 这不是61对6.1,而是10对2。

作为结束语,如果某些古怪的人使用(比如说)基数为17,但我们的计算机使用的是基数5,那么你的直觉就不会被误导 - 它不会有(非零,非整数)终止的数字在这两种情况下!

链接地址: http://www.djcxy.com/p/77459.html

上一篇: Why can't decimal numbers be represented exactly in binary?

下一篇: How to nicely format floating numbers to String without unnecessary decimal 0?