1

「Think Java」の本を使用していますが、演習 7.6 で行き詰まっています。ここでの目標は、 を見つけることができる関数を書くことです。それはあなたにいくつかのヒントを与えます:

評価する 1 つの方法は、無限級数展開を使用することです。

つまり、i 番目の項が等しい一連の項を合計する必要があります。

これが私が思いついたコードですが、(Math.exp と比較すると) 1 の累乗以外の場合はひどく間違っています。本からの公式。これが数学の問題なのか、double と int が保持できる数値の大きさに関連するものなのかはわかりませんが、なぜこれが機能しないのかを理解しようとしています。

   public static void main(String[] args) {
      System.out.println("Find exp(-x^2)");
      double x = inDouble("Enter x: ");
      System.out.println("myexp(" + -x*x + ") = " + gauss(x, 20));
      System.out.println("Math.exp(" + -x*x + ") = " + Math.exp(-x*x));
   }

   public static double gauss(double x, int n) {
      x = -x*x;
      System.out.println(x);
      double exp = 1;
      double prevnum = 1;
      int prevdenom = 1;
      int i = 1;
      while (i < n) {
         exp = exp + (prevnum*x)/(prevdenom*i);
         prevnum = prevnum*x;
         prevdenom = prevdenom*i;
         i++;
      }
      return exp;
   } // I can't figure out why this is so inacurate, as far as I can tell the math is accurate to what the book says the formula is

   public static double inDouble(String string) {
      Scanner in = new Scanner (System.in);
      System.out.print(string);
      return in.nextDouble();
   }
4

1 に答える 1

1

私はあなたの質問に対するコメントに追加しようとしています。これを行うのは、実装が少し優れていると感じているからです。

あなたのアプローチ

あなたのアプローチは、関数が 2 つの引数を受け入れるようにすることです。ここで、2 番目の引数は反復回数です。これは悪くありませんが、@JamesKPolk が指摘したように、オーバーフローしない int (または long) を手動で検索する必要がある場合があります。

私のアプローチ

私のアプローチでは、データ型にマシン イプシロンと呼ばれるものを使用します。マシン イプシロンは、その数値として表現できるその型 (この場合は double) の最小の数値です。クラス内のマシンイプシロンへのアクセスが「許可」されていない場合、そのマシンイプシロンが何であるかを判断するためのアルゴリズムが存在しますDouble

この背後には数学があります。

関数の級数表現はe^(-x^2) の級数表現 次のとおりです。これは交互級数であるため、誤差項は、含めないことを選択した最初の項の絶対値です (証明はあなたに任せます)。

これが意味することは、反復を使用しないエラーベースの実装を持つことができるということです! 最良の部分は、float、および double よりも「多い」データ型に対して実装できることです。私はこう提示します:

public static double gauss(double x) 
{
    x = -x*x;
    double exp = 0, error = 1, numerator = 1, denominator = 1;
    double machineEpsilon = 1.0;
    // calculate machineEpsilon
    while ((1.0 + 0.5 * machineEpsilon) != 1.0)
        machineEpsilon = 0.5 * machineEpsilon;
    int n = 0; //
    // while the error is large enough to be representable in terms of the current data type
    while ((error >= machineEpsilon) || (-error <= -machineEpsilon))
    {
        exp += error;
        // calculate the numerator (it is 1 if we just start, but -x times its past value otherwise)
        numerator = ((n == 0) ? 1 : -numerator * x);
        // calculate the denominator (denominator gets multiplied by n)
        denominator *= (n++);
        // calculate error
        error = numerator/denominator;
    }
    return exp;
}

これがどのように機能するか教えてください!

于 2015-10-03T20:39:22.717 に答える