寻找零点的算法

时间:2010-11-03 18:07:18

标签: java algorithm recursion iteration

我有以下挑战:

实现一个在a和b之间的间隔中搜索窦函数的零点的函数。搜索间隔[下限,上限]应减半,直到下限和上限小于0.0001。

  1. 找到一个条件来决定必须继续搜索的减半间隔。因此,在将间隔缩短为两个间隔后,我们必须选择一个继续我们的搜索。

  2. 我们假设a和b之间的间隔只有一个零点。

  3. alt text

    我正在努力解决第一点。我已经对该主题提出了一些问题,这些问题对我有很大帮助,但现在我需要在java中实现它,但它还没有用。

    到目前为止,这是我的代码:

    private static double nullstelle(double a, double b){
            double middle = (a + b)/2;
            double result = middle;
    
            if(Math.abs(a-b) > 0.0001){
                double sin = Math.sin(middle);
                if(sin > 0){
                    result = nullstelle(a, middle);
                }else{
                    result = nullstelle(middle, b);
                }
            }
            return result;
        }
    

    我尝试使用递归实现,但也许另一种方式会更好,我不知道。 有什么想法吗?

4 个答案:

答案 0 :(得分:2)

由于在我们考虑的时间间隔内最多有一个过零点,因此有三种可能性:

  1. 零点在左半边
  2. 零点在右半边
  3. 二分是零点。
  4. 如果二分点是零点,那么就完成了。

    否则,包含零交叉的段必须在其端点上具有不同的符号。

    递归在其端点上具有不同符号的段

答案 1 :(得分:2)

如果a和b之间只有一个零点,则表示符号(sin(a))!=符号(sin(b))。在用你的中点替换a或b时,你需要通过这样的方式确保这种情况仍然存在:

if (sign(sin(a)) == sign(sin(middle)))
    result = nullstelle(middle, b);
else
    result = nullstelle(a, middle);

将sign(x)定义为

int sign(double x) { return x >= 0 ? 1 : -1; }

答案 2 :(得分:1)

你差不多了。您可以根据符号更改选择间隔 - 如果符号在间隔的左右边界之间发生变化,则选择该间隔:

private static double nullstelle(double a, double b){
        double middle = (a + b)/2;
        double result = middle;

        if(Math.abs(a-b) > 0.0001){
            double sin = Math.sin(middle);
            if(sin == 0) {  // Rare case but might happen
                result = middle;
            } else if (Math.signum(sin) != Math.signum(b))  { // The sign changes between middle and b
                result = nullstelle(middle, b);
            } else if (Math.signum(sin) != Math.signum(a))  { // The sign changes between a and middle
                result = nullstelle(a, middle);
            } else  {
              // Throw an exception here, the sin function does not cross x axis in the given interval
            }
        }
        return result;
    }

另请注意,在给定间隔内,函数可能会越过x轴多次。然后,signum可能会在两个时间间隔内发生变化,此函数将只选择正确的一个(中间到b),您将失去一些解决方案。

答案 3 :(得分:1)

在[a,b]丰富的区间(a&lt; = x&lt; = b)中给出x,我们可以说应用程序f:[a,b] - &gt; R在[a,b]上有一个根,即那里当且仅当f(a)* f(b)<0时,有界区间[a,b]中的x是满足f(x)= o的x。

简单来说,区间上有一个根是该区间上函数变化的符号。

为了找到这一点,我们将使用间隔的二进制分区。

我会修改此代码,如下所示:

  private static double nullstelle(double a, double b){
       double middle = (a + b)/2;

        if(Math.abs(a-b) < 0.0001){
            return middle;
        }
        if(Math.sin(a)*Math.sin(middle)<0) {
            return nullstelle(a, middle);
        }
        if(Math.sin(middle)*Math.sin(b)<0) {
            return nullstelle(middle, b);
        }
    }