0

正弦関数のゼロ点を見つけたい。パラメータは区間[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;
        }       
    }
}

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

実行時にスタックオーバーフローエラーが発生していると思います。<と>の符号が逆になります。また、比較するには0ではなく.0001を使用する必要があります。

編集1:実際、基本的なアルゴリズムには問題があります。間隔に複数のゼロがある場合はどうなりますか?sin(a)とsin(mitte)の符号が同じ場合はどうなりますか?間隔にゼロがない場合はどうなりますか?

編集2:わかりました、それで私は問題を解決しました、そして基本的に、あなたの解決策は問題があります。私はそれを解決する方法を考えて最初からやり直そうとします。

主な問題は、間隔に複数のゼロが存在する可能性があり、それぞれを見つけようとしていることです。double型を返す関数を作成すると、1つの解しか返すことができません。したがって、doubleを返す関数を作成するのではなく、voidを返し、ゼロを見つけたら出力します。

別のヒント:aとbが互いに.0001以内になるまで検索を続けることになっています。最終的なソリューションでは、他の方法で.0001を使用しません。(つまり、ゼロが見つかったかどうかを確認するために、.0001許容値を使用するべきではなく、0を正確に使用することもありません。abs(ab)が.0001未満の場合に、ゼロを見つけたかどうかを実際に知る方法を考えてください。 。

于 2010-11-03T11:15:05.560 に答える
3

単に「エラーが発生する」と言ってもあまり役に立ちません。どんなエラー?実行時にエラーまたはキャッチされない例外をコンパイルしますか?

コードの場合、考えられる問題として2つのことが際立っています。

  1. 変数mitteはどこにも宣言されていないようです。
  2. >と<を使用して実数を比較しています。それ自体は問題ありませんが、浮動小数点の精度による問題を回避するために、<と>に依存するのではなく、許容誤差を使用して0をチェックすることをお勧めします。すべての実用的な目的で、-0.000000000001は0です。

他にも問題があるかもしれませんが、一目で飛び出したものを書き留めておきました。

編集:

どうやら、これmitteはOPによるコードの貼り付けエラーが原因だったようです(その後修正されました)。他の回答が指摘しているように、コードは無限再帰に分類されます。これは、再帰呼び出しの間隔が間違っているためです。

注意すべき点の1つは、sin関数はaとbの1つの選択に対して単調に増加し、他の間隔で単調に減少する可能性があることです。たとえば、[0、pi / 2]を超えて増加し、[pi / 2,3 * pi/2]を超えて減少しています。したがって、再帰呼び出しは、検索が行われている元の間隔に従って変更する必要があります。1つの間隔の場合、Math.sin(middle)<0は、[a、middle]内のすべてのxに対してMath.sin(x)<0を意味します。しかし、他の間隔では、その逆が当てはまります。これがおそらく、これが試行している間隔で無限再帰に分類される理由です。これは、罪が実際に減少している他の間隔で機能すると思います。[pi / 2,3 * pi/2]を介して関数を呼び出してみてください。

于 2010-11-03T11:12:06.793 に答える
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 に答える
2

課題を最後まで読みましたか?それは言う:

検索間隔[下限、上限]は、下限と上限が互いに0.0001未満になるまで半分にする必要があります。

Math.sin(middle)したがって、浮動小数点の精度の問題のために、正確にゼロを返すことは期待できません。代わりに、0.0001の精度に達したときに、再帰を停止する必要があります。

于 2010-11-03T11:11:04.427 に答える
1

他の人が言及したいくつかの浮動小数点の問題に加えて、あなたのアルゴリズムは次のような暗黙の仮定に基づいているようです。

  1. sin(a)は正です
  2. sin(b)は負であり、
  3. sin(x)は、区間[a、b]の減少関数です。

これらの仮定の根拠はわかりません。それらのいずれかが偽の場合、私はあなたのアルゴリズムが機能することを期待していません。a=5およびb=8の場合、これらはすべてfalseです。

于 2010-11-03T15:37:35.903 に答える
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 に答える
0
if(Math.sin(mitte) < 0){

どこでmitte宣言されますか?そうじゃないmitte middle

于 2010-11-03T11:11:00.247 に答える