Bonjour,
Je me demande (c'est un euphémisme) si c'est bien de nommer votre fonction round(), qui existe dans <math.h> avec certes une interface différente.
Vous devriez donner plus de précisions sur votre problème. Est-il "quelle est la routine la plus rapide en C/C++ pour calculer un arrondi à n décimales?" ou doit-on respecter le comportement de la fonction que vous proposez:
1 2 3 4 5 6
| inline double round(double dNum, double dStep)
{
double dVal = dStep * ((dStep > 0) ? (int)(dNum / dStep) : 0);
if (dNum-dVal<dStep/2) return dVal;
else return dVal + dStep;
} |
quel que soit dStep ?
Déjà, vous ne pouvez pas être plus lent en validant dStep > 0 dès l'acquisition de cette variable, avant la fonction.
Vous pouvez ensuite réécrire le machin sans tests, ce qui à priori n'est pas toujours mieux qu'un test (et même parfois loin de là) mais ici sans doute mieux qu'un test à branches déséquilibrées. Enfin, c'est à voir ...
1 2 3 4
| inline double round2(double dNum, double dStep)
{
return (dStep * (int)((dNum + (dStep / 2)) / dStep));
} |
Facilement macrotable, comme ça on est sûr de l'inlinage (inlinitude, Ségolène ?) :
#define ROUND(x, y) ((y) * (int)(((x) + ((y) / 2)) / (y)))
Maintenant, il me parait évident que si vous avez un tel souci d'optimisation, c'est que vous êtes dans une méchante boucle. Imaginons que vous ayez plusieurs niveaux de boucles, et que au dernier niveau seul dNum change, en d'autres termes que dStep change "peu souvent". Vous pouvez peut-être améliorer un peu en prémâchant le boulot à chaque changement de valeur de dStep:
1 2 3 4
| inline double round3(double dNum, double dStep, double demiStep, int invStep)
{
return (dStep * (int)((dNum + demiStep) * invStep));
} |
ou (parce que là la non inlinitude serait dramatitude):
#define ROUND(x, y, z, t) ((y) * (int)(((x) + (z)) * (t)))
A vous de tester et de voir si un int est suffisant et si la multiplication par un entier est mieux que la division par un double.
Enfin, il est possible que ne puissiez avoir qu'un nombre fini et raisonnable de valeurs de dStep, correspondant bien entendu à un nombre de décimales. Vous pourriez alors multipliquer la boucle en-dessous de l'acquisition de dStep et aiguiller selon la valeur de dStep. Vous ne pouvez pas vous contenter de multipliquer la fonction round() puiqu'en utilisant un tel tableau de fonctions, vous ne pourriez plus inliner. Vous auriez donc des fonctions du type:
1 2 3 4
| inline double round3(double dNum)
{
return (0.001 * (int)((dNum + 0.0005) * 1000));
} |
ou
#define ROUND3(x) (0.001 * (int)(((x) + 0.0005) * 1000))
Vous pouvez panacher, en ne codant en constantes que les cas les plus fréquent et en conservant une branche paramétrée, bref en utilisant ce que vous savez de vos données et que le compilateur ne peut savoir d'avance.
Partager