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 计算并启用输出,我的方法会快得多。

有人可以解释一下吗?

谢谢

抱歉英语不好。

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 回答