2

私はこのコードを持っています:

package math;

import java.io.IOException;
import java.util.Scanner;

public class Main
{
    public static void main(String[] args) throws IOException
    {
        System.out.println("Hi, I will beat Java's Math.sqrt(double) method");
        System.out.println("Both ways of calculation will be done");
        System.out.println("I will time how long they took to calculate");
        System.out.println("Random doubles will be generated");
        System.out.println();
        System.out.println("Please give the number of sqrt-calculation will be done");
        int calcs = new Scanner(System.in).nextInt();
        boolean output = true;
        if (calcs > 10000)
        {
            System.out.println("You're asking much calculations");
            System.out.println("Disabling output is recommend");
            System.out.println("Disable output? (y/n)");
            char a = (char) System.in.read();
            if (a == 'y')
            {
                output = false;
            }
        }
        System.out.println("Press enter to start");
        System.in.read();
        test(calcs, output);
        System.out.println();
        System.out.println("I was much faster I think");
        System.out.println("Now you can check my precision");
        System.out.println("Please give a complex double");
        double x = Double.parseDouble(new Scanner(System.in).next());
        System.out.println();
        System.out.println("Math.sqrt(" + x + ")           = " + Math.sqrt(x));
        System.out.println("SqrtCalculator.sqrt(" + x + ") = " + sqrt(x));
        System.out.println("------------------------");
        System.out.println("Now please make your conclusion");
        System.out.println("Thanks for trying");
    }

    public static void test(int calculations, boolean output)
    {
        double factor = Math.random() / 2;
        // Math
        long mathStart = System.currentTimeMillis();
        for (int i = 1; i <= calculations; i++)
        {
            double x = i * factor;
            double result = Math.sqrt(x);
            if (output)
            {
                System.out.println("Math.sqrt(" + x + ") =  " + result);
            }
        }
        long mathStop = System.currentTimeMillis();
        long mathTime = mathStop - mathStart;
        // My Method
        long myStart = System.currentTimeMillis();
        for (int i = 1; i <= calculations; i++)
        {
            double x = i * factor;
            double result = sqrt(x);
            if (output)
            {
                System.out.println("SqrtCalculater.sqrt(" + x + ") =  " + result);
            }
        }
        long myStop = System.currentTimeMillis();
        long myTime = myStop - myStart;
        System.out.println();
        if (output)
            System.out.println("---------------------------");
        System.out.println("Here are the results:");
        System.out.println("Math and SqrtCalculator did each " + calculations + " of the same sqrt-calculations");
        System.out.println();
        System.out.println("Math: " + mathTime + " milliseconds");
        System.out.println("I:    " + myTime + " milliseconds");
    }

    public final static double sqrt(double x)
    {
        double previous = 1;
        double now = 0;
        for (;;)
        {
            now = (x / previous + previous) / 2;
            if (previous == now)
            {
                return now;
            }
            previous = now;
        }
    }
}

このsqrtメソッドは「heroon」と呼ばれます。
プログラムを実行して80000の計算を要求し、出力を無効にすると、Math.sqrt()はメソッドよりもはるかに高速になります。80000 calcsを要求し、出力を有効にすると、私の方法ははるかに高速になります。

誰かがこれを説明できますか?

ありがとう

英語が下手でごめんなさい。

4

4 に答える 4

5

Math.sqrtメソッドは、ハードウェアまたはネイティブコードで実行されるStrictMath.sqrtに従います。(JDKのソースを見てください。これがネイティブメソッドであることがわかります。)これは、これから作成するものよりも確かに高速です。コーディングしたのと同じアルゴリズムを使用している可能性もあります。よく知られています。あなたの方法は、平方根を計算するためのニュートン法です。それはバビロン以来知られています; ニュートンは、微積分を使用してそれを単純に再導出しました。二次収束は良好です。

何をしたとしても、新しいものや注目に値するものを発見した可能性はほとんどありません。IOに関係していることが、結果に人為的にバイアスをかけているように聞こえます。

于 2010-01-03T16:40:32.337 に答える
5

結果を再現できませんでした。Eclipse Galileo と JDK 1.6.0 を使用して何度か試しました。

80000 の場合、出力が無効になり、次のような結果が得られました。

Math: 15 milliseconds
I:    32 milliseconds

System.nanoTime()小さいときは、以上のやり取りを利用したほうがよいでしょう。

80000 の場合、出力可能:

Math: 3609 milliseconds
I:    4906 milliseconds

したがって、おそらく問題は、出力の処理方法 (スクロール、バッファリングなど) にあります。

于 2010-01-03T20:53:46.117 に答える
3

あなたはおそらく実際の計算時間を出力時間で圧倒し、バッファリングのまぐれにぶつかっています。プロファイラーは、実際に時間を消費しているものを示します。

于 2010-01-03T16:38:37.303 に答える
3

既存の実装を改善しようとしていることに感謝します。たとえ失敗しても、その過程でアルゴリズムについて多くを学ぶことができます。当然、この種のマイクロベンチマークを使用して代替案をテストする必要があります。残念ながら、多くの落とし穴があります。特に、テストや出力などの無関係なコードを計算に混ぜないでくださいテストの早い段階で JVM をウォームアップしてくださいベンチマークに関するこの記事には、さらに多くの情報があります。また、浮動小数点値を比較する場合は、浮動小数点数の比較に関するガイドラインを考慮してください。

于 2010-01-03T17:20:09.060 に答える