Java 用递归法求零点

Java 用递归法求零点,java,math,recursion,binary-search,Java,Math,Recursion,Binary Search,我想找到正弦函数的零点。该参数是一个区间[a,b]。我必须将其与二进制搜索类似 实现一个函数,在a和b之间的间隔内搜索窦函数中的零点。搜索间隔[下限,上限]应减半,直到下限和上限彼此之间的距离小于0.0001 这是我的密码: public class Aufg3 { public static void main(String[] args) { System.out.println(zeropoint(5,8)); } private static

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

实现一个函数,在a和b之间的间隔内搜索窦函数中的零点。搜索间隔[下限,上限]应减半,直到下限和上限彼此之间的距离小于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;
        }       
    }
}
公共类Aufg3{
公共静态void main(字符串[]args){
系统输出println(零点(5,8));
}
专用静态双零点(双a、双b){
双中=(a+b)/2;
if(数学sin(中间)<0){
返回零点(a,中间);
}else如果(数学sin(中间)>0){
返回零点(中间,b);
}否则{
返回中间;
}       
}
}
它在返回零点(中间,b)的直线上给了我很多错误

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

有什么想法吗?

if(Math.sin(mitt)<0){
if(Math.sin(mitte) < 0){

mitt
在哪里声明?mitt不是中间的吗?

你把作业读到最后了吗?上面写着:

搜索间隔[下限,上限] 限制]应减半,直到更低 极限和上限小于 彼此之间的距离为0.0001

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

简单地说“it gives me errors”(它给了我错误)并没有多大帮助。什么类型的错误?编译错误还是运行时未捕获的异常

对于您的代码,有两件事是可能出现的问题:

  • 变量
    mitt
    似乎没有在任何地方声明
  • 您正在使用>和<来比较实数。虽然这本身是可以的,但最好使用公差检查0,而不是依赖<和>,以避免由于浮点精度引起的问题。在所有实际用途中-0.000000000001是0
  • 可能还有其他问题,我只是写下了那些第一眼就跳出来的问题

    编辑:

    显然,
    mitt
    是由于OP粘贴代码时出错造成的(此后已被更正)。正如其他答案所指出的,代码属于无限递归。这是因为递归调用的间隔错误


    需要注意的一点是,sin函数可以在a和b中的一个选项上单调递增,在另一个区间上单调递减。例如,它在[0,pi/2]上递增,在[pi/2,3*pi/2]上递减因此,递归调用需要根据搜索的原始间隔进行更改。对于一个间隔Math.sin(中间)我猜您遇到了一个
    StackOverflowerError
    。这是因为您在递归中从未达到基本情况。(
    Math.sin(中间)
    可能永远不会精确等于0!)

    你的练习说

    […]直到下限和上限彼此之间的距离小于0.0001

    因此,请尝试将其放在方法的顶部:

    double middle = (a + b)/2;
    if (b - a < 0.0001)
        return middle;
    
    double-middle=(a+b)/2;
    如果(b-a<0.0001)
    返回中间;
    
    我猜您在运行时遇到堆栈溢出错误。<和>符号是相反的。此外,您应该使用.0001而不是0来比较

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

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

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

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

    专用静态双零点(双a,双b){
    
    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;   
    }
    
    双中=(a+b)/2; 双重结果=中等; 如果(数学绝对值(a-b)>0.0001){ 双正弦=数学正弦(中间); if(数学绝对值(sin)<0.0001){ 结果=中等; }否则如果(sin>0){ 结果=零点(a,中间); }否则{ 结果=零点(中间,b); } } 返回结果; }

    我想是这样的——只是为了解决大家都忽略的第一个错误:

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

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


    除了前面提到的一些浮点问题外,您的算法似乎基于以下隐式假设:

  • sin(a)是正的
  • sin(b)为负,且
  • sin(x)是区间[a,b]上的递减函数

  • 我看不出这些假设的依据。如果其中任何一个假设为假,我就不指望你的算法能起作用。当a=5和b=8时,它们都是假的。

    也许你应该对当前命名为al的变量使用相同的名称
    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)
        }
    }