Je travaille sur une bibliothèque de traitement d'image qui s'étend sur OpenCV, Halcon, .... La bibliothèque doit être avec .NET Framework 3.5 et, depuis que mes expériences avec .NET sont limitées, je voudrais poser quelques questions concernant la performance.
J'ai rencontré quelques éléments spécifiques que je ne peux pas m'expliquer correctement et je voudrais vous aimer Demander à A) Pourquoi et b) quelle est la meilleure pratique pour faire face aux cas. P>
Ma première question concerne les maths.pow. J'ai déjà trouvé des réponses ici sur Stackoverflow qui l'explique assez bien (a) mais pas quoi faire à propos de cela (b). Mon programme de référence ressemble à ce p> Le résultat n'était pas très agréable (~ 300ms sur mon ordinateur) (j'ai exécuté le test 10 fois et calculé la valeur moyenne). < / P> Ma première idée était de vérifier si elle est parce que c'est une fonction statique. J'ai donc mis en place ma propre classe p> La troisième chose que j'ai vérifiée était si je remplacerais le math.Pow (4,7) directement à 4 * 4 * 4 * 4 * 4 * 4 * 4. P> Les résultats sont (la moyenne sur 10 exécutions de tests) p> MAINTENEZ MAINTALEMENT est essentiellement comme ceci: Don Utilisez des maths pour POW. Mon seul problème est juste que ... Dois-je vraiment mettre en œuvre ma propre classe de mathématiques maintenant? Il semble en quelque sorte inefficace de mettre en œuvre une classe propre juste pour la fonction de puissance. (BTW. Powloop et Pow7 sont encore plus rapides dans la construction de libération par ~ 25% tandis que Math.Pow n'est pas). P> Donc, mes dernières questions sont P> A) Suis-je tort si Je n'utiliserais pas de maths.pow du tout (mais pour les fractions peut-être) (ce qui me rend peut-être triste). P> b) Si vous avez un code à optimiser, écrivez-vous vraiment toutes ces opérations mathématiques directement? p> c) est peut-être déjà une bibliothèque plus rapide (open-source ^^) pour les opérations mathématiques p> d) La source de ma question est fondamentalement: j'ai supposé que le .NET Le cadre lui-même fournit déjà des résultats de code / compilez très optimisé pour ces opérations de base - que ce soit les tableaux de classe de mathématiques ou de manutention et j'étais un peu surprise de la quantité de prestations que je gagnerais en écrivant mon propre code. Y a-t-il d'autres "champs généraux" ou autre chose à regarder en C # où je ne peux pas faire confiance au C # directement. P> p>
3 Réponses :
Quand vous parlez de gagner un million d'itérations d'une ligne de code, tout évidemment, tous les petits détails feront une différence. P>
math.pow () est un appel de fonction qui sera sensiblement plus lent que votre manuel 4 * 4 ... * 4 Exemple. P>
N'écrivez pas votre propre classe comme il est douteux que vous puissiez écrire quelque chose de plus optimisé que la classe de mathématiques standard. P>
Premièrement, les opérations entier sont beaucoup em> plus rapides que le point flottant. Si vous n'avez pas besoin de valeurs de points flottants, n'utilisez pas le type de données de point flottant. Cela est généralement vrai pour tout langage de programmation. P>
Deuxièmement, comme vous l'avez dit, Je ne suis pas vraiment sûr pourquoi essentiellement La question que vous devez vous poser est de savoir si cela en vaut la peine. Est math.pow code> peut gérer des réelles. Il utilise un algorithme beaucoup plus complexe qu'une boucle simple. Pas étonnant qu'il soit plus lent que tout simplement en boucle. Si vous vous débarrassez de la boucle et que vous ne faites que n multiplications, vous coupez également les frais généraux de la configuration de la boucle - rendant ainsi plus vite. Mais si vous n'utilisez pas de boucle, vous devez savoir
La valeur de l'exposant à l'avance - elle ne peut pas être fournie au moment de l'exécution. P>
math.exp code> et
math.log code> est plus rapide. Mais si vous utilisez
math.log code>, vous ne pouvez pas trouver la puissance des valeurs négatives. P>
int code> sont plus rapides et en évitant les boucles évitent les frais généraux supplémentaires. Mais vous négociez une certaine flexibilité lorsque vous allez pour ceux-ci. Mais il est généralement une bonne idée d'éviter les réels lorsque tout ce dont vous avez besoin sont des entiers, mais dans ce cas, codant une fonction personnalisée quand on existe déjà un peu trop. p>
math.pow code> ralentit réellement votre programme? Et dans tous les cas, le
math.pow code> déjà groupé avec votre langue est souvent le plus rapide ou très proche de cela. Si vous vouliez vraiment faire une mise en œuvre alternative réellement à usage général (c'est-à-dire non limitée à des entiers, des valeurs positives, etc.), vous finirez probablement d'utiliser le même algorithme utilisé dans la mise en œuvre par défaut. P>
Bien que je suis d'accord avec le sentiment général de votre réponse, je souhaite faire une remarque: bien sûr, les fonctions de la bibliothèque sont optimisées, mais il n'est pas toujours possible d'optimiser pour tous les cas. Considérez par exemple le tri, où il y a beaucoup d'options valides pour les algorithmes, et cela dépend vraiment de vos données particulières que l'on est la meilleure.
@Markijbema: C'est pourquoi j'ai utilisé le mot "but général" dans ma réponse. Si vous pouvez effectuer des hypothèses supplémentaires sur les données (par exemple, ils seront toujours des entiers, ou se situeront dans une plage donnée), bien sûr, vous pouvez créer quelque chose qui optimise l'utilisation de celle-ci (par exemple de comptage au lieu de QuicksTort). C'est tout le point de ma réponse, pour des fonctions générales, il est difficile de faire correspondre la bibliothèque.
Deux choses à garder à l'esprit: p>
vous probablement Vous n'avez pas besoin d'optimiser cette Bit de code. Vous venez de faire un million d'appels vers la fonction en moins d'une seconde. Est-ce que cela va vraiment causer de gros problèmes dans votre programme? P> LI>
La programmation numérique est plus difficile que vous ne le pensez. Même les algorithmes que vous pensez savoir calculer, ne sont pas calculés de cette façon. Par exemple, lorsque vous calculez la moyenne, vous ne devez pas simplement ajouter les chiffres et diviser le nombre de chiffres que vous avez. (Les bibliothèques de numérics modernes utilisent une routine de deux passes pour corriger les erreurs de points flottants.) P> li>
ol>
Cela dit, si vous décidez que vous avez définitivement besoin d'optimiser, envisagez d'utiliser des entiers plutôt que des valeurs de points flottantes ou de sous-traiter cela dans une autre bibliothèque numériques. P> math.pow code> est probablement assez optimal de toute façon. À une conjecture, cela appellera une bibliothèque numériques appropriée écrite dans une langue de niveau inférieure, ce qui signifie que vous ne devriez pas vous attendre à des commandes de grandeur augmente. P> Li>
Je pense que 4 * 4 * 4 * 4 * 4 * 4 * 4 * 4 4 * 4 seront évalués à l'heure de la compilation d'où la raison pour laquelle il est super rapide.
Je pense que pour la plupart des gens un 100 ms ou alors n'est pas un gros problème. C # n'est souvent pas le premier choix pour de telles applications de la plupart des gens.
Avez-vous testé avec des nombres plus importants? Je penserais que Math.Pow est optimisé pour les plus grands exposants, et fait des choses comme: x ^ 7 == x ^ {3 + 3 + 1} == {x ^ 3 + x ^ 3 x}, ce qui signifierait qu'il fonctionnera La commande est Rougly O (journal (n)), tandis que votre solution est O (n) et serait probablement beaucoup plus lent pour les grands exposants.
Les deux tests finaux (POW7 et STATICS) sont optimisables du compilateur et, en tant que tels, pas aussi génériques que celles précédents.
Il faut vraiment être une surcharge sur
math.pow code> qui prend un exposant
int code>, comme c'est la case la plus courante, et cela fonctionnerait plus vite.
Je crois que la classe mathématique est optimisée / rapide pour quelque chose - que ce soit un grand nombre ou des puissants fractuels. Mais pour les cas "non spéciaux" (calculer les maths.pow (.., 2)) ou pour des valeurs inteer faibles en production, il serait généralement de rédiger son propre code? Dans ce cas particulier, je veux calculer mon image flottante (résolution 1280 * 1024) dans l'image ^ 7 et je ferais mieux d'utiliser le document .NET. D'ailleurs. J'ai aussi ran de maths.pow (4, (int) 7) et le résultat était légèrement plus lent puis maths.pow (4,7) - probablement à cause de la conversion.
@Markijbema: aucun moyen. Math.Pow utilise des arithmétiques à point flottant, qui sera probablement une instruction unique, que le FPU sera probablement probablement (spéculation, je ne suis pas en conception matérielle) Évaluez à l'aide de l'expansion de Taylor ou de quelque chose.
@erikkallen: Vous voyez bien sûr, je pensais au pouvoir d'une matrice.