math - 为什么十进制数不能用二进制精确表示?

标签 math floating-point

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

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

例如,数字 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 ...

这些数字也没有任意限制。位置向左和向右无限增加。

最佳答案

如果你有足够的空间,小数可以精确地表示——只是不是用 float 的二进制点数。如果您使用 float decimal 点类型(例如 .NET 中的 System.Decimal),则可以精确表示许多无法用二进制 float 精确表示的值.

让我们换一种方式来看它 - 在您可能熟悉的基数 10 中,您无法准确表示 1/3。它是 0.3333333...(重复出现)。您不能将 0.1 表示为二进制 float 的原因完全相同。您可以准确表示 3、9 和 27,但不能表示 1/3、1/9 或 1/27。

问题是 3 是一个质数,它不是 10 的因数。当你想将一个数乘以 3 时,这不是问题:你总是可以乘以一个整数而不用遇到问题。但是,当您除以一个质数而不是您基数的一个因素时,您可能会遇到麻烦(如果您尝试除以 1,将会这样做按那个数字)。

虽然 0.1 通常用作无法用二进制 float 精确表示的精确十进制数的最简单示例,但可以说 0.2 是一个更简单的示例,因为它是 1/5 - 而 5 是导致两者之间出现问题的素数十进制和二进制。


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

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

关于math - 为什么十进制数不能用二进制精确表示?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20121409/

相关文章:

c++ - AlmostEqual2sComplement 实现不处理退化的情况

c - 在x86上给出无分支FP最小值和最大值的指令是什么?

perl - int() 递减一个整数

algorithm - 我可以实现什么样的酷图形算法?

algorithm - 这种确定上限的推理有什么问题?

sql - 从数据集 SQL 创建趋势线

c# - 找到垂直线及其与矩形的交点

c# - 从一侧缩放多边形

matlab - 在 Matlab 中测试 float 是否为整数

floating-point - 计算器如何精确工作?