9
votes

Pourquoi C # ne peut-il pas calculer les valeurs exactes des fonctions mathématiques

Pourquoi ne peut-il pas # faire des opérations exactes.

Math.Pow(Math.Sqrt(2.0),2) == 2.0000000000000004


4 commentaires

Évidemment, vous ne l'avez pas saisis. Votre calculatrice n'utilise probablement pas un double pour stocker un numéro ... Regardez le type décimal .


@Bobby: Decimal le trouverait aussi difficile de représenter des nombres irrationnels que le double fait ...


Un résultat dans une précision de 10 ^ -15 est un résultat assez exact lors de la gestion des doubles.


Vous devriez obtenir un résultat exact si vous utilisez une précision unique au lieu de double précision sur cet exemple, c'est peut-être ce que votre calculatrice fait


8 Réponses :


2
votes

Votre calculatrice ne le calculait pas exactement, il suffit que l'erreur d'arrondi est si petite que ce n'est pas affiché.


0 commentaires

8
votes

chances sont votre calculatrice ne peut pas le faire exactement - mais il stocke probablement plus d'informations que l'affichage, de sorte que l'erreur après la mise en place se termine à l'extérieur des limites de ce qui est affiché. Soit cela, ou ses erreurs arrivent à annuler dans ce cas - mais ce n'est pas la même chose que de l'obtenir exactement de manière délibérée.

Une autre option est que la calculatrice se souvient des opérations qui ont abouti aux résultats précédents et en appliquant l'algèbre pour annuler les opérations ... Cela semble plutôt improbable. .NET Certainement ne va pas essayer de le faire - il calculera la valeur intermédiaire (la racine de deux) puis la cassera.

Si vous pensez vous peut faire mieux, je vous suggère d'essayer d'écrire la racine carrée de deux à (dire) 50 décimales, puis de la place exactement. Voir si vous sortez avec exactement 2 ...


16 commentaires

Ok, bien ma question n'est pas vraiment sur ma calculatrice, c'est à propos de C #. SQRT (2) ^ 2 a une valeur exacte, il doit y avoir des moyens d'obtenir une valeur exacte de celle-ci.


@Timo: Oui - stockez les opérations algébriques au lieu de calculer les valeurs intermédiaires. C'est ce que les outils comme Mathematica font ... Mais ce n'est pas la façon dont les langues ordinaires travaillent aussi loin que je suis au courant.


@Timo seulement si (comme Jon déjà signalé) l'ordinateur connaît une algèbre, ou en particulier une fonction math.pow () qui prend une autre fonction comme argument et évalue que ...


Je trouve que très étrange, parce que bien ... un ordinateur est basé sur des mathématiques, mais elle ne peut pas résoudre exactement des fonctions mathématiques simples.


@Timo oui ça peut! C'est ce que Mathematica est pour après tout. Et au fait: un ordinateur est basé sur le calcul des nombres distincts 0 et 1.


@Imo: Veuillez lire: en.wikipedia.org/wiki/floitant_point#accuracy_problèmes


Martin, je sais sur des points flottants d'inexactitude, mais ce que je trouve étrange, c'est que, pourquoi voudriez-vous l'inexactitude lorsque d'autres langages de programmation (Mathematica) Cán le calculent exactement.


@Timo "Pourquoi voudriez-vous l'inexactitude lorsque d'autres langages de programmation (Mathematica) Cán Calculez-le exactement» - Je pense que vous devriez reformuler votre question comme celle-ci, ou demandez-la comme une nouvelle question car il y a une tonne d'autres réponses à cette question . (Comme, performance!)


D'accord, je vais faire une nouvelle question, car sinon, les réponses à celui-ci n'ont plus de sens.


Parce que l'arithmétique de points flottants est rapide et simple et pour la plupart des applications, c'est assez bon. Oui, Mathematica peut le faire et oui, il est rapide. Mais cela vient avec le prix de la complexité accrue. Et puisque chaque programmeur sait (ou devrait savoir) ce n'est pas un problème: si ce type de précision est nécessaire, des outils peuvent le faire.


@Timo: Un ordinateur est basé sur arithmétique plutôt que algèbre . Les ordinateurs sont très bons pour effectuer des opérations arithmétiques spécifiques très rapidement, mais ce n'est pas la même chose que si vous faites une racine carrée, vous revenez à la valeur d'origine. Vous pourriez y penser aussi semblable à la différence entre pouvoir écrire sur papier très rapidement vs capable de composer un beau poème. Deux personnes peuvent tous deux être bonnes à "écrire" de différentes manières.


BTW, MANTISSA d'une précision unique 2.0000000000000004 est 10, même que pour 2.0, donc dans ce cas, C # Calcul est exact, c'est vraiment un problème d'affichage


@Yaroslav: Mais il n'utilise pas une précision unique, il utilise une double précision. Il n'y a pas de float valeurs impliqués, uniquement double .


Je n'ai vérifié que la précision unique, mais je suppose que c'est aussi exact pour la double précision. La question ici est la manière dont binaire 10. doit être imprimé en décimal


@Yaroslav: Non, ce n'est pas le cas. Évidemment 2.0000000000000004 est identique à 2 dans une précision unique, car la précision unique n'a que 7 chiffres de précision - tandis que le double a 15 ou 16. En bref, c'est pas un problème d'affichage.


Ok, je pense que vous avez raison, le dernier peu de signification de 2.000 ... 4 est 1



0
votes

Qu'est-ce qui vous fait penser que votre calculatrice peut le faire? Il affiche presque certainement moins de chiffres qu'il ne calcule avec et vous obtiendriez le résultat "correct" si vous imprimez votre 2.0000000000000004 avec seulement cinq chiffres fractionnaires (par exemple).

Je pense que vous constaterez probablement que cela ne peut pas. Lorsque je fais la racine carrée de 2 puis multipliez cela en soi, je reçois 1.999999998 . .

La racine carrée de 2 est l'un de ces nombres irrationnels ennuyeux tels que PI et ne peut donc pas être représenté avec des types normaux IEEE754 doubles ou même des types décimaux. Pour la représenter exactement, vous avez besoin d'un système capable de mathématiques symboliques où la valeur est stockée comme "la racine carrée de deux" afin que les calculs suivants puissent obtenir des résultats corrects.


0 commentaires

1
votes

Je pense que la plupart des calculatrices utilisent des décimales codées binaires, ce qui correspond à l'équivalent du type décimal de C # (et est donc entièrement précis). C'est-à-dire que chaque octet contient deux chiffres du nombre et les mathématiques sont effectués via des logarithmes.


2 commentaires

... Calculatrices (pas calendriers) ... Logarithmes (pas Logarythms) ... Dans tous les cas, BCD ne vous aidera pas avec les irrationnelles :-)


Merci pour les corrections. Un peu dure évanouissement pour les fautes de frappe lorsque d'autres réponses ici sont un peu erronées.



0
votes

La manière dont les calculateurs de calcul des calculateurs varient du modèle au modèle. Mon TI Voyage 200 fait l'algèbre pour simplifier les équations (entre autres choses ) Mais la plupart des calculatrices n'ayant afficheront qu'une partie de la valeur réelle calculée, après avoir appliqué une fonction ronde sur le résultat. Par exemple, vous pouvez trouver la racine carrée de 2 et la calculatrice stockerait (disons) 54 décimales, mais affichera seulement 12 décimales arrondies. Ainsi, lorsque vous faites une racine carrée de 2, faites une puissance de ce résultat de 2 renvoyerait la même valeur car le résultat est arrondi. Dans tous les cas, à moins que la calculatrice ne puisse conserver un nombre infini de décimales, vous aurez toujours le meilleur résultat approximatif des opérations complexes.

Au fait, essayez de représenter 10.0 en binaire et vous vous rendrez compte que vous ne pouvez pas la représenter uniformément et vous finirez par (quelque chose comme) 10.00000000000 .. 01


0 commentaires

-1
votes

2.000000000000000004 et 2. sont représentés comme 10. en une précision unique. Dans votre cas, en utilisant une précision unique pour C # devrait donner la réponse exacte

pour votre autre exemple, Wolfram Alpha peut utiliser une précision supérieure à la précision de la machine pour le calcul. Cela ajoute une grande pénalité de performance. Par exemple, dans Mathematica, une précision plus élevée permet de calculer environ 300 fois plus lent xxx

Il est 0,01 seconde vs 3 secondes sur ma machine

vous pouvez voir la différence de résultats utilisant une précision unique et une double précision introduite en faisant quelque chose comme ce qui suit dans Java xxx

Vous pouvez voir que le résultat de la précision unique est exact, tandis que la double précision est désactivée par un bit


2 commentaires

2.000000000000000004 est pas représenté comme le même numéro que 2 dans la double précision. Utilisez bitconverter.doubletoint64bits et vous verrez qu'il existe différentes valeurs. N'utilisez pas une plate-forme pour trouver la représentation dans un autre ...


Mais la question était fondamentalement à propos de C # "le faire faux" - et vous n'avez pas vérifié la représentation dans .NET, ce qui est important ici. Vous venez de supposer - de manière incorrecte - cette précision unique était pertinente ici, et ailleurs, vous avez supposé que la représentation à double précision serait la même. .NET N'est-ce pas donnant la réponse exacte, alors c'est n'est pas un problème d'affichage.



0
votes

Votre calculatrice contient des méthodes qui reconnaissent et manipulent des valeurs d'entrée irrationnelles.

Par exemple: 2 ^ (1/2) n'est probablement pas évalué à un nombre dans la calculatrice si vous ne le direz pas explicitement de le faire (comme dans le TI89 / 92).

En outre, la calculatrice a la logique qu'il peut utiliser pour les manipuler tel que x ^ (1/2) * y ^ (1/2) = (x * y) ^ 1/2 où il peut ensuite se laver, rincer, Répétez la méthode pour travailler avec des valeurs irrationnelles.

Si vous deviez donner à C # une méthode pour faire cela, je suppose que cela pourrait aussi bien. Après tout, des solvains algébriques tels que Mathematica ne sont pas magiques.


0 commentaires

0
votes

Il a été mentionné précédemment, mais je pense que ce que vous recherchez est un système d'algèbre informatique. Des exemples de ceux-ci sont Maxima et Mathematica, et ils sont conçus uniquement pour fournir des valeurs exactes aux calculs mathématiques, quelque chose qui n'est pas couvert par la CPU.

Les routines mathématiques dans des langues comme c # sont conçues pour des calculs numériques: on s'attend à ce que, si vous effectuez des calculs en tant que programme, vous l'aurez déjà simplifié, ou vous n'aurez besoin que d'un résultat numérique.


0 commentaires