求函数的根/零点

发布于 2024-10-20 21:25:29 字数 1395 浏览 5 评论 0原文

我试图通过使用二分法找到函数的根,指出:

if f(a)*f(b) < 0 then a root exists, 
then you repeat with f(a)*f(c)<0 where c = (a+b)/2       

但我不确定如何修复代码以使其正常工作。 这是我的代码,但它无法正常工作

from scipy import *
from numpy import *


def rootmethod(f, a, b, tol):


    x = a
    fa = sign(eval(f))

    x = b
    fb = sign(eval(f))

    c = a + b
    iterations = 0

    if fa == 0:
        return a
    if fb == 0:
        return b

    calls = 0         
    fx = 1

    while fx != 0:
        iterations = iterations + 1
        c *= 0.5
        x = a + c
        fc = sign(eval(f))
        calls = calls + 1

        if fc*fa >= 0:
            x = a
            fx = sign(eval(f))
        if fc == 0 or abs(sign(fc)) < eps:
            fx = sign(eval(f))
            return x, iterations, calls





print rootmethod("(x-1)**3 - 1", 1, 3, 10*e-15)

新编辑..但仍然无法正常工作

   if fa*fb < 0:

        while fx != 0:
            iterations = iterations + 1
            c = (a + b)/2.0
            x =  c
            fc = sign(eval(f))
            calls = calls + 1

            if fc*fa >= 0:
                x = c
                fx = sign(eval(f))
            if fc == 0 or abs(sign(fc)) < tol:
                fx = sign(eval(f))
                return x, iterations, calls

编辑:将方法描述中的 c=(a+b)*2 更改为 c=(a+b)/2 。

I am trying to find a root of a function by using the bisection method stating that :

if f(a)*f(b) < 0 then a root exists, 
then you repeat with f(a)*f(c)<0 where c = (a+b)/2       

but im not sure how to fix the code so it works properly.
This is my code but its not working properly

from scipy import *
from numpy import *


def rootmethod(f, a, b, tol):


    x = a
    fa = sign(eval(f))

    x = b
    fb = sign(eval(f))

    c = a + b
    iterations = 0

    if fa == 0:
        return a
    if fb == 0:
        return b

    calls = 0         
    fx = 1

    while fx != 0:
        iterations = iterations + 1
        c *= 0.5
        x = a + c
        fc = sign(eval(f))
        calls = calls + 1

        if fc*fa >= 0:
            x = a
            fx = sign(eval(f))
        if fc == 0 or abs(sign(fc)) < eps:
            fx = sign(eval(f))
            return x, iterations, calls





print rootmethod("(x-1)**3 - 1", 1, 3, 10*e-15)

New edit.. but still doesnt work

   if fa*fb < 0:

        while fx != 0:
            iterations = iterations + 1
            c = (a + b)/2.0
            x =  c
            fc = sign(eval(f))
            calls = calls + 1

            if fc*fa >= 0:
                x = c
                fx = sign(eval(f))
            if fc == 0 or abs(sign(fc)) < tol:
                fx = sign(eval(f))
                return x, iterations, calls

Edit: Changed c=(a+b)*2 to c=(a+b)/2 in the description of the method.

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

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

发布评论

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

