web-dev-qa-db-fra.com

Pourquoi le cube est plus rapide que carré

J'ai écrit ceci:

  var max = 0xffffff * 4;
  var step = 1 / max;
  function cube() {
    var result = 0.;
    for (var x = 0.; x < 1; x += step) {
      result += x * x * x;
    }
    return result;
  }
  function mul() {
    var result = 0.;
    for (var x = 0.; x < 1; x += step) {
      result += x * x;
    }
    return result;
  }
  function go() {
    var r = '';
    r += cube() + ' \n';
    r += mul() + ' \n';
    alert(r);
  }

et voir le résultat dans le profileur Chrome:

mul: 106ms 
cube: 87ms

Comment est-ce possible?

43
shal

Votre affirmation est carrément fausse. cube n’est pas plus rapide que mul et votre exemple ne le prouve pas. 

En fait, ce qui se passe, c’est que les éléments internes de l’exécution de Javascript prennent plus de temps que la multiplication réelle, ce qui entraîne des temps très similaires pour mul et cube. J'ai couru les deux fonctions en boucle, juste pour augmenter la différence et le profileur indique 20219 vs 20197, ce qui est insignifiant. Et BTW, le cube est le "plus lent" ici. 

De plus, cette méthode de profilage ne fonctionne pas car Chrome et Firefox optimisent beaucoup avant de faire des calculs à l'intérieur de boucles. Ce que vous pensez être une boucle peut très bien utiliser une valeur en cache ou même une fonction mathématique dont l'optimisation sait qu'elle renvoie le même résultat.

Voici le code que j'ai utilisé:

<script>
 var max = 0xffffff * 4;
  var step = 1 / max;
  function cube() {
    var result = 0.;
    for (var x = 0.; x < 1; x += step) {
      result += x * x * x;
    }
    return result;
  }
  function mul() {
    var result = 0.;
    for (var x = 0.; x < 1; x += step) {
      result += x * x;
    }
    return result;
  }
  function go() {
    var s='';
    for (var i=0; i<100; i++) {
        s+=cube();
        s+=mul();
    }
    console.log(s);
  }
  go();
</script>

Aussi, à titre de référence seulement, regardez la vidéo ici: https://fosdem.org/2016/schedule/event/mozilla_benchmarking_javascript_tips/ où un gars de Firefox explique pourquoi microbenchmarking ne veut pas vraiment dire grand chose.

34

Cela est probablement dû au fait que, puisque tous vos nombres sont inférieurs à 1, la fonction de cube ajoute des nombres plus petits que le carré et (je ne suis pas sûr que ce soit ainsi que cela fonctionne) prend donc moins de temps. Ceci est juste une supposition. Et parce que les chiffres sont si petits, cela pourrait aussi être dû à une précision insuffisante. J'ai aussi testé avec des nombres supérieurs à un, le cube est plus lent avec eux.

0
C L K Kissane

peut-être que l'optimiseur décide que l'un d'entre eux pourrait être exécuté avec des instructions vectorielles, tandis que l'autre utilise un vieux fmul. Je suppose que 'square' utilise fmul et que cube utilise l'instruction vectorielle mulpd qui peut multiplier jusqu'à 4 doubles dans une instruction. J'ai ajouté un «quad» qui a fait 4 multiplications et son temps est assez proche du cube. mais quand je suis allé à "cinq", il a ralenti plus lentement que carré. C’est une preuve indirecte que les instructions vectorielles sont utilisées pour les cubes et les quadruples.

Il serait intéressant de voir les résultats sur un processeur Intel vs un bras sur une tablette.

0
dmh2000