Python:哪种方式提供更好的精度

发布于 2024-08-23 17:50:44 字数 149 浏览 2 评论 0 原文

一次赋值:

res=n/k

和 for 循环中的多次赋值:

for i in range(n):
    res+=1/k

之间的精度有什么区别吗?

Is there any difference in precision between one time assignment:

res=n/k

and multiple assignment in for cycle:

for i in range(n):
    res+=1/k

?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

陪你搞怪i 2024-08-30 17:50:44

浮点除法 a/b 不是数学除法 a ÷ b,除非在极少数*情况下。

一般来说,浮点除法a/ba ÷ b + ε。

确实如此,原因有二。

  1. 浮点数(极少数情况除外)是十进制数的近似值。

    aa + εa。

    bb + εb。

    浮点数字使用小数点右侧数字的基数 2 编码。当您编写 3.1 时,它会扩展为以 2 为底的近似值,与实际值略有不同。

    顺便说一句,实数十进制数也有同样的问题。写下 1/3 的小数展开式。哎呀。你必须在某个时候停止写小数位。二进制浮点数也有同样的问题。

  2. 除法有固定数量的二进制位数,这意味着答案会被截断。如果存在重复的二进制模式,它就会被截断。在极少数情况下,这并不重要。一般来说,您通过执行除法引入了错误。

因此,当您重复添加 1/k 值时,您正在计算

1 ÷ k + ε

并将它们相加。您的结果(如果范围正确)将为

n × (1 ÷ k + ε) = n > ÷ k + n × ε

您已将小误差 ε 乘以 n。犯了一个大错误。 (除非在极少数情况下。)

这很糟糕。非常糟糕。所有浮点除法都会引入错误。作为程序员,你的工作就是进行代数运算以避免或推迟除法以防止这种情况发生。好的软件设计意味着好的代数可以防止除法运算符引入错误。

[*罕见的情况。在极少数情况下,小误差恰好为零。当您的浮点值是小整数或分数(即两个 1/2、1/4、1/8 等的幂之和)时,会出现极少数情况。在极少数情况下,您有一个良性数字和一个良性小数部分,误差将为零。]

Floating-point division a/b is not mathematical division a ÷ b, except in very rare* circumstances.

Generally, floating point division a/b is a ÷ b + ε.

This is true for two reasons.

  1. Float numbers (except in rare cases) are an approximation of the decimal number.

    a is a + εa.

    b is b + εb.

    Float numbers uses a base 2 encoding of the digits to the right of the decimal place. When you write 3.1, this is expanded to a base-2 approximation that differs from the real value by a small amount.

    Real decimal numbers have the same problem, by the way. Write down the decimal expansion of 1/3. Oops. You have to stop writing decimal places at some point. Binary floating point numbers have the same problem.

  2. Division has a fixed number of binary places, meaning the answer is truncated. If there's a repeating binary pattern, it gets chopped. In rare cases, this doesn't matter. In general, you've introduced error by doing division.

Therefore, when you do something like repeatedly add 1/k values you're computing

1 ÷ k + ε

And adding those up. Your result (if you had the right range) would be

n × (1 ÷ k + ε) = n ÷ k + n × ε

You've multiplied the small error, ε, by n. Making it a big error. (Except in rare cases.)

This is bad. Very bad. All floating point division introduces an error. Your job as a programmer is to do the algebra to avoid or defer division to prevent this. Good software design means good algebra to prevent errors being introduced by the division operator.

[* The rare cases. In rare cases, the small error happens to be zero. The rare cases occur when your floating point values are small whole numbers or fractions that are sums of powers of two 1/2, 1/4, 1/8, etc. In the rare case that you have a benign number with a benign fractional part, the error will be zero.]

最近可好 2024-08-30 17:50:44

当然,它们是不同的,因为浮点除法的工作原理不同。

>>> res = 0
>>> for x in xrange(5000): res += 0.1
... 
>>> res == 5000 * 0.1
False

Python 官方教程中有很好的解释

Sure, they are different, because of how floating point division works.

>>> res = 0
>>> for x in xrange(5000): res += 0.1
... 
>>> res == 5000 * 0.1
False

There's a good explanation in the python official tutorial.

三月梨花 2024-08-30 17:50:44

好吧,如果 kn 那么肯定第一个更精确:-) 说实话,如果除法是浮点数并且 n > 1 那么第一个无论如何都会更精确,尽管它们可能会给出不同的结果,正如诺斯克洛所说。

顺便说一句,在 Python 2.6 中,除法默认是整数,所以你会得到非常不同的结果。 1/k 将始终给出 0,除非 k <= 1

Well if k divides n then definitely the first one is more precise :-) To be serious, if the division is floating point and n > 1 then the first one will be more precise anyway though they will probably give different results, as nosklo said.

BTW, in Python 2.6 the division is integer by default so you'll have very different results. 1/k will always give 0 unless k <= 1.

失退 2024-08-30 17:50:44

浮点运算存在表示误差和舍入误差。对于浮点数旨在表示合理大小的实数的数据类型,这些错误通常是可以接受的。

如果你想计算两个数字的商,正确的方法就是简单地说 result = n / k (请注意,如果它们都是整数并且你没有说 from __future__ import div< /code>,这不是您所期望的)。第二种方法很愚蠢,容易出错,而且丑陋。

Python 教程中有一些关于浮点不精确性的讨论: http://docs.python.org /tutorial/floatingpoint.html

Floating point arithmetic has representation and roundoff errors. For the types of data floating point numbers are intended to represent, real numbers of reasonable size, these errors are generally acceptable.

If you want to calculate the quotient of two numbers, the right way is simply to say result = n / k (beware if these are both integers and you have not said from __future__ import division, this is not what you may expect). The second way is silly, error-prone, and ugly.

There is some discussion of floating point inexactness in the Python tutorial: http://docs.python.org/tutorial/floatingpoint.html

长发绾君心 2024-08-30 17:50:44

即使我们善意地假设浮点除法,精度上也肯定存在差异; for 循环执行了 n - 1 次!

assert (n-1) / k != n / k

还取决于在第二种情况下 res 的初始化结果:-)

Even if we charitably assume a floating-point division, there's very definitely a difference in precision; the for loop is executed n - 1 times!

assert (n-1) / k != n / k

Also depends on what res is initialised to in the second case :-)

楠木可依 2024-08-30 17:50:44

如果您使用浮点数,当然会有差异,除非您使用的 Python 解释器/编译器能够优化循环(也许 Jython 或 IronPython 可以?C 编译器在这方面非常擅长)。

如果您实际上希望这两种方法具有相同的精度,并且您使用整数作为分子和分母,则可以使用 python 分数

from fractions import Fraction
n,k = 999,1000
res = Fraction(0,1)

for i in range(0,n):
    res += Fraction(1,k)

print float(res)

Certainly there is a difference if you use floating point numbers, unless the Python interpreter/compiler you are using is capable of optimizing away the loop (Maybe Jython or IronPython might be able to? C compilers are pretty good at this).

If you actually want these two approaches to be the same precision though, and you are using integers for your numerator and denominator, you can use the python fractions package

from fractions import Fraction
n,k = 999,1000
res = Fraction(0,1)

for i in range(0,n):
    res += Fraction(1,k)

print float(res)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文