math nombres Un peu de diversion en virgule flottante(im) précision, partie 1




virgule flottant ieee 754 (8)

Ce n'est pas que la plupart des implémentations à virgule flottante sont en désaccord, c'est juste qu'ils ne peuvent pas obtenir l'exactitude nécessaire pour obtenir une réponse à 100%. Et la bonne réponse est qu'ils ne peuvent pas.

PI est une série infinie de chiffres que personne n'a pu dénoter autrement que par une représentation symbolique, et e ^ X est la même, et donc la seule façon d'arriver à 100% de précision est d'aller symboliquement.

La plupart des mathématiciens conviennent que:

e πi + 1 = 0

Cependant, la plupart des implémentations à virgule flottante ne sont pas d'accord. Comment pouvons-nous régler ce différend?

Je suis désireux d'entendre parler de différentes langues et implémentations, et de diverses méthodes pour rendre le résultat aussi proche de zéro que possible. Sois créatif!


En fait, comment représente-t-on i (ou j pour les ingénieurs) dans un langage de programmation conventionnel?

Dans un langage qui n'a pas de représentation native, il est généralement ajouté en utilisant OOP pour créer une classe Complex pour représenter i et j , avec une surcharge de l'opérateur pour traiter correctement les opérations impliquant d'autres nombres Complex et / ou d'autres primitives natives du langage .

Par exemple: Complex.java , C ++ <complex>


@Ryan Fox

En fait, comment représente-t-on i (ou j pour les ingénieurs) dans un langage de programmation conventionnel?

Les types de données complexes natifs sont loin d'être inconnus. Fortran l'a eu au milieu des années soixante, et le PO expose une variété d'autres langues qui les soutiennent dans le suivi de l'hist.

Et les numéros complexes peuvent être ajoutés à d'autres langages en tant que bibliothèques (avec une surcharge de l'opérateur, ils ressemblent même à des types natifs dans le code).

Mais à moins de fournir un cas particulier pour ce problème, le "non-accord" n'est qu'une expression de l'arithmétique imprécise de la machine, non? C'est comme se plaindre

float r = 2/3;
float s = 3*r;
float t = s - 2;

se termine par (t! = 0) (Au moins si vous utilisez un compilateur assez stupide) ...


Je suis d'accord avec Ryan, il faudrait passer à un autre système de représentation numérique. La solution est en dehors du domaine des calculs en virgule flottante car vous avez besoin de pi pour représenter comme une décimale infiniment longue, donc n'importe quel schéma de précision limitée ne fonctionne pas (du moins sans utiliser un facteur de fudge pour compenser la perte précision).


Votre question me semble un peu étrange, car vous semblez suggérer que le calcul en virgule flottante est implémenté par le langage. Ce n'est généralement pas vrai, car le calcul de FP est fait en utilisant un processeur à virgule flottante dans le matériel. Mais le logiciel ou le matériel, le point flottant sera toujours inexact. C'est juste comment les flotteurs fonctionnent.

Si vous avez besoin d'une meilleure précision, vous devez utiliser une représentation numérique différente. Tout comme si vous faites des maths entiers sur des nombres qui ne tiennent pas dans un int ou long. Certains langages ont des librairies pour cela (je sais que java a BigInteger et BigDecimal), mais vous devriez utiliser explicitement ces librairies au lieu des types natifs, et les performances seraient (parfois significativement) moins bonnes que si vous utilisiez des floats.


J'ai eu des conversations de café looooong avec mon meilleur ami parlant des nombres irrationnels et de la différence entre d'autres nombres. Eh bien, nous sommes tous les deux d'accord sur ce point de vue différent:

Les nombres irrationnels sont des relations, des fonctions, d'une certaine manière, de quelle manière? Eh bien, pensez à "si vous voulez un cercle parfait, donnez-moi un pi parfait", mais les cercles sont différents des autres figures (4 côtés, 5, 6 ... 100, 200) mais ... Combien de côtés y a-t-il de plus? vous avez, plus comme un cercle, il ressemble. Si vous m'avez suivi jusqu'à présent, relier toutes ces idées ici est la formule pi:

Donc, pi est une fonction, mais une qui ne finit jamais! à cause du paramètre,, mais j'aime penser que vous pouvez avoir "instance" de pi, si vous changez le paramètre for pour un très gros Int, vous aurez une très grosse instance pi.

Même avec e, donnez-moi un paramètre énorme, je vais vous donner un e énorme.

Mettre toutes les idées ensemble:

Comme nous avons des limitations de mémoire, le langage et les libs nous fournissent une énorme instance de nombres irrationnels, dans ce cas, pi et e, comme résultat final, vous aurez une longue approche pour obtenir 0, comme les exemples fournis par @Chris Jester-Young


L'analyse numérique nous enseigne que vous ne pouvez pas compter sur la valeur précise des petites différences entre les grands nombres.

Cela n'affecte pas seulement l'équation en question ici, mais peut apporter de l'instabilité à tout, de la résolution d'un ensemble quasi-singulier d'équations simultanées, à la recherche des zéros des polynômes, à l'évaluation log (~ 1) ou exp (~ 0) ( J'ai même vu des fonctions spéciales pour évaluer log (x + 1) et (exp (x) -1) pour contourner cela).

Je vous encourage à ne pas penser à la réduction à zéro de la différence - vous ne pouvez pas - mais plutôt à faire les calculs associés de manière à assurer l'erreur minimale.

Je suis désolé, ça fait 43 ans que je n'ai pas eu ça à l'université, et même si je me souviens des références, je suis sûr qu'il y a de meilleurs trucs maintenant. Je suggère cela comme point de départ.

Si cela semble un peu condescendant, je m'en excuse. Mon "Numerical Analysis 101" faisait partie de mon cours de chimie, car il n'y avait pas beaucoup de CS à cette époque. Je n'ai pas vraiment une idée de l'importance de l'analyse numérique du lieu / de l'importance dans un cours CS moderne.


Voici une courte liste d'implémentations et de langues que j'ai essayées. Il est trié par proximité à zéro:

  • Schéma: (+ 1 (make-polar 1 (atan 0 -1)))
    • 0.0+1.2246063538223773e-16i (Chez Scheme, MIT Scheme)
    • 0.0+1.22460635382238e-16i (Guile)
    • 0.0+1.22464679914735e-16i (Poulet avec des oeufs de numbers )
    • 0.0+1.2246467991473532e-16i (MzScheme, SISC, Gauche, Gambit)
    • 0.0+1.2246467991473533e-16i (SCM)
  • Common Lisp: (1+ (exp (complex 0 pi)))
    • #C(0.0L0 -5.0165576136843360246L-20) (CLISP)
    • #C(0.0d0 1.2246063538223773d-16) (CMUCL)
    • #C(0.0d0 1.2246467991473532d-16) (SBCL)
  • Perl: use Math::Complex; Math::Complex->emake(1, pi) + 1 use Math::Complex; Math::Complex->emake(1, pi) + 1
    • 1.22464679914735e-16i
  • Python: à from cmath import exp, pi; exp(complex(0, pi)) + 1 from cmath import exp, pi; exp(complex(0, pi)) + 1
    • 1.2246467991473532e-16j (CPython)
  • Ruby: require 'complex'; Complex::polar(1, Math::PI) + 1 require 'complex'; Complex::polar(1, Math::PI) + 1
    • Complex(0.0, 1.22464679914735e-16) (IRM)
    • Complex(0.0, 1.2246467991473532e-16) (JRuby)
  • R: complex(argument = pi) + 1
    • 0+1.224606353822377e-16i






floating-point