Math 为什么可以';十进制数不能用二进制精确表示吗?

Math 为什么可以';十进制数不能用二进制精确表示吗?,math,floating-point,Math,Floating Point,关于浮点表示法,SO上已经发布了几个问题。例如,十进制数0.1没有精确的二进制表示,因此使用==运算符将其与另一个浮点数进行比较是危险的。我理解浮点表示背后的原理 我不明白的是,为什么从数学的角度来看,小数点右边的数字比左边的数字更“特殊” 例如,数字61.0具有精确的二进制表示,因为任何数字的整数部分总是精确的。但数字6.10并不准确。我所做的只是把小数点移动一位,突然我从精确到了不精确。从数学上讲,这两个数字之间应该没有本质上的区别——它们只是数字 相比之下,如果我将小数点朝另一个方向移动一

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

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

例如,数字61.0具有精确的二进制表示,因为任何数字的整数部分总是精确的。但数字6.10并不准确。我所做的只是把小数点移动一位,突然我从精确到了不精确。从数学上讲,这两个数字之间应该没有本质上的区别——它们只是数字

相比之下,如果我将小数点朝另一个方向移动一位来生成数字610,我仍然处于Exactopia状态。我可以继续朝那个方向走(6100,61000000,61000000000000),它们仍然是精确的,精确的,精确的。但一旦小数点超过某个阈值,数字就不再精确

发生什么事了

编辑:为了澄清,我不想讨论行业标准表示法,比如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并不总是会产生更高的精度,因为在某些点上,浮点数必须使用指数来表示数字的大,这样也会失去一些精度。

BCD--表示是精确的。它们的空间效率不高,但在这种情况下,这是一个必须权衡的准确性问题。

问题是,您不知道该数字是否正好是61.0。考虑这一点:


浮点数a=60;
浮动b=0.1;
浮点数c=a+b*10;

c的值是多少?它不完全是61,因为b不是真正的.1,因为.1没有精确的二进制表示。

根(数学)原因是当你处理整数时,它们是可数无限的

这意味着,即使它们的数量是无限的,我们也可以“数出”序列中的所有项,而不会跳过任何项。这意味着如果我们想得到列表中第位的项目,我们可以通过一个公式计算出来

然而,实数是不可数无限的。你不能说“给我61000000000000位置的真实数字”然后得到答案。原因是,即使在
0
1
之间,当您考虑浮点值时,值的数量也是无限的。这同样适用于任意两个浮点数

更多信息:

更新:
很抱歉,我似乎误解了这个问题。我的回答是为什么我们不能表示每个实数,我没有意识到浮点被自动归类为有理数。

数字61.0确实有一个精确的浮点运算,但并非所有整数都是这样。如果您编写了一个循环,在双精度浮点数和64位整数中都添加了一个循环,那么最终您将达到64位整数完美表示的点

float a = 60;
float b = 0.1;
float c = a + b * 10;
1.525         - 1*2^0   --> 1
0.525         - 1*2^-1  --> 1
0.025         - 0*2^-2  --> 0
0.025         - 0*2^-3  --> 0
0.025         - 0*2^-4  --> 0
0.025         - 0*2^-5  --> 0
0.025         - 1*2^-6  --> 1
0.009375      - 1*2^-7  --> 1
0.0015625     - 0*2^-8  --> 0
0.0015625     - 0*2^-9  --> 0
0.0015625     - 1*2^-10 --> 1
0.0005859375  - 1*2^-11 --> 1
0.00009765625...
0; 3
0; 1, 1, 4
0; 4, 3, 3
0; 2, 31, 7, 8, 5
3; 7, 15, 1, 292 ...
2^x = y ;  
x = log(y) / log(2)
 2^1, 2^0, 2^(log(1/2) / log(2)), 2^(log(1/4) / log(2)), 2^(log(1/8) / log(2)),2^(log(1/16) / log(2)) ........
2^5 + 2^(log(0.4) / log(2)) + 2^(log(0.01) / log(2))
2^5 + 2^(log(0.41) / log(2))