有几个关于浮点表示法的问题被提交给了SO。例如,十进制数0.1没有精确的二进制表示,因此使用==操作符将其与另一个浮点数进行比较是危险的。我理解浮点表示法背后的原理。
我不明白的是,为什么从数学的角度来看,小数点右边的数字比左边的数字更“特殊”?
例如,数字61.0具有精确的二进制表示,因为任何数字的整数部分总是精确的。但6.10这个数字并不准确。我所做的只是把小数点移了一位突然间我就从精确乌托邦变成了不精确镇。从数学上讲,这两个数字之间不应该有本质差别——它们只是数字。
相比之下,如果我把小数点向另一个方向移动一位,得到数字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 ...
这些数字也没有任意的限制。位置向左和向右无限增加。
根(数学)原因是,当你处理整数时,它们是可数无限的。
这意味着,即使它们的数量是无限的,我们也可以“数出”序列中的所有项目,而不会跳过任何一项。这意味着,如果我们想要在列表中的第610000000000000th位置上得到一项,我们可以通过一个公式来计算它。
然而,实数是无限的。你不能说“给我位置610000000000000的真实数字”并得到一个答案。原因是,即使在0到1之间,当考虑浮点值时,也有无限个值。这同样适用于任何两个浮点数。
更多信息:
http://en.wikipedia.org/wiki/Countable_set
http://en.wikipedia.org/wiki/Uncountable_set
更新:
很抱歉,我似乎误解了这个问题。我的回答是关于为什么我们不能表示每一个真实的值,我没有意识到浮点数被自动归类为理性。
(注意:我将在这里添加'b'来表示二进制数。其他数字均为十进制)
一种思考方法是用科学记数法。我们习惯看到用科学符号表示的数字,比如6.022141 * 10^23。浮点数内部使用类似的格式存储——尾数和指数,但使用2的幂而不是10。
你的61.0可以重写为1.90625 * 2^5,或者1.11101b * 2^101b加上尾数和指数。把它乘以10(移动小数点),我们可以这样做:
(1.90625 * 2 ^ 5) * 1.25 * 2 ^ (3) = 2.3828125 * 2 ^ (8) = 1.19140625 * 2 ^ (9)
或者在二进制中用尾数和指数:
(1.1110b * 2^101b) * (1.01b * 2^11b) = (10.011000b * 2^1000b) = (1.0011000b * 2^1001b)
Note what we did there to multiply the numbers. We multiplied the mantissas and added the exponents. Then, since the mantissa ended greater than two, we normalized the result by bumping the exponent. It's just like when we adjust the exponent after doing an operation on numbers in decimal scientific notation. In each case, the values that we worked with had a finite representation in binary, and so the values output by the basic multiplication and addition operations also produced values with a finite representation.
现在,考虑一下我们如何用61除以10。我们先把尾数分成1.90625和1.25。小数是1.525,一个很短的数。但是如果我们把它转换成二进制呢?我们会用通常的方法来做——尽可能减去2的最大幂,就像把整数小数转换成二进制一样,但我们将使用2的负幂:
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...
哦哦。现在我们有麻烦了。原来,1.90625 / 1.25 = 1.525,用二进制表示时是一个重复分数:1.1110b / 1.01b = 1.10000110011…b我们的机器只有这么多位来容纳尾数,所以它们会四舍五入,假设超过某一点是零。当你用61除以10时,你看到的错误是:
1.100001100110011001100110011001100110011……B * 2^10b
而且,说:
1.100001100110011001100110b * 2^10b
正是尾数的舍入导致了我们与浮点值相关的精度损失。即使当尾数可以精确地表示(例如,当只是两个数字相加时),如果在标准化指数后尾数需要太多数字来拟合,我们仍然会得到数字损失。
实际上,我们一直在做这样的事情,当我们把小数四舍五入到一个可管理的大小时,只给出它的前几位。因为我们用十进制表示结果,所以感觉很自然。但是如果我们四舍五入一个小数,然后把它转换成不同的底数,它看起来就像我们通过浮点四舍五入得到的小数一样难看。
你不能用二进制精确地表示0.1,就像你不能用传统的英国尺测量0.1英寸一样。
英国的尺子,就像二进制分数一样,都是关于一半的。你可以测量半英寸,或四分之一英寸(当然是一半),或八分之一,或十六分之一,等等。
If you want to measure a tenth of an inch, though, you're out of luck. It's less than an eighth of an inch, but more than a sixteenth. If you try to get more exact, you find that it's a little more than 3/32, but a little less than 7/64. I've never seen an actual ruler that had gradations finer than 64ths, but if you do the math, you'll find that 1/10 is less than 13/128, and it's more than 25/256, and it's more than 51/512. You can keep going finer and finer, to 1024ths and 2048ths and 4096ths and 8192nds, but you will never find an exact marking, even on an infinitely-fine base-2 ruler, that exactly corresponds to 1/10, or 0.1.
不过,你会发现一些有趣的事情。让我们看看我列出的所有近似值,对于每一个近似值,明确地记录0.1是大是小:
fraction |
decimal |
0.1 is... |
as 0/1 |
1/2 |
0.5 |
less |
0 |
1/4 |
0.25 |
less |
0 |
1/8 |
0.125 |
less |
0 |
1/16 |
0.0625 |
greater |
1 |
3/32 |
0.09375 |
greater |
1 |
7/64 |
0.109375 |
less |
0 |
13/128 |
0.1015625 |
less |
0 |
25/256 |
0.09765625 |
greater |
1 |
51/512 |
0.099609375 |
greater |
1 |
103/1024 |
0.1005859375 |
less |
0 |
205/2048 |
0.10009765625 |
less |
0 |
409/4096 |
0.099853515625 |
greater |
1 |
819/8192 |
0.0999755859375 |
greater |
1 |
现在,如果向下读最后一列,就会得到0001100110011。1/10的无限重复二进制分数是0.0001100110011,这不是巧合……
我不想重复其他20个答案的总结,所以我只简单地回答:
答案在你的内容中:
为什么以两为基数的数字不能精确地表示一定的比率?
出于同样的原因,小数不足以表示某些比率,即分母中包含除2或5之外的素数因子的不可约分数,至少在其小数展开的尾数中总是有一个不确定的字符串。
为什么十进制数不能精确地用二进制表示?
This question at face value is based on a misconception regarding values themselves. No number system is sufficient to represent any quantity or ratio in a manner that the thing itself tells you that it is both a quantity, and at the same time also gives the interpretation in and of itself about the intrinsic value of the representation. As such, all quantitative representations, and models in general, are symbolic and can only be understood a posteriori, namely, after one has been taught how to read and interpret these numbers.
由于模型是主观的东西,在反映现实的范围内是正确的,我们不需要严格地将二进制字符串解释为2的负幂和正幂的和。相反,我们可以观察到,我们可以创建一组任意的符号,这些符号以2为基底或任何其他基底来精确地表示任何数字或比例。只要考虑一下,我们可以用一个词甚至一个符号来指代无穷大,而不需要“显示无穷大”本身。
As an example, I am designing a binary encoding for mixed numbers so that I can have more precision and accuracy than an IEEE 754 float. At the time of writing this, the idea is to have a sign bit, a reciprocal bit, a certain number of bits for a scalar to determine how much to "magnify" the fractional portion, and then the remaining bits are divided evenly between the integer portion of a mixed number, and the latter a fixed-point number which, if the reciprocal bit is set, should be interpreted as one divided by that number. This has the benefit of allowing me to represent numbers with infinite decimal expansions by using their reciprocals which do have terminating decimal expansions, or alternatively, as a fraction directly, potentially as an approximation, depending on my needs.
例如,数字61.0具有精确的二进制表示,因为任何数字的整数部分总是精确的。但6.10这个数字并不准确。我所做的只是把小数点移了一位突然间我就从精确乌托邦变成了不精确镇。从数学上讲,这两个数字之间不应该有本质差别——它们只是数字。
让我们暂时撇开以10为底和以2为底的细节。我们问一下,在以b为底的情况下,哪些数字有终止表示,哪些数字没有?稍微思考一下,我们就知道一个数字x有一个终止的b表示,当且仅当存在一个整数n,使得x b^n是一个整数。
例如,x = 11/500有一个终止10表示,因为我们可以选择n = 3,然后x b^n = 22,一个整数。但是x = 1/3不是,因为不管n取多少都不能消掉3。
第二个例子促使我们思考因子,我们可以看到,对于任何有理数x = p/q(假设是最小值),我们可以通过比较b和q的质因数分解来回答这个问题。如果q有任何不在b的质因数分解中的质因数,我们将永远无法找到一个合适的n来摆脱这些因数。
因此,对于以10为底的任何p/q,其中q有除2或5之外的素数因子,将没有终止表示。
现在回到以10和2为底,我们看到任何以10为底的有理数都是p/q的形式当q的质因数分解中只有2s和5s时;当q的质因数分解中只有2时,同样的数会有一个终止的2表示。
但其中一个案例是另一个案例的子集!每当
Q的质因数分解只有2
这显然也是正确的
Q的质因数分解只有2和5
换句话说,只要p/q有终止的2表示,p/q就有终止的10表示。然而反过来就不成立了——只要q的质因数分解中有一个5,它就会有一个终止的10表示,而不是终止的2表示。这是其他答案提到的0.1的例子。
这就是问题的答案了因为2的质因数是10的质因数的子集,所以所有以2结尾的数都是以10结尾的数,反之则不然。不是61比6.1,而是10比2。
最后提醒一下,如果有些人使用17进制,而我们的计算机使用5进制,你的直觉永远不会被这引入歧途——在这两种情况下都不会有(非零,非整数)数字终止!