评论(4

花想c 2024-10-27 21:25:29

坦率地说,你的代码有点混乱。这是一些有效的方法。阅读循环中的评论。
(顺便说一句,给定函数的解是 2,而不是 3.75)

from scipy import *
from numpy import *


def rootmethod(f, a, b, tol):


  x = a
  fa = sign(eval(f))

  x = b
  fb = sign(eval(f))

  c = a + b
  iterations = 0

  if fa == 0:
    return a
  if fb == 0:
    return b

  calls = 0         
  fx = 1

  while 1:
    x = (a + b)/2
    fx = eval(f)

    if abs(fx) < tol:
      return x

    # Switch to new points.
    # We have to replace either a or b, whichever one will
    # provide us with a negative 
    old = b # backup variable
    b = (a + b)/2.0

    x = a
    fa = eval(f)

    x = b
    fb = eval(f)

    # If we replace a when we should have replaced b, replace a instead
    if fa*fb > 0:
      b = old
      a = (a + b)/2.0




print rootmethod("(x-1)**3 - 1", 1, 3, 0.01)

Frankly your code was a bit of a mess. Here's some that works. Read the comments in the loop.
(BTW the solution to your given function is 2, not 3.75)

from scipy import *
from numpy import *


def rootmethod(f, a, b, tol):


  x = a
  fa = sign(eval(f))

  x = b
  fb = sign(eval(f))

  c = a + b
  iterations = 0

  if fa == 0:
    return a
  if fb == 0:
    return b

  calls = 0         
  fx = 1

  while 1:
    x = (a + b)/2
    fx = eval(f)

    if abs(fx) < tol:
      return x

    # Switch to new points.
    # We have to replace either a or b, whichever one will
    # provide us with a negative 
    old = b # backup variable
    b = (a + b)/2.0

    x = a
    fa = eval(f)

    x = b
    fb = eval(f)

    # If we replace a when we should have replaced b, replace a instead
    if fa*fb > 0:
      b = old
      a = (a + b)/2.0




print rootmethod("(x-1)**3 - 1", 1, 3, 0.01)
眼趣 2024-10-27 21:25:29

我相信你的循环应该是这样的(在伪代码中,并省略一些检查):

before loop:
a is lower bound
b is upper bound
Establish that f(a) * f(b) is < 0

while True:
    c = (a+b)/2
    if f(c) is close enough to 0:
        return c
    if f(a) * f(c) > 0:
        a = c
    else
        b = c

换句话说,如果中点不是答案,则根据其符号将其作为新端点之一。

I believe your loop should be something like this (in pseudocode, and leaving out some checking):

before loop:
a is lower bound
b is upper bound
Establish that f(a) * f(b) is < 0

while True:
    c = (a+b)/2
    if f(c) is close enough to 0:
        return c
    if f(a) * f(c) > 0:
        a = c
    else
        b = c

In other words, if the midpoint isn't the answer, then make it one of the new endpoints depending on its sign.

惯饮孤独 2024-10-27 21:25:29

我认为的一个问题是:

    x = a + c

由于c = (a + b)*.5,你不需要添加a在这里...

更新

您似乎没有检查fa * fb fa * fb < 0 开始,我也不知道你在哪里缩小范围:你应该将 ab 重新分配给 c< /code> 在循环中,然后重新计算 c

代码 自从我上次玩Python以来已经有一段时间了,所以要持保留态度^_^

x = a
fa = sign(eval(f))

x = b
fb = sign(eval(f))

iterations = 0

if fa == 0:
    return a
if fb == 0:
    return b

calls = 0         
fx = 1

while fa != fb:
    iterations += 1
    c = (a + b)/2.0
    x = c
    fc = eval(f)
    calls += 1

    if fc == 0 or abs(fc) < tol:
        #fx = fc not needed since we return and don't use fx
        return x, iterations, calls
    fc = sign(fc)
    if fc != fa:
        b = c
        fb = fc
    else
        a = c
        fa = fc
#error because no zero is expected to be found

I think your one problem is with:

    x = a + c

Since c = (a + b)*.5, you don't need to add in a here...

Update

You don't seem to check if fa * fb < 0 to start, and I also don't see where you're narrowing your bounds: you should either reassign a or b to c in your loop and then recalculate c.

Code It's been a while since I played with python last, so take it with a grain of salt ^_^

x = a
fa = sign(eval(f))

x = b
fb = sign(eval(f))

iterations = 0

if fa == 0:
    return a
if fb == 0:
    return b

calls = 0         
fx = 1

while fa != fb:
    iterations += 1
    c = (a + b)/2.0
    x = c
    fc = eval(f)
    calls += 1

    if fc == 0 or abs(fc) < tol:
        #fx = fc not needed since we return and don't use fx
        return x, iterations, calls
    fc = sign(fc)
    if fc != fa:
        b = c
        fb = fc
    else
        a = c
        fa = fc
#error because no zero is expected to be found
人│生佛魔见 2024-10-27 21:25:29

请注意,该代码有一个由舍入错误引起的简单缺陷

a=0.015707963267948963 
b=0.015707963267948967
c=(a+b)*.5 

c 再次变为 b(检查一下!)。
你可能会陷入无限循环
如果公差非常小,例如 1e-16。

def FindRoot( fun, a, b, tol = 1e-16 ):
  a = float(a)
  b = float(b)
  assert(sign(fun(a)) != sign(fun(b)))  
  c = (a+b)/2
  while math.fabs(fun( c )) > tol:
    if a == c or b == c: 
      break
    if sign(fun(c)) == sign(fun(b)):
      b = c
    else:
      a = c
    c = (a+b)/2
  return c

现在,一遍又一遍地调用 eval 效率不是很高。
您可以执行以下操作

expr = "(x-1.0)**3.0 - 1.0"
fn = eval( "lambda x: " + expr )
print FindRoot( fn, 1, 3 )

或者您可以将 eval 和 lambda 定义放在 FindRoot 中。

有帮助吗?

    Reson

Please note that the code has a simple deficiency caused by round-off errors

a=0.015707963267948963 
b=0.015707963267948967
c=(a+b)*.5 

c is becoming b again (check it out!).
You can end up in infinite loop
in case of very small tolerance like 1e-16.

def FindRoot( fun, a, b, tol = 1e-16 ):
  a = float(a)
  b = float(b)
  assert(sign(fun(a)) != sign(fun(b)))  
  c = (a+b)/2
  while math.fabs(fun( c )) > tol:
    if a == c or b == c: 
      break
    if sign(fun(c)) == sign(fun(b)):
      b = c
    else:
      a = c
    c = (a+b)/2
  return c

Now, to call the eval over and over again is not very efficient.
Here is what you can do instead

expr = "(x-1.0)**3.0 - 1.0"
fn = eval( "lambda x: " + expr )
print FindRoot( fn, 1, 3 )

Or you can put the eval and lambda definition inside the FindRoot.

Was it helpful?

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