pow () semble être sorti par un ici

Que se passe t-il ici:

#include  #include  int main(void) { printf("17^12 = %lf\n", pow(17, 12)); printf("17^13 = %lf\n", pow(17, 13)); printf("17^14 = %lf\n", pow(17, 14)); } 

Je reçois cette sortie:

 17^12 = 582622237229761.000000 17^13 = 9904578032905936.000000 17^14 = 168377826559400928.000000 

13 et 14 ne correspondent pas à wolfram alpa cf:

 12: 582622237229761.000000 582622237229761 13: 9904578032905936.000000 9904578032905937 14: 168377826559400928.000000 168377826559400929 

De plus, ce n’est pas mal par une fraction étrange – c’est faux par exactement une!

Si c’est à moi d’atteindre les limites de ce que pow() peut faire pour moi, existe-t-il une alternative capable de calculer cela? J’ai besoin d’une fonction capable de calculer x^y , où x^y est toujours inférieur à ULLONG_MAX.

    pow travaille avec double nombres double . Celles-ci représentent des nombres de la forme s * 2 ^ e où s est un entier de 53 bits. Donc double peut stocker tous les entiers inférieurs à 2 ^ 53, mais seulement quelques entiers supérieurs à 2 ^ 53. En particulier, il ne peut représenter que des nombres pairs> 2 ^ 53, car pour e> 0, la valeur est toujours un multiple de 2.

    17 ^ 13 nécessite 54 bits pour représenter exactement, donc e est mis à 1 et donc la valeur calculée devient un nombre pair. La valeur correcte est étrange, donc ce n’est pas surprenant qu’elle soit désactivée. De même, 17 ^ 14 prend 58 bits à représenter. Le fait qu’elle soit également désactivée est une coïncidence heureuse (tant que vous n’appliquez pas trop de théorie des nombres), il se trouve qu’elle se trouve à un multiple de 32 , ce qui est la granularité à laquelle double nombres double de cette ampleur sont arrondis.

    Pour une exponentiation exacte des nombres entiers, vous devez utiliser des entiers tout le long. Ecrivez votre propre routine d’exponentiation sans double . Utilisez une exponentiation en mettant au carré si y peut être grand, mais je suppose qu’il est toujours inférieur à 64, ce qui rend ce problème sans object.

    Les chiffres que vous obtenez sont trop gros pour être représentés avec un double avec précision. Un nombre à virgule flottante à double précision a essentiellement 53 chiffres binarys significatifs et peut représenter tous les entiers jusqu’à 2^53 ou 9 007 199 254 740 992.

    Pour les nombres plus élevés, les derniers chiffres sont tronqués et le résultat de votre calcul est arrondi au prochain chiffre pouvant être représenté par un double . Pour 17^13 , qui est légèrement au-dessus de la limite, c’est le nombre pair le plus proche. Pour les nombres supérieurs à 2^54 c’est le nombre le plus proche qui est divisible par quatre, et ainsi de suite.

    Si vos arguments d’entrée sont des entiers non négatifs, vous pouvez implémenter votre propre pow .

    Récursivement:

     unsigned long long pow(unsigned long long x,unsigned int y) { if (y == 0) return 1; if (y == 1) return x; return pow(x,y/2)*pow(x,yy/2); } 

    Itérativement:

     unsigned long long pow(unsigned long long x,unsigned int y) { unsigned long long res = 1; while (y--) res *= x; return res; } 

    Efficacement:

     unsigned long long pow(unsigned long long x,unsigned int y) { unsigned long long res = 1; while (y > 0) { if (y & 1) res *= x; y >>= 1; x *= x; } return res; } 

    Un petit ajout à d’autres bonnes réponses: sous l’architecture x86, il existe généralement un format étendu x87 80 bits , qui est pris en charge par la plupart des compilateurs C via le type long double . Ce format permet de travailler avec des nombres entiers jusqu’à 2^64 sans lacunes.

    Il y a un analogue de pow() dans qui est destiné à fonctionner avec long double nombres long doublepowl() . Il convient également de noter que le spécificateur de format pour les valeurs long double est différent des double%Lf . Donc, le programme correct utilisant le type long double ressemble à ceci:

     #include  #include  int main(void) { printf("17^12 = %Lf\n", powl(17, 12)); printf("17^13 = %Lf\n", powl(17, 13)); printf("17^14 = %Lf\n", powl(17, 14)); } 

    Comme l’a noté Stephen Canon dans ses commentaires, rien ne garantit que ce programme donnera des résultats exacts.