【问题标题】:Algorithm for finding a zero point寻找零点的算法
【发布时间】:2011-05-04 15:49:48
【问题描述】:

我有以下挑战:

实现一个函数,在 a 和 b 之间的区间内搜索 sinus 函数的零点。 search-interval[lower limit, upper limit] 应该减半,直到下限和上限之间的距离小于 0.0001。

  1. 找到一个条件来决定必须在哪个减半间隔内继续搜索。因此,在将区间分成两个区间后,我们必须选择一个继续搜索。

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

我在第 1 点上苦苦挣扎。我已经有一些关于该主题的问题对我有很大帮助,但现在我需要在 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;
    }

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

【问题讨论】:

  • 这不是您在此处发布的完全相同的问题吗:stackoverflow.com/questions/4086385/…
  • 如果图表上的 x1 和 x2 是您用于 ab 的值,则您的测试数据违反了 2) 中的假设。
  • 这不是一个新问题,只是对旧问题(实际上是两个旧问题)的重述。简单地编辑这些问题就足够了。投票结束。
  • 投票结束而不是投票就足够了,问题本身还不错......

标签: java algorithm recursion iteration


【解决方案1】:

如果 a 和 b 之间只有一个零点,这意味着 sign(sin(a)) != sign(sin(b))。在用中点替换 a 或 b 时,您需要通过执行以下操作来确保情况仍然如此:

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

符号(x)定义为

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

【讨论】:

    【解决方案2】:

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

    1. 零点在左半边
    2. 零点在右半边
    3. 二等分是零点。

    如果二等分点是零点,你就完成了。

    否则,包含过零的段的端点必须有不同的符号。

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

    【讨论】:

      【解决方案3】:

      你几乎猜对了。您根据符号变化选择区间 - 如果符号在区间的左右边界之间发生变化,则选择该区间:

      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 轴。然后符号可能会在两个间隔中发生变化,并且此函数将只选择正确的一个(中间到 b),您将丢失一些解决方案。

      【讨论】:

        【解决方案4】:

        给定 x 在 [a,b] 有界区间 (aR 在 [a,b] 上有一个根,即有当且仅当 f(a)*f(b)

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

        为了找到那个点,我们将使用区间的二分法。

        我将修改此代码如下:

          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);
                }
            }
        

        【讨论】:

          猜你喜欢
          • 2019-05-03
          • 2010-10-24
          • 2010-12-23
          • 2011-11-29
          • 2020-01-27
          • 2015-02-28
          • 1970-01-01
          • 2013-05-28
          • 2021-08-25
          相关资源
          最近更新 更多