0

我想找到正弦函数的零点。参数是一个区间 [a,b]。我必须类似于二进制搜索。

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

这是我的代码:

public class Aufg3 {
    public static void main(String[] args) {

        System.out.println(zeropoint(5,8));
    }

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

        if(Math.sin(middle) < 0){
            return zeropoint(a,middle);
        }else if(Math.sin(middle) > 0){
            return zeropoint(middle,b);
        }else{
            return middle;
        }       
    }
}

它给了我很多错误return zeropoint(middle,b);

在第一步中,我只想找到区间中的第一个零点。

有任何想法吗?

4

8 回答 8

6

每个人都忽略的基本问题:

  • 我们并不总是想要返回一个结果(想象一下在 pi/4 和 3pi/4 之间找到正弦函数的零点,没有)。
  • 在任何任意范围范围内都可能有多个零。

显然需要的是一组(可能是空的)值。

所以真正要求的函数的伪代码(不使用Java,因为这是家庭作业):

Set zeropoint(double a, double b)
{
    double middle = mid point of a and b;
    if a and be less than 0.0001 apart
    {
        if (sin(a) and sin(b) are on opposite sides of 0)
        { 
            return set containing middle
        }
        else
        {
            return empty set
        }
    }
    else
    {
        return union of zeropoint(a, middle) and zeropoint(middle, b)
    }
} 
于 2010-11-03T12:03:34.013 回答
3

我猜你在运行时遇到堆栈溢出错误。< 和 > 符号是相反的。此外,您应该使用 .0001 而不是 0 进行比较。

编辑 1:实际上,您的基本算法有问题。如果间隔中有多个零会发生什么?如果 sin(a) 和 sin(mitte) 有相同的符号会发生什么?如果间隔中没有零会发生什么?

编辑2:好的,所以我做了这个问题,从根本上说,你的解决方案有问题;我会尝试重新开始思考如何解决它。

主要问题是间隔中可能有多个零,而您正试图找到它们中的每一个。创建一个返回 double 类型的函数只能返回一个解决方案。因此,与其创建一个返回 double 的函数,不如返回 void 并在找到它们时打印出零。

另一个提示:您应该继续搜索,直到 a 和 b 彼此相距在 0​​.0001 以内。您的最终解决方案不会以任何其他方式使用 .0001。(即,您检查是否找到零不应使用 .0001 容差,也不会完全使用 0。想想当 abs(ab) 小于 0.0001 时,您将如何真正知道是否找到零.

于 2010-11-03T11:15:05.560 回答
3

简单地说“它给了我错误”并不是很有帮助。什么样的错误?在运行时编译错误或未捕获的异常?

对于您的代码,有两件事可能会引起问题:

  1. 该变量mitte似乎没有在任何地方声明。
  2. 您正在使用 > 和 < 来比较实数。虽然这本身没问题,但最好使用容差检查 0 而不是依赖 < 和 >,以避免因浮点精度引起的问题。出于所有实际目的,-0.000000000001 为 0。

可能还有其他问题,我只是把第一眼跳出来的写下来。

编辑:

显然这mitte是由于 OP 在粘贴代码时出错(并且已经更正)。正如其他答案所指出的那样,代码陷入无限递归。这是因为递归调用的间隔错误。

需要注意的一点是,sin 函数对于 a 和 b 的一种选择可以单调递增,而在其他某个区间单调递减。例如,它在 [0,pi/2] 上增加,在 [pi/2,3*pi/2] 上减少。因此,递归调用需要根据进行搜索的原始间隔进行更改。对于一个间隔 Math.sin(middle)<0 意味着 Math.sin(x)<0 对于 [a,middle] 中的所有 x,但对于其他一些时间间隔,情况正好相反。这可能是您尝试的区间陷入无限递归的原因。我认为这在罪恶实际上正在减少的其他时间段内有效。尝试通过 [pi/2,3*pi/2] 调用您的函数。

于 2010-11-03T11:12:06.793 回答
2

你把作业读到最后了吗?它说:

search-interval[lower limit, upper limit] 应该减半,直到下限和上限之间的距离小于 0.0001。

Math.sin(middle)因此,由于浮点精度问题,您不能期望完全返回零。相反,当您达到 0.0001 精度时,您需要停止递归。

于 2010-11-03T11:11:04.427 回答
2

我的猜测是你遇到了StackOverflowError. 这是因为您在递归中永远不会达到基本情况。(可能永远不会正好Math.sin(middle)等于0!)

你的练习说

[...] 直到下限和上限之间的距离小于 0.0001。

所以,试着把它放在你的方法之上:

double middle = (a + b)/2;
if (b - a < 0.0001)
    return middle;
于 2010-11-03T11:13:37.603 回答
1

除了其他人提到的一些浮点问题外,您的算法似乎基于以下隐含假设:

  1. sin(a) 为正
  2. sin(b) 是负数,并且
  3. sin(x) 是区间 [a,b] 上的递减函数。

我认为这些假设没有根据。当其中任何一个为假时,我不希望您的算法起作用。当 a=5 和 b=8 时,它们都是错误的。

于 2010-11-03T15:37:35.903 回答
0
if(Math.sin(mitte) < 0){

在哪里mitte声明?不是mitte middle吗?

于 2010-11-03T11:11:00.247 回答
0
private static double zeropoint(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 (Math.abs(sin) < 0.0001) {
           result = middle;
        } else if (sin > 0) {
           result = zeropoint(a, middle);
        } else {
           result = zeropoint(middle, b);
        }
    }
    return result;   
}

我认为这样的事情 - 只是为了修复第一个错误

于 2010-11-03T11:23:07.983 回答