Le plus rapide double-to-int du monde :-)
Si tu dois vraiment faire du cast de double vers int en grande quantite, je te recommande cette petite merveille:
(Pour ceux qui voient vraiment pas comment ca peut marcher, au point de croire que ca marche pas, je ne saurais trop recommander de faire un essai)
Code:
1 2 3 4 5 6 7 8 9 10 11
|
#define D2I_CONVERSION_FACTOR (1.5 * 4503599627370496.0)
inline int d2i(double val)
{
union {
int i[2];
double d;
} dlong;
dlong.d = val + D2I_CONVERSION_FACTOR;
return dlong.i[0];
} |
C'est plus rapide qu'un cast standard par un facteur de 8, et meme plus rapide qu'un cast en assembleur du genre:
Code:
1 2 3 4 5 6 7
|
double d;
int val;
__asm {
fld qword ptr[d]
fistp dword ptr[val]
} |
J'ai verifie moi-meme.
les limitations du truc:
-Tres difficile a comprendre (je peux filer une explication si tu cale et que ca t'interesse).
-Les ints doivent etre en 32 bits
-Les doubles doivent etre en representation standard (1/11/52)
-Marche tel quel uniquement sur une machine big-endian
-Pas du tout du tout de verification ou de traitement d'erreurs.
Les trois premieres peuvent etre contournees, la derniere non :-)
Il est possible de faire la fonction inverse ;-)
J'essaye de ratrapper mon retard
Citation:
Pour forcer le second bit à 1, car le premier est implicite ?
C'est en fait pour être certain de rester avec la mantisse alignée sur le bit 0 quand on a des doubles négatifs.
Citation:
- Aucune garantie que ça fasse quoi que ce soit. Ecrire dans un membre d'une union et lire dans un autre est un comportement indéfini. Il se peut que ça marche sur une certaine machine, avec une certaine version d'un compilateur, avec certaines options de compilation, pendant certaines phases de la lune, mais rien n'est moins sur.
Tu as raison. On peut un peu réduire ce problème en utilisant le réinterpret_cast suggèré par Médinoc, mais de toute façon, le truc entier dépend d'un tas de conditions similaires: c'est un hack!
Citation:
Déjà, le résultat n'est pas le même qu'un simple cast en int. Un cast tronque, ta méthode fait autre chose
Tu as raison, je me suis mal exprimé: c'est pour faire une conversion double vers int en arrondi, c'est en général ce dont tu as besoin pour faire du calcul. L'arrondi est exact.
Citation:
Sans ce test (en se limitant à des nombres positifs), elle est plus rapide de 10% à 20%.
C'est le rapport que j'avais mesuré entre la version d2i et la version assembleur. Ce gain (que je trouve étonnant, personellement) semble être réellement une différence basique entre le add et le fistp.
Citation:
Les variations dépendent de si je fais beaucoup d'itérations sur des petits jeus de données, ou moins d'itération sur des plus grand (moins bonne utilisation de la mémoire, qui vient masquer les différences, ce qui tend à dire que dans une utilisation classique, la différence sera probablment elle aussi masquée par d'autres aspects)
Bien entendu. N'importe quelle tentative d'optimisation de cette conversion souffrira de ce genre de problème. Comprends moi, je ne dis pas qu'il faut optimiser du code de cette manière, je file juste un hack qui peut aider dans certains cas particuliers. Ça m'a personnelement servi dans un cas particulier. Je n'en ai pas fait une recommendation auprès de Boost :-)
Citation:
On est quoi qu'il en soit loin du *8 sur cette architecture.
Dans la mesure que j'avais faite qui donnait ce résultat, l'assembleur géneré par VC8 appelait une fonction (de la runtime lib, je crois) au lieu d'inliner l'operation, d'où le rapport plus élevé. Je ne me suis pas vraiment attardé sur le pourquoi du comment. Je vais voir si je peux retrouver mon code de test qui est peut-être érroné.
Citation:
- MAIS en utilisant l'assembleur (celui que tu as donné), le rapport de vitesse s'inverse !
Il n'y a pas de secret. L'assembleur doit être différent (celui géneré pour d2i). Il faudrait comparer le code généré dans ton cas avec le mien.
Citation:
Après tout, c'est un astuce pour gagner en vitesse, pourquoi faire une multiplication dans le calcul, alors qu'on peut la faire en avance ?
Tous les compilateurs réduisent ce genre d'expression au moment de la compilation (optimisée). C'était juste un indice pour le lecteur qui voulait comprendre ce qui se passe au niveau de la représentation du double.
Bon je vais m'arrêter là. Juste une petite remarque. À la base, j'essayais juste de filer un coup de main. Je pensais pas me faire assaillir de la sorte :aie: