浮点什么时候完全转动?

时间:2017-03-15 20:31:23

标签: floating-point precision floating-accuracy

我的问题被标记为https://stackoverflow.com/a/22023918/856090的副本,但不是重复。这个问题涉及不精确表示的情况,而我的问题是关于特殊情况下的确切表示

在Python 3会话中:

>>> 0.1*3/3
0.10000000000000002
>>> 12.34567
12.34567

第一次计算会产生不准确的结果。 (我明白为什么:这是因为浮点数是四舍五入的。)

但是第二次计算(从小数部分切换到二进制FP然后返回)会产生精确的结果。

我的问题是为什么第二个结果(许多类似的"计算"只涉及一个没有算术运算的FP号)是准确的(与Python会话中输入的相同) ?

另外:关于两位小数之和的准确性是什么(它们的指数差异不大)?

3 个答案:

答案 0 :(得分:5)

它不是"确切" ... 12.34567没有二进制64的精确表示。但是Python的浮点到字符串转换的默认规则与你输入的输入相同。如果你强迫它给你整个故事,它会揭示不精确性:

>>> '{:.500}'.format(12.34567)
'12.3456700000000001438138497178442776203155517578125'

答案 1 :(得分:0)

精确表示有两个限制。

第一个消除了诸如12.34567和0.1之类的数字,它必须具有有限表示作为基数2分数。它必须等于A / B,其中A是整数,B是2的整数幂,如1,2,4,8等。

这可以很容易地测试。首先将数字写为比率。例如,0.1是1/10。减少到最低限度。除了1以外,1和10没有共同的整数因子,所以1/10已经减少了。看看分母,10。它不是2的幂,所以0.1不能完全代表。

现在考虑0.375。它等于375/1000或3/8。 8是2的幂,因此0.375具有有限的二进制分数表示。

第二组条件限制所涉及的数字的大小以适合特定的浮点格式。

答案 2 :(得分:0)

你不能做10件事,并假设他们以同样的方式在基地2工作。

双精度IEEE

0.1 = 0x3FB999999999999A
3.0 = 0x4008000000000000
12.34567 = 0x4028B0FBA8826AA9
0.1*3.0 = 0x3FD3333333333334
(0.1*3.0)/3.0 = 0x3FB999999999999B

单个在计算器上更容易处理,并注意到有趣的区别:

0.1 = 0x3DCCCCCD
3.0 = 0x40400000
12.34567 = 0x414587DD
0.1*3.0 = 0x3E99999A
(0.1*3.0)/3.0 = 0x3DCCCCCD

首先关闭

0x3DCCCCCD is 0 01111011 10011001100110011001101

如果我们在分母1/3 = 0.3333333中有三个,请注意重复模式,就像在十垒中一样。和1/6 0.16666667一样,因为我们收尾了。看看结束时有点过了1001,但是这个数字太多了,如果你要切断点之后的数字大于你向上舍入的一半,那么0.1001回合到0.101的二进制数是?同样的交易。

在这种情况下,对于你的十进制数,单个精度得出正确的答案乘以一些数字然后再将它除以你获得相同的数字,但是在另一个点的两倍圆形剪辑中,我们再次向上舍入结果是一个比开始时略大的数字。

这在十进制中很容易看到。如果我的格式是固定的位数,我必须在某个时刻停止,所以1/6 = 0.166666可以说或者是0.166667。和6.0就是说6.00000。因此,如果我使用我的十进制浮点格式并乘以6 *(1/6),我得到0.99996或1.000002,在任何情况下我都得到1.不是因为舍入而是因为数字无法以该格式准确表示。

如果你从一些基本的10个ASCII字符串转到浮点数然后回到一些基本的10个ASCII字符串,那么你可以找回你开始的数字,那就是运气。数字是以浮点准确表示还是不是。你可以看到上面非常简单的基数10浮点,无论你有多少数字你都害羞无穷,你就不会得到6 *(1/6)= 1,因为基数10浮点数不能准确地代表1/6固定的位数。

查看您的其他号码

12.34567 = 0x414587DD
0 10000010 10001011000011111011101
12.34567 = 0x4028B0FBA8826AA9
0 10000000010 1000101100001111101110101000100000100110101010101001

1.10001011000011111011101
1.1000101100001111101110101000100000100110101010101001

显然单个没有足够的位来表示它,并且没有向上舍入,因为下一位是零,小于一半。并且双重保持工作数字到最后,我不会把它转换回基数10,但我愿意打赌你很幸运。如果你有更多的位会安定下来吗?我再也不会为你转换那个。我认为你应该能够看到,即使你只是看了0.1然后去漂浮并回到ASCII你也不会得到0.1。就像在十分之一的1/6没有转换那里然后回来,如果你围绕它你会很幸运:5.9999 ...如果你在正确的地方剪辑/舍入它的轮到6.0,但这只是为了转换ASCII转换而不是浮点格式表示的实际数字。