Python乘法丢失浮点精度

问题描述 投票:2回答:2

我最近正在使用浮点数,但我意识到了一些我不期望的关于浮点数的东西。这是一个例子

a = 0.1
print(f"{a:0.20f}")
#'0.10000000000000000555'
b = a * 10
print(f"{b:0.20f}")
#'1.00000000000000000000'

我希望最后的打印输出1.00000000000000005551(即1后跟0.1的数字1到21)。

我很好奇的是为什么乘以10时浮点误差会消失。正常的算术规则表明,浮点误差会传播,但实际上并没有发生。为什么会这样?有办法避免吗?

python floating-point precision
2个回答
3
投票

[10和0.1000000000000000055511151231257827021181583404541015625,IEEE 754 64位二进制表示形式为1.000000000000000055511151231257827021181583404541015625。

这不能完全代表。它由1.0和1.0000000000000002括起来。0000000000000002220446049250313080847263336181640625

接近1.0,所以这是乘法的舍入到最接近的结果。

我使用一个简短的Java程序计算了数字:

import java.math.BigDecimal;

public strictfp class Test {
    public static void main(String[] args) {
        BigDecimal rawTenth = new BigDecimal(0.1);
        BigDecimal realProduct = rawTenth.multiply(BigDecimal.TEN);
        System.out.println(realProduct);
        System.out.println(new BigDecimal(Math.nextUp(1.0)));
    }
}

输出:

1.0000000000000000555111512312578270211815834045410156250
1.0000000000000002220446049250313080847263336181640625

2
投票

此答案说明了如何仅需一点点算术就可以确定将1/10转换为浮点并乘以10将产生正1的结果;无需计算大数或精确数字。

您的Python实现使用通用的IEEE-754 binary64格式。 (Python并不严格限制应使用哪种浮点格式实现。)在这种格式下,数字实际上表示为一些53位整数乘以2的幂。因为2 -4≤1/ 10 <2 -3,所以最接近的1/10的可表示数是某个整数M乘以2 -3-5]]。 (-53将53位整数缩放为½和1之间,而-3将其整数缩放为2 -4和2 -3。)让我们将可表示的数字称为x。

那么我们有x = M•2 − 56

= 1/10 + e,其中e是当我们将1/10舍入到最接近的可表示值时发生的舍入误差。由于我们舍入到最接近的可表示值,因此| e |。 ≤½•2 − 56 = 2 − 57

要确切地找到e是什么,请将1/10乘以2 56

WolframAlpha告诉我们这是7205759403792793 + 3/5。为了获得最接近的可表示值,我们应该四舍五入,所以M = 7205759403792794和e = 2/5•2 − 56。尽管我使用WolframAlpha进行了说明,但是我们不需要M,并且可以通过以两个模10的幂观察模式来找到e:2 1]→2,2 2→4,2 < [3→8、2 4→6、2 5→2、2 6→4,因此模式以4的循环重复,而56模4为0,所以2 [56]模10的余数与2 [4] 6的余数相同,因此分数为6/10 = 3/5。我们知道应该四舍五入到最接近的整数1,因此e = 2/5•2 − 56So x = M•2 − 56 = 1/10 + 2/5•2 − 56

现在我们可以算出用浮点算法计算10•x的结果。结果就像我们先用实数算法计算10•x,然后四舍五入到最接近的可表示值。在实数运算中,10•x = 10•(1/10 + 2/5•2 − 56

)= 1 + 10•2/5•2 − 56 = 1 + 4• 2

-56 = 1 + 2 -54

。两个相邻的可代表值是1和1 + 2 -52,并且1 + 2 -54比1 + 2 -52更接近1。所以结果是1。
© www.soinside.com 2019 - 2024. All rights reserved.