Question

A une ou deux décennies, il est utile d'écrire un code numérique pour éviter d'utiliser multiplie et divise et se servir de l'addition et de la soustraction à la place.Un bon exemple est l'aide de en avant les différences pour évaluer un polynôme de la courbe, au lieu de le calcul du polynôme directement.

Est-ce toujours le cas ou moderne informatique architectures avancées au point où *,/ ne sont plus beaucoup de fois plus lent que +,- ?

Pour être plus précis, je suis intéressé dans compilé en C/C++ code en cours d'exécution sur moderne typique x86 frites avec de vastes à bord du matériel de point flottant, pas un petit micro en essayant de faire de la PF dans le logiciel.Je me rends compte de pipeline et d'autres améliorations architecturales obstacle spécifique comptage de cycles, mais je voudrais encore pour obtenir une intuition.

Était-ce utile?

La solution

Elle dépend également de l'instruction de mélange.Votre processeur vous disposez de plusieurs unités de calcul en attente à tout moment, et vous obtiendrez un débit maximum si tous sont remplies de tous les temps.Ainsi, l'exécution d'une boucle de mul est aussi rapide que l'exécution d'une boucle ou ajoute - mais les mêmes ne tient pas si l'expression devient de plus en plus complexe.

Par exemple, prenez cette boucle:

for(int j=0;j<NUMITER;j++) {
  for(int i=1;i<NUMEL;i++) {
    bla += 2.1 + arr1[i] + arr2[i] + arr3[i] + arr4[i] ;
  }
}

pour NUMITER=10^7, NUMEL=10^2, les deux tableaux initialisés à de petits nombres positifs (NaN est beaucoup plus lent), cela prend en 6.0 secondes en utilisant un double sur 64 bits proc.Si je remplace la boucle avec

bla += 2.1 * arr1[i] + arr2[i] + arr3[i] * arr4[i] ;

Il faut seulement 1.7 secondes...alors, puisque nous "exagéré" les ajouts, les muls étaient essentiellement libre;et de la réduction des ajouts aidé.Il est plus confuse:

bla += 2.1 + arr1[i] * arr2[i] + arr3[i] * arr4[i] ;

-- même mul/ajouter de la distribution, mais maintenant, la constante est ajoutée plutôt que d'multiplié en-prend en 3,7 secondes.Votre processeur est probablement optimisé pour effectuer des calculs numériques de manière plus efficace;donc produit scalaire comme des sommes de muls et mise à l'échelle sommes sont à peu près aussi bon qu'il obtient;l'ajout des constantes n'est pas aussi commun, de sorte que c'est plus lent...

bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; /*someval == 2.1*/

encore une fois 1.7 secondes.

bla += someval + arr1[i] + arr2[i] + arr3[i] + arr4[i] ; /*someval == 2.1*/

(identique à l'initiale de la boucle, mais sans cher ajout constant:2.1 secondes)

bla += someval * arr1[i] * arr2[i] * arr3[i] * arr4[i] ; /*someval == 2.1*/

(surtout muls, mais un ajout:1.9 secondes)

Donc, en gros;il est difficile de dire qui est plus rapide, mais si vous souhaitez éviter les goulets d'étranglement, le plus important est d'avoir un mélange sain d'esprit, éviter NaN ou INF, éviter d'ajouter des constantes.Quoi que vous fassiez, assurez-vous de tester, et tester les différents paramètres du compilateur, car, souvent, de petits changements peuvent juste faire la différence.

Certains cas de plus:

bla *= someval; // someval very near 1.0; takes 2.1 seconds
bla *= arr1[i] ;// arr1[i] all very near 1.0; takes 66(!) seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; // 1.6 seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; //32-bit mode, 2.2 seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; //32-bit mode, floats 2.2 seconds
bla += someval * arr1[i]* arr2[i];// 0.9 in x64, 1.6 in x86
bla += someval * arr1[i];// 0.55 in x64, 0.8 in x86
bla += arr1[i] * arr2[i];// 0.8 in x64, 0.8 in x86, 0.95 in CLR+x64, 0.8 in CLR+x86

Autres conseils

En théorie l'information est ici:

Intel®64 et IA-32 Architectures Optimisation Manuel de référence, ANNEXE C INSTRUCTIONS LATENCE ET DÉBIT

Pour chaque processeur ils énumèrent, le temps d'attente sur FMUL est très proche de celle de FADD ou FDIV. Sur certains des anciens processeurs, FDIV est 2-3 fois plus lent que, alors que sur les processeurs les plus récents, il est le même que FMUL.

Avertissements:

  1. Le document que je vous dit en fait lié ne pouvez pas compter sur ces chiffres dans la vie réelle puisque le processeur fera ce qu'il souhaite faire les choses plus vite si elle est correcte.

  2. Il y a une bonne chance que votre compilateur décidera d'utiliser l'un des nombreux jeux d'instructions nouvelles qui ont un

    multiplier / diviser disponible à virgule flottante.
  3. Ceci est un document complexe uniquement destiné à être lu par les auteurs du compilateur et je pourrais avoir obtenu mal. Comme je ne suis pas clair pourquoi le nombre de temps d'attente FDIV est complètement absent pour certaines des unités centrales.

La meilleure façon de répondre à cette question est d'écrire en fait une référence / profil du traitement que vous devez faire. Empirique doit être utilisé plus théorique chaque fois que possible. Surtout quand il est facile à atteindre.

Si vous connaissez déjà différentes implémentations du Math que vous devez faire, vous pouvez écrire quelques différents transfermations de code du calcul et de voir où vos pics de performance. Cela permettra au processeur / compilateur pour générer différents flux d'exécution pour remplir les pipelines de traitement et de vous donner une réponse concrète à votre réponse.

Si vous êtes intérêt spécifiquement les performances des instructions DIV / MUL / type ADD / SUB vous pourriez même lancer dans une assemblée en ligne pour contrôler spécifiquement les variantes de ces instructions sont exécutées. Cependant, vous devez vous assurer que vous gardez des unités d'exécution multilple occupé pour avoir une bonne idée de la performance du système est capable.

aussi faire quelque chose comme ceci vous permettra de comparer les performances sur de multiples variations du processeur en exécutant simplement le même programme sur eux, et pourrait également vous permettre de prendre en compte les différences de la carte mère.

Edit:

L'architecture de base d'un + - est identique. Ils prennent donc logiquement en même temps pour calculer. * D'autre part, nécessitent plusieurs couches, généralement construites à partir de « pleins sommateurs » pour terminer une seule opération. Cette garentees que si un * peut être délivré à la conduite de chaque cycle, il aura un temps d'attente supérieur à un circuit addition / soustraction. A fp / opération est généralement réalisée en utilisant une méthode d'approximation itérative qui converge vers la réponse correcte dans le temps. Ces types d'approximations sont généralement mises en œuvre par la multiplication. Donc, pour en virgule flottante, vous pouvez supposer généralement la division prendra plus de temps, car il est impossible de « déroulez » multiplications (ce qui est déjà un grand circuit et il est auto) en pipeline d'une multitude de circuits multiplicateurs. Toujours la performance d'un système donné est mieux mesurée par le test.

Je ne peux pas trouver une référence définitive, mais une vaste expérimentation me dit que la multiplication flottante est aujourd'hui à peu près la même vitesse que l'addition et la soustraction, alors que la division n'est pas (mais pas « plusieurs fois » plus lent, soit). Vous pouvez obtenir l'intuition que vous désirez que par l'exécution de vos propres expériences - rappelez-vous de générer des nombres aléatoires (en millions d'entre eux) à l'avance, les lire avant de commencer à temps, et utiliser les compteurs de performance CPU (sans autre processus en marche, comme autant que vous pouvez les empêcher de) pour une mesure précise!

La différence de vitesse de * / vs + - dépend de l'architecture de votre processeur. En général et x86 en particulier la différence de vitesse est devenue moins avec les processeurs modernes. * Devrait être proche de +, en cas de doute: il suffit de l'expérience. Si vous avez un problème vraiment difficile avec beaucoup d'opérations de PF Pensez également à utiliser votre GPU (GeForce, ...) qui fonctionne comme un processeur vectoriel.

Il y a probablement très peu de différence dans le temps entre la multiplication et l'addition. division d'autre part est encore nettement plus lent que la multiplication en raison de sa nature récursive. sur le fonctionnement du point doivent être considérés comme des instructions sse modernes d'architecture x86 en faisant flotter plutôt que d'utiliser la fpu.Though un bon C / C ++ compilateur devrait vous donner la possibilité d'utiliser sse au lieu de la FPU.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top