Pergunta

Eu tenho este código:

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;
        }
    }
}

Este método SQRT é chamado "Heroon".
Se eu executar meu programa e pedir 80000 cálculos e desativar a saída, Math.Sqrt () é muito mais rápido que o meu método. Se eu pedir 80000 Calcs e ativar a saída, meu método será muito mais rápido.

Alguém pode explicar isso?

Obrigado

Desculpe pelo inglês ruim.

Foi útil?

Solução

Não pude reproduzir seus resultados. Tentei algumas vezes usando o Eclipse Galileo e o JDK 1.6.0.

Para 80000, saída desativada, eu tenho algo como:

Math: 15 milliseconds
I:    32 milliseconds

pequenos tempos, seria melhor usar System.nanoTime() ou mais interações.

Para 80000, a saída ativada:

Math: 3609 milliseconds
I:    4906 milliseconds

Então, provavelmente, o problema é a maneira como a saída é tratada (rolagem, buffer, ...)

Outras dicas

O método Math.Sqrt adia a StrictMath.Sqrt, que é feito em hardware ou código nativo. (Veja a fonte do JDK - você verá que é um método nativo.) Isso é certamente mais rápido do que qualquer coisa que você escrever. Pode até estar usando o mesmo algoritmo que você codificou. É bem conhecido. Seu método é simplesmente o método de Newton para calcular raízes quadradas. É conhecido Desde Babilônia; Newton simplesmente o rederou usando cálculo. A convergência quadrática é boa.

O que você fez, é improvável que você tenha descoberto algo novo ou digno de nota. Parece que algo tem a ver com IO está influenciando artificialmente os resultados.

Você provavelmente está sobrecarregado o tempo real de cálculo com o tempo de saída e que está de acordo com um acaso do buffer. Um perfilador mostraria o que realmente está consumindo o tempo.

Parabéns por tentar melhorar uma implementação existente; Mesmo se você falhar, pode aprender muito sobre algoritmos no processo. Naturalmente, você deve testar sua alternativa usando esse tipo de micro-benchmark. Infelizmente, existem inúmeras armadilhas. Em particular, não misture código irrelevante, por exemplo, teste e saída, com seu cálculo; Faz Aqueça a JVM no início do seu teste. Há mais nisso Artigo sobre Bechmarking. Além disso, ao comparar valores de ponto flutuante, considere estes Diretrizes para comparar números de ponto flutuante.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top