web-dev-qa-db-fra.com

Fonctionnement modulo à virgule flottante

J'essaie de mettre en œuvre l'opération de réduction de plage pour la trigonométrie. Mais à la place, je pense qu'il serait préférable de simplement effectuer une opération modulo pi/2 sur les données entrantes. Je me demandais quels algorithmes existent et sont efficaces pour cette opération en virgule flottante IEEE 754 32 bits?

Je dois implémenter cela dans Assembly, donc fmod, division, multiplication, etc. ne sont pas disponibles pour moi avec une seule instruction. Mon processeur utilise des mots 16 bits et j'ai implémenté l'addition, la soustraction, la multiplication, la division, la racine carrée, le cosinus et le sinus 32 bits. J'ai juste besoin d'une réduction de plage (module) pour entrer des valeurs en cosinus et sinus.

21
Veridian

Je pense que la fmod() de la bibliothèque standard sera le meilleur choix dans la plupart des cas. Voici un lien pour une discussion de plusieurs algorithmes simples.

Sur ma machine, fmod() utilise un code d'assemblage en ligne optimisé (/usr/include/bits/mathinline.h):

#if defined __FAST_MATH__ && !__GNUC_PREREQ (3, 5)
__inline_mathcodeNP2 (fmod, __x, __y, \
  register long double __value;                           \
  __asm __volatile__                                  \
    ("1:    fprem\n\t"                            \
     "fnstsw    %%ax\n\t"                             \
     "sahf\n\t"                                   \
     "jp    1b"                               \
     : "=t" (__value) : "0" (__x), "u" (__y) : "ax", "cc");           \
  return __value)
#endif

Il utilise donc une instruction CPU dédiée (fprem) pour le calcul.

17
Michał Kosmulski

Peut-être que je manque le point ici, mais avez-vous quelque chose contre simplement utiliser fmod ?

double theta = 10.4;
const double HALF_PI = 2 * atan(1);
double result = fmod(theta, HALF_PI);
15
Prashant Kumar

L'algorithme que vous souhaitez, pour limiter une virgule flottante value entre 0 et un module n:

Double fmod(Double value, Double modulus)
{
    return value - Trunc(value/modulus)*modulus;
}

par exemple pi mod e (3.14159265358979 mod 2.718281828459045)

3.14159265358979 / 2.718281828459045 
   = 1.1557273497909217179

Trunc(1.1557273497909217179)
   = 1

1.1557273497909217179 - 1
   = 0.1557273497909217179

0.1557273497909217179 * e
   = 0.1557273497909217179 * 2.718281828459045
   = 0.42331082513074800

pi mod e = 0,42331082513074800

9
Ian Boyd