web-dev-qa-db-fra.com

Équerre rapidement un double

Je cherche le moyen le plus rapide de mettre un double au carré (double d). Jusqu'à présent, j'ai trouvé deux approches:

1. d*d
2. Math.pow(d, 2)

Pour tester les performances, j'ai mis en place trois cas de test, dans chacun je génère des nombres aléatoires en utilisant la même graine pour les trois cas et je calcule simplement le nombre au carré dans une boucle 100 000 000 fois.

Dans le premier cas, les numéros sont générés à l'aide de random.nextDouble(), dans le second cas à l'aide de random.nextDouble()*Double.MAX_VALUE et dans le troisième à l'aide de random.nextDouble()*Double.MIN_VALUE.

Les résultats de quelques exécutions (résultats approximatifs, theres toujours une certaine variation, exécutez en utilisant Java 1.8, compilé pour Java 1.6 sur Mac OSX Mavericks)

Approach | Case 1 | Case 2 | Case 3
---------•--------•--------•-------
    1    | ~2.16s | ~2.16s | ~2.16s
    2    | ~9s    | ~30s   | ~60s

La conclusion semble être que l'approche 1 est beaucoup plus rapide mais aussi que Math.pow Semble se comporter un peu bizarrement.

J'ai donc deux questions:

1 Pourquoi Math.pow Est-il si lent et pourquoi fait-il mal avec > 1 Et pire encore avec < -1 Chiffres?

2 Existe-t-il un moyen d'améliorer les performances par rapport à ce que j'ai suggéré comme approche 1? Je pensais à quelque chose comme:

long l = Double.doubleToRawLongBits(d);
long sign = (l & (1 << 63));
Double.longBitsToDouble((l<<1)&sign);

Mais c'est a) faux, et b) à peu près à la même vitesse que l'approche 1.

17
Samuel

Le moyen le plus rapide de mettre un nombre au carré est de le multiplier par lui-même.

Pourquoi est-ce Math.pow tellement lent?

Ce n'est vraiment pas le cas, mais il effectue exponentiation au lieu d'une simple multiplication.

et pourquoi fait-il mal avec> 1 et pire encore avec <-1 numéros

D'abord parce qu'il fait le calcul. De la Javadoc il contient également des tests pour de nombreux cas de coin. Enfin, je ne compterais pas trop sur votre micro-benchmark.

10
Elliott Frisch

La quadrature en multipliant avec soi est la plus rapide. Parce que cette approche peut être directement traduite en un bytecode simple et sans branchement (et donc indirectement en code machine).

Math.pow () est une fonction assez complexe qui comporte diverses garanties pour les cas Edge. Et il doit être appelé au lieu d'être intégré.

6
Durandal

Math.pow() est lente car elle doit traiter le cas générique ou élever un nombre à une puissance donnée.
Quant à savoir pourquoi il est plus lent avec des nombres négatifs, c'est parce qu'il doit tester si la puissance est positive ou négative afin de donner le signe, c'est donc une opération de plus à faire.

2
Varpie