Une bonne façon de faire une division rapide en C ++?
Parfois je vois et qui ont utilisé la suite de la variation rapide de la diviser en C++ avec des nombres à virgule flottante.
//orig loop
double y = 44100.0;
for(int i=0; i<10000; ++i) {
double z = x / y;
}
//alternative
double y = 44100;
double y_div = 1.0 / y;
for(int i=0; i<10000; ++i) {
double z = x * y_div;
}
Mais quelqu'un a laissé entendre récemment que cela pourrait ne pas être la façon la plus précise.
Toutes les pensées?
source d'informationauteur Stephen Blinkhorn
Vous devez vous connecter pour publier un commentaire.
Sur tous les CPU, un flottant fracture est plusieurs fois plus cher qu'un virgule flottante multiplier, donc en multipliant par l'inverse de votre diviseur est une bonne optimisation. L'inconvénient est qu'il ya une possibilité que vous allez perdre un très petite portion de précision sur certains processeurs, par exemple, sur les processeurs x86 modernes, 64-bit à virgule flottante opérations sont en fait calculé en interne à l'aide de 80 bits lors de l'utilisation de la valeur par défaut FPU mode, et de le stocker dans une variable de ceux provoquer une précision supplémentaire bits pour être tronqué selon votre FPU mode d'arrondi (qui est par défaut la plus proche). Cela seul qui compte vraiment, si vous êtes de la concaténation de plusieurs flottent des opérations et de l'avoir à vous soucier de l'accumulation d'erreurs.
Wikipedia d'accord que cela peut être plus rapide. L'article lié contient également plusieurs autres de division rapide des algorithmes qui peuvent être d'intérêt.
Je suppose que toute puissance industrielle moderne compilateur va faire que l'optimisation pour vous si c'est pour le bénéfice de vous.
Original de votre
peut être facilement optimisé pour
et de la performance est assez agréable. 😉
EDIT: les Gens continuer à voter ce bas, voici donc la version drôle:
Si il y avait une façon générale, à la division plus rapide pour tous les cas, ne pensez-vous pas que les rédacteurs du compilateur pourrait avoir lieu dès maintenant? Bien sûr, ils l'auraient fait. Aussi, certains de les gens qui font de la FPU, les circuits ne sont pas exactement stupide, soit.
Donc la seule façon que vous allez obtenir le meilleur rendement est de savoir à quelle situation spécifique, vous avez à portée de main et de faire un code optimal. Le plus probable c'est un gaspillage de votre temps, parce que votre programme est lent pour d'autres raisons telles que l'exécution de maths sur les invariants de boucle. Allez trouver un meilleur algorithme à la place.
Audio, hunh? Ce n'est pas seulement de 44 100 divisions par seconde lorsque vous avez, disons, cinq pistes audio fonctionnant à la fois. Même un simple fader consomme des cycles, après tout. Et ce n'est qu'assez de bare-bones, exemple minimal-si vous voulez avoir, disons, un égaliseur et un compresseur? Peut-être un peu de réverbération? Votre total de mathématiques budget, pour ainsi dire, se mange rapidement. Il ne sens pour l'essorer un peu plus de performance dans ces cas.
Profileurs sont bonnes. Les profileurs sont à votre ami. Les profileurs méritent des fellations et pudding. Mais vous le savez déjà où le principal goulot de bouteille est en audio, il est dans la boucle qui traite les échantillons, et le plus vite vous pouvez le faire que, le plus heureux de vos utilisateurs. Utilisez tout ce que vous pouvez! Multiplier par inverses, de décalage de bits à chaque fois que possible (exp(x*y) = exp (x)*exp(y), après tout), l'utilisation de tables de recherche, de référence à des variables par référence au lieu de valeurs (moins de pousser ou de sauter sur la pile), refactoriser termes, et ainsi de suite. (Si vous êtes bon, vous allez rire à ces élémentaire optimisations.)
Dans votre exemple, à l'aide de
gcc
la division avec les options-O3 -ffast-math
donne le même code que la multiplication sans-ffast-math
. (Dans un environnement de test avec assez volatiles autour de la boucle est toujours là.)Donc, si vous voulez vraiment optimiser ces divisions à l'écart et ne se soucient pas des conséquences, c'est le chemin à parcourir. La Multiplication semble être à peu près 15 fois plus rapide, btw.
multiplication est plus rapide que la division jusqu'à la deuxième méthode est plus rapide. Il pourrait être un peu moins précis, mais sauf si vous faites de noyau dur numerics le niveau de précision devrait être plus que suffisant.
Lors du traitement de l'audio, je préfère utiliser de point fixe de mathématiques à la place. Je suppose que cela dépend du niveau de précision dont vous avez besoin. Mais, supposons que 16.16 point fixe entiers feront (sens élevé de 16 bits nombre entier, faible 16 est la fraction). Maintenant, tous les calculs peuvent être faits en tant que simple math entier:
Ou avec des macros à l'aide:
J'sont en boucle de 10 000 fois simplement pour rendre le code de tenir assez longtemps pour mesurer le temps facilement? Ou avez-vous des 10000 numéros de diviser par le même nombre? Dans le premier cas, de mettre le "y_div = 1.0 /y;" à l'intérieur de la boucle, parce que ça fait partie de l'opération.
Si le dernier, oui, à virgule flottante de multiplication est généralement plus rapide que la division. Ne changez pas votre code à partir de l'évidence pour les arcanes basé sur des suppositions. De référence pour trouver lente spots, et puis d'optimiser ceux (et de prendre des mesures avant et après pour vous assurer que votre idée en réalité provoque une amélioration)
Je suppose à partir de l'original post que x n'est pas une constante montré là, mais probablement de données à partir d'un tableau donc x[i] est susceptible d'être la source des données et de même pour la sortie, il sera stocké quelque part dans la mémoire.
Je suggère que si le nombre de boucles est vraiment 10 000 dans le post original qu'il fera peu de différence que vous utilisez comme la totalité de la boucle ne prendront même pas une fraction de milliseconde de toute façon sur un processeur récent. Si le nombre de boucles est vraiment très beaucoup plus élevé, peut-être 1 000 000 ou plus, alors je m'attends à ce que le coût d'accès à la mémoire serait susceptible de rendre le fonctionnement plus rapide complètement sans importance de toute façon comme il sera toujours en attente pour les données de toute façon.
Je vous propose d'essayer à la fois avec votre code et des tests si cela fait vraiment aucune différence significative dans le temps d'exécution et si elle n'est pas le cas, alors il suffit d'écrire à la simplicité de la division si c'est ce que l'algorithme besoins.
ici, est le problème de le faire avec de la réciprocité, il vous reste à faire la division avant que vous pouvez réellement diviser par Y. à moins que votre seule en divisant par Y puis je suppose que cela peut être utile. ce n'est pas très pratique étant donné que la division se fait en binaire avec des algorithmes similaires.
Sur de vieux Processeurs comme le 80286, à virgule flottante mathématiques est incroyablement lent et nous avons utilisé beaucoup de trickiness pour accélérer les choses.
Sur les Processeurs modernes à virgule flottante les maths, c'est absolument rapide et l'optimisation des compilateurs peuvent généralement faire des merveilles avec une syntonisation fine des choses.
Il n'est presque jamais la valeur de l'effort d'employer peu de micro-optimisations comme ça.
Essayez de faire de votre code simple et idiot-proof. Seulement de vous trouver un véritable goulot d'étranglement (à l'aide d'un profileur) penseriez-vous d'optimisations dans vos calculs en virgule flottante.