Java: cálculos de desempenho SQRT de desempenho
-
22-09-2019 - |
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.
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.