if 语句或 while 循环条件?

if statements or while loop conditions?

因此,对于一项作业,我应该编写一个函数来计算我之前在程序中定义的另外两个函数。如何,我必须定义的下一个函数的复杂性让我感到困惑,我应该如何设置它。基本上,我已经确定我必须写一个 while 循环,但我不能决定是否要有三个不同的条件或 if 语句来评估这个函数。问题是,循环必须在满足三个条件之一后结束;我只是不知道目前如何布局。 这些是三个条件(其中只有一个必须满足才能使 loop/function 终止):

  1. 当前估计的多项式的绝对值小于 epsilon,在
    在这种情况下该方法是成功的。
  2. 当前估计的多项式导数的绝对值小于
    比 epsilon(这可能导致被 0 除),在这种情况下该方法失败,或者
  3. 预估的修改次数已超时(预估未 收敛于一个解决方案)。这个案例也是失败的。

这是我目前拥有的代码(显然 运行 还没有):

def newtonsMethod(poly, x_, epislon, timeout):
    """Calculating root of polynomial using newton's Method."""
    estimate = 0
    epislon = 1e-20
    while (abs(evaluatePoly(poly, x_)) < epislon and \
abs(evaluatePoly(findDerivative(poly), x_)) and estimate > timeout):
        estimate = x_ - (evaluatePoly(poly) / evaluatePoly(findDerivative(poly)))
         x_ = estimate
         print(x_)

我该怎么办?函数名称是分配的要求,因此不能更改。此外,我是这方面的初学者(上个月才开始),我基本上只需要了解数据结构、循环和 if 语句(和函数)。因此,请尽可能保留您的回复作为 simple/dumby 证据。

这是我之前关于这个问题的所有代码:

def findDerivative(poly):
    """Find the derivative of the polynomial and return it as a list of 
    coefficents"""
    count = 0
    polyList = []
    for nn in poly:
        polyList += [nn * count]
        count += 1
    return polyList[1:]

def evaluatePoly(poly, x_):
    """Evaluates the polynomial at x = x_ and returns the result as a   floating-
    point number using Horner's rule"""
    #http://mathworld.wolfram.com/HornersRule.html
    count = 0
    polyEval = []
    for nn in poly:
        xVal = x_**count
        polyEval += [xVal * nn]
        count += 1
    polySum = sum(polyEval)
    return float(polySum)

编辑:2016 年 10 月 23 日

我应该在之前提到这个或更详细地解释作业,但估计是该函数的参数,因为它稍后在作业中作为列表给出。我已经理解超时表示循环可以 运行 在它 "breaks" 或结束之前经过这么多次。该函数是 return 一个由两部分组成的元组,其中元组的第一个变量是精炼的 x_ 值,第二个变量是一个布尔值,表示该方法是否成功。使用@Blckknght 和@David Bowling 的建议,我能够将我的代码改进为以下内容:

def newtonsMethod(poly, x_, epsilon, timeout):
    """Calculating root of polynomial using newton's Method."""
    deriv_poly = findDerivative(poly)
    deriv = evaluatePoly(deriv_poly, x_)
    value = evaluatePoly(poly, x_)
    count = 1
    while True:
        x_ -= value / deriv
        if abs(value) < epsilon:
            boolean = abs(value) < epsilon
            xTuple = (x_, boolean)
            return xTuple
        if abs(deriv) < epsilon or count > timeout:
            boolean = abs(deriv) < epsilon or count > timeout
            xTuple = (x_, boolean)
            return xTuple
        count += 1

但是,当我 运行 代码时,我仍然遇到崩溃问题。我后来才意识到我不能让两个布尔变量都等于 True(对于我的以下代码,我需要布尔值等于 True 或 False)但是为了停止循环,if 语句之一必须等于 True。 对于此代码所需的所有混淆和规范,我深表歉意;我希望这个解释有助于理解我需要什么。

正如 Barmar 评论的那样,使用更简单的 while 条件(可能只是 while True)几乎总是比甚至不能放在一行中的非常复杂的条件更好。您可以将结束循环的实际逻辑放在循环体内的一个或多个 if 语句中:

while True:  # no condition here
    # do stuff

    if failure_condition1():
        break        # stop looping

    if success_condition():
        return result()        # another way to stop looping is to return a value

    if failure_condition2():
        raise SomeException()     # you could also raise an exception on failure

    # do other stuff

returnraisebreak 的任意组合都可能适用于您的函数,这完全取决于满足每个条件时您想做什么(以及您想要什么API 是)。

这种循环方式的一个优点是您可以在算法中任何有意义的地方检查条件。测试不一定要在循环开始时进行(这通常需要您使用首次通过条件的组合值来初始化变量)。

以下是我如何在您的特定问题中应用这种控制流:

def newtonsMethod(poly, x_, timeout):
    """Calculating root of polynomial using newton's Method."""
    estimate = 0
    epsilon = 1e-20
    deriv_poly = findDerivative(poly)
    while True:
        value = evaluatePoly(poly, x_)
        if abs(value) < epsilon:
            return x_
        deriv = evaluatePoly(deriv_poly, x_)
        if abs(deriv) < epsilon or estimate > timeout:
            raise ValueError("Not converging")
        #print(x_, value, deriv)
        x_ -= value / deriv
        estimate += 1

请注意,我们每次只需要调用 evaluatePoly 两次,因为我们保存结果而不是重新计算它们。

我还修复了您代码中的一些错误。我使用 estimate 作为计数器,而不是 x_ 的别名,并且不再将 epsilon 作为在函数体中被覆盖的参数(您也将其拼错为 epislon).

其他人提出的将复杂的条件分解为更简单的语句的建议非常好。您原始条件中的逻辑有问题,但可以调整以使其正常工作。然而你的功能还有其他问题。

不需要在循环之前分配 epsilon 一个值,因为这个值是作为函数参数提供的。 estimate 应该用作计数器,但随后混淆地分配了要在下一次迭代中用于 x_ 的值。我在下面的代码中将 estimate 重命名为 iterations

你应该用过:

abs(evaluatePoly(poly, x_)) > epsilon

因为只要在 x_ 计算的多项式值大于 epsilon,您就希望循环继续。并且,为了避免在更新 x_ 的值的语句中出现困难,您希望仅在以下情况下继续循环:

abs(evaluatePoly(findDerivative(poly), x_)) > epsilon

您的原始代码中缺少条件。最后,如果 iterations 的数量还没有达到 timeout 的值,你想继续循环。如果以上所有条件都满足,你只想循环,所以你的条件表达式应该是:

while abs(evaluatePoly(poly, x_)) > epsilon and \
          abs(evaluatePoly(findDerivative(poly), x_)) > epsilon and \
          iterations < timeout:

我以两种方式更改了你的下一个赋值语句。首先,现在赋值给 x_ 而不是旧的、令人困惑的 estimate 变量。其次,您在两个 evaluatePoly() 函数中都缺少第二个参数。我添加了一行来增加 iterations 计数器,并将 print() 移出循环,以便您只看到最终结果。

修改后的代码如下:

def newtonsMethod(poly, x_, epsilon, timeout):
    """Calculating root of polynomial using newton's Method."""
    iterations = 0
    while abs(evaluatePoly(poly, x_)) > epsilon and \
          abs(evaluatePoly(findDerivative(poly), x_)) > epsilon and \
          iterations < timeout:
        x_ = x_ - (evaluatePoly(poly, x_) / evaluatePoly(findDerivative(poly), x_))
        iterations += 1
    print(x_)

这是使用您提供的 findDerivative()evaluatePoly() 函数的示例 运行:

>>> xpr = [0, 0, 5]
>>> newtonsMethod(xpr, -1, 1e-20, 1000)
-2.91038304567e-11
>>> evaluatePoly(xpr, -2.91038304567e-11)
4.235164736261692e-21

更新:

我查看了您发布的新函数定义,发现了问题所在。您的代码中的根本问题是 valuederiv 仅在循环外评估一次。您需要将这两个语句移动到循环内,以便它们可以在每次迭代后更新。另外,我会将 x_ 的分配移到循环的末尾,以便您的第一个猜测在更新之前得到测试。您还可以稍微简化 if 语句的主体。实际上,当您由于 deriv 的值小得无法接受或超时而转义该函数时,您的函数会报告 True。我假设您希望它报告 False。以下是我如何修改您的代码:

def newtonsMethod(poly, x_, epsilon, timeout):
    """Calculating root of polynomial using newton's Method."""
    deriv_poly = findDerivative(poly)
    count = 1
    while True:
        deriv = evaluatePoly(deriv_poly, x_)
        value = evaluatePoly(poly, x_)

        if abs(value) < epsilon:
            boolean = True
            return (x_, boolean)

        if abs(deriv) < epsilon or count > timeout:
            boolean = False
            return (x_, boolean)

        x_ -= value / deriv
        count += 1

这是一个示例 运行:

>>> xpr = [0, 0, 5]
>>> newtonsMethod(xpr, -1, 1e-20, 1000)
(-2.9103830456733704e-11, True)
>>> evaluatePoly(xpr, -2.9103830456733704e-11)
4.235164736271502e-21

我猜测这些结果与早期结果之间的细微差别是由于舍入误差和不同的计算程序造成的。