Java 用递归法求零点
我想找到正弦函数的零点。该参数是一个区间[a,b]。我必须将其与二进制搜索类似 实现一个函数,在a和b之间的间隔内搜索窦函数中的零点。搜索间隔[下限,上限]应减半,直到下限和上限彼此之间的距离小于0.0001 这是我的密码: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
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
似乎没有在任何地方声明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之间找到正弦函数的零点,没有任何结果)
- 在任何任意范围内都可能有几个零
除了前面提到的一些浮点问题外,您的算法似乎基于以下隐式假设:
我看不出这些假设的依据。如果其中任何一个假设为假,我就不指望你的算法能起作用。当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)
}
}