You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用该Python求根代码时输出始终存在±0.0000001的偏差?

为什么我的Python平方根计算程序总是有0.0000001的偏差?

我编写了一个用于计算数字平方根的小型Python程序,代码如下:

def findRoot(number):
    a = 0
    aa = 0.00
    aaa = 0.0000
    aaaa = 0.000000
    aaaaa = 0.00000000
    x = 1
    while x == 1:
        if a * a > number:
            break
        else:
            a = a + 1
    a = a - 1
    aa = aa + a
    while x == 1:
        if aa * aa > number:
            break
        else:
            aa = aa + 0.01
    aa = aa - 0.01
    aaa = aaa + aa
    while x == 1:
        if aaa * aaa > number:
            break
        else:
            aaa = aaa + 0.0001
    aaa = aaa - 0.0001
    aaaa = aaaa + aaa
    while x == 1:
        if aaaa * aaaa > number:
            break
        else:
            aaaa = aaaa + 0.000001
    # 后续省略的逻辑类似

但每次运行该代码时,输出结果总是存在0.0000001的偏差(偏高或偏低),请问这是什么原因?


问题原因分析

1. 浮点数的二进制精度限制

这是最核心的问题——计算机里的float类型是用二进制存储的,很多十进制小数根本没法被二进制精确表示。比如你用的0.01、0.0001这些步长,在二进制里都是无限循环的近似值。每次累加这些近似值时,误差会一点点累积,到最后就变成了你看到的0.0000001左右的偏差。

举个简单的例子:0.1在二进制里是无限循环的,你在Python里跑0.1 + 0.1 + 0.1,结果会是0.30000000000000004,这就是浮点数精度误差的直观体现,你的程序里多次累加步长,自然会把这种误差放大。

2. 循环终止逻辑的“过冲”问题

你的循环逻辑是:每次加步长,直到平方超过目标数,再退一步得到近似值。但因为浮点数的精度误差,有时候累加后的数值可能已经因为精度问题稍微“超标”,或者没达到预期精度就触发了终止条件,导致最终结果要么偏高一丢丢,要么偏低一丢丢。

比如假设目标数的平方根是2.0,但因为浮点数误差,当你累加到2.0000001时才触发aaa * aaa > number,减去步长后就得到1.9999999,偏差就这么来了。


改进建议

方法一:用牛顿迭代法替代逐位累加

逐位累加不仅效率低,还容易受精度问题影响。牛顿迭代法是计算平方根的高效且精准的方案,核心逻辑是通过不断迭代逼近真实值,公式很简单:x = (x + number / x) / 2。你可以设定一个精度阈值,当两次迭代的差值小于这个阈值时就停止,示例代码:

def findRoot(number, precision=1e-8):
    if number < 0:
        raise ValueError("负数没有实数平方根")
    x = number  # 初始值
    while True:
        next_x = (x + number / x) / 2
        if abs(next_x - x) < precision:
            break
        x = next_x
    return x

这种方法的精度完全可控,而且受浮点数误差的影响极小。

方法二:调整循环的终止判断逻辑

如果你坚持想用逐位累加的思路,可以把终止条件从“平方超过目标数”改成“平方与目标数的差值小于你要的精度”,同时尽量减少累加次数。比如:

def findRoot(number):
    result = 0.0
    # 找整数部分
    while (result + 1)**2 <= number:
        result += 1
    # 小数点后两位
    step = 0.01
    while (result + step)**2 <= number:
        result += step
    # 小数点后四位
    step = 0.0001
    while abs((result + step)**2 - number) > 1e-8:
        if (result + step)**2 <= number:
            result += step
        else:
            break
    return result

不过这种方式还是没法完全避免浮点数精度问题,只能稍微缓解偏差。

内容的提问来源于stack exchange,提问作者Djaro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:10:00