牛顿法:循环语句的顺序

Newton's method: order of statements in loop

我正在尝试在 Python 中实现牛顿法以获得乐趣,但我在概念上理解支票的位置时遇到了问题。

重温牛顿法作为一种通过微分重复线性逼近来逼近根的方法:

我有以下代码:

# x_1 = x_0 - (f(x_0)/f'(x_0))
# x_n+1 - x_n = precision

def newton_method(f, f_p, prec=0.01):
    x=1
    x_p=1
    tmp=0

    while(True):
        tmp = x
        x = x_p - (f(x_p)/float(f_p(x_p)))
        if (abs(x-x_p) < prec):
            break;
        x_p = tmp

    return x

这有效,但是如果我将循环中的 if 语句移动到 x_p = tmp 行之后,该函数将停止按预期工作。像这样:

# x_1 = x_0 - (f(x_0)/f'(x_0))
# x_n+1 - x_n = precision

def newton_method(f, f_p, prec=0.01):
    x=1
    x_p=1
    tmp=0

    while(True):
        tmp = x
        x = x_p - (f(x_p)/float(f_p(x_p)))
        x_p = tmp
        if (abs(x-x_p) < prec):
            break;

    return x

澄清一下,函数 v1(第一段代码)按预期工作,函数 v2(第二段)没有。

为什么会这样?
原始版本本质上不是检查当前的 x 与 2 个作业中的 x ,而不是紧邻的前一个 x 吗?

这是我使用的测试代码:

def f(x):
    return x*x - 5

def f_p(x):
    return 2*x

newton_method(f,f_p)

编辑

我最终使用了这个版本的代码,它放弃了 tmp 变量并且在概念上对我来说更加清晰:

# x_1 = x_0 - (f(x_0)/f'(x_0))
# x_n+1 - x_n = precision

def newton_method(f, f_p, prec=0.01):
    x=1
    x_p=1
    tmp=0

    while(True):
        x = x_p - (f(x_p)/float(f_p(x_p)))
        if (abs(x-x_p) < prec):
            break;
        x_p = x

    return x

更新

这保存了x的当前值

tmp = x

在此语句中,x 的下一个值是根据当前值创建的 x_p

x = x_p - (f(x_p)/float(f_p(x_p)))

如果收敛(例如下一个值-当前值<阈值),中断

if (abs(x-x_p) < prec):
    break;

将x_p设置为下一次迭代的值

x_p = tmp

如果您将 x_p = tmp 拉到 if 语句上方,您实际上是在检查 2 次迭代前的 x 与 x`,这不是您想要做的。这实际上会导致奇怪的行为,其中结果的正确性取决于起始值。如果你从 x 开始,你会得到正确的答案,而如果你从 1 开始,你就不会。

要对其进行测试并了解原因,添加如下所示的打印语句会很有帮助。

def newton_method(f, f_p, prec=0.01):
    x=7
    x_p=1
    tmp=0

    while(True):
        tmp = x
        x = x_p - (f(x_p)/float(f_p(x_p)))
        print (x,x_p,_tmp)
        if (abs(x-x_p) < prec):
            break;
        x_p = tmp

您是否要检查 2 次迭代前的 X 与 X?还是来自上一次循环迭代的 X?

如果在 if 语句之前有 x_p=tmpif (abs(x-x_p) < prec): 将检查 x 的当前值与之前版本的 x,而不是来自 2 次赋值之前的 x

x[i] 成为迭代中要计算的新值。

版本 1 发生了什么:

语句 x = x_p - (f(x_p)/float(f_p(x_p))) 转换为:

x[i] = x[i-2] - f(x[i-2])/f'(x[i-2]) - 1

但是根据实际的数学公式,应该是这样的:

x[i] = x[i-1] - f(x[i-1])/f'(x[i-1])

同理,x[i-1] = x[i-2] - f(x[i-2])/f'(x[i-2]) - 2

比较12,我们可以看到1中的x[i]根据数学公式实际上是x[i-1]

这里要注意的要点是 xx_p 始终相隔一次迭代。也就是说,xx_p 的实际继承者,这与仅查看代码时看起来的情况不同。

因此,它按预期正常工作。

版本 2 发生了什么:

就像上面的例子一样,同样的事情发生在语句x = x_p - (f(x_p)/float(f_p(x_p))).
但是当我们到达 if (abs(x-x_p) < prec) 时,x_p 已将其值更改为 temp = x = x[i-1]

但正如在版本 1 中推导出的,x 也是 x[i-1] 而不是 x[i]

因此,abs(x - x_p) 转换为 abs(x[i-1] - x[i-1]),结果为 0,因此终止迭代。

这里要注意的要点是 xx_p 在数值上实际上是相同的值,这总是导致算法本身仅在 1 次迭代后终止。