Est-ce que (int) pow (n, m) sera faux pour certains entiers positifs n, m?

En supposant que n et m sont des entiers positifs et que n m est dans la plage d’un entier, est-ce que (int)pow(n,m) donnera toujours une mauvaise réponse?

J’ai essayé beaucoup de n pour m=2 et je n’ai pas eu de mauvaises réponses jusqu’à présent.

    La norme C n’impose aucune exigence quant à la précision de l’arithmétique en virgule flottante. La précision est définie par l’implémentation, ce qui signifie que des implémentations sont nécessaires pour la documenter. Cependant, les implémentations restnt avec un “out” significatif: (§5.2.4.2.2 paragraphe 6, italiques ajoutés.)

    La précision des opérations en virgule flottante ( + , - , * , / ) et des fonctions de bibliothèque dans et des résultats en virgule flottante est définie par l’implémentation, de même que la précision de la conversion entre les représentations internes à virgule flottante et les représentations de chaîne effectuées par les fonctions de bibliothèque dans , et . L’implémentation peut indiquer que la précision est inconnue.

    Et, en effet, gcc en profite pour spécifier que la précision est inconnue . Néanmoins, la précision des calculs de la glibc est très bonne, même si elle n’est pas garantie.

    L’implémentation MS libc est connue pour générer occasionnellement une erreur de 1ULP pour la fonction pow avec des arguments entiers, ce qui entraîne une valeur incorrecte si le résultat de l’opération pow est simplement tronqué en int . (Je ne pouvais trouver aucune spécification dans la documentation de Visual Studio concernant la précision en virgule flottante, mais j’estime que la liste des questions SO ci-dessous fournit la preuve de mon affirmation.)

    Sur les architectures x86, la plupart des implémentations tentent d’implémenter IEEE 754, car la représentation native en virgule flottante est conforme. Cependant, jusqu’à la révision de 2008, IEEE-754 ne demandait que des résultats correctement arrondis de + , - , * , / et sqrt . Depuis la révision, il est recommandé qu’un certain nombre d’autres fonctions renvoient des résultats correctement arrondis, mais toutes ces recommandations sont facultatives et peu de bibliothèques de mathématiques les implémentent toutes.

    Si vous voulez vraiment utiliser pow pour calculer les puissances entières des entiers, il est conseillé (et facile) d’utiliser lround(pow(n, m)) au lieu de (long)(pow(n, m)) , qui arrondira le résultat au nombre entier le plus proche, plutôt que de se fier de manière positive à l’erreur. Cela devrait donner la valeur entière correcte pour les résultats allant jusqu’à 2 52 (avec des doublons IEEE-754) si pow est dans les limites de 1ULP. Entre 2 52 et 2 53 , une erreur 1ULP serait de 0,5, ce qui arrondira parfois au nombre entier incorrect. Au-delà de 2 53, tous les entiers ne sont pas représentables sous forme de doublons.

    SO est en fait plein de questions résultant de ce problème particulier. Voir:

    • Inverser un numéro à cinq chiffres avec fonction de prisonnier de guerre en C
    • La fonction pow () de C selon le fichier d’en-tête ne fonctionne pas correctement
    • Comportement étrange de la fonction pow
    • Pourquoi ai-je un résultat inattendu lorsque j’utilise Floor avec Pow
    • Pourquoi pow (10,5) = 9 999 en C ++
    • La valeur de retour de pow () est arrondie si elle est assignée à un entier (trouvé par Lưu Vĩnh Phúc )
    • mauvaise sortie par la fonction d’alimentation – C (également)

    et sans doute beaucoup plus.

    Certaines implémentations évaluent pow(x,y) comme exp(y*log(x)) dans tous les cas, tandis que d’autres utilisent une alimentation à multiplication carrée pour les exposants intégraux.

    Par exemple, glibc a des implémentations ‘C’, ainsi que des implémentations spécifiques à la plate-forme avec des tables de correspondance, des approximations polynomiales, etc. De nombreux dérivés Sun / BSD semblent traiter les exposants intégraux comme un cas spécial.

    Plus important encore, IEEE-754 n’en a pas besoin. Il ne spécifie pas non plus la précision requirejse du résultat. La glibc documente ses erreurs ulp maximales, bien que cette page puisse ne pas être à jour.

    En résumé, ne supposez pas un résultat d’intégrale exacte , même si pow(n,m) a une représentation en virgule flottante exacte.

    Sur les plates-formes où un int a 64 bits et un double a également 64 bits, cela peut ne pas fonctionner comme un double (les arguments et le résultat de pow() ) n’ont pas assez de mantisse pour représenter chaque entier de 64 bits avec exactitude. Sur une plate-forme ordinaire où un int a 32 bits et un double est un type à virgule flottante IEEE 754 64 bits, votre hypothèse est vraie.

    Cela dépend de la taille de vos entiers et doubles.

    Avec un entier 32 bits et un double IEEE 754 64 bits, vous obtiendrez une réponse correcte pour tous les entiers possibles.

    Un nombre à virgule flottante binary64 IEEE 754 (qui est la représentation habituelle des doubles sur la plupart des machines modernes) peut représenter exactement tous les entiers [0,2 ^ 53].