0
votes

Python produit des décimales étranges lors de la multiplication

Lorsque j'exécute ces 2 lignes, je reçois 2 résultats différents. - Pourquoi?

La variable d'élément est un type numpy.float32 p> xxx pré>

sortie: p> xxx pré>

Je soupçonne que c'est Être lié au type numpy.float32 en quelque sorte? p>

Si j'essaie de convertir le numpy.float32 en float I Obtenir ceci: p>

0.0006000000284984708


10 commentaires

Bienvenue dans le monde merveilleux des arithmétiques de points flottants. Je ne pense pas que vous ressentez un problème, c'est à quel point le point flottant fonctionne. En effet, je reçois ces résultats exacts à ma fin


y-a-t-il un moyen d'éviter ça? Cela me fait des tas de problèmes sur la route.


Quel genre de problemes? Vous pouvez essayer de lire cette réponse à ce qui semble être un problème similaire, vous pouvez aussi essayez Ceci pour contourner les problèmes


@Jottbe Vous pouvez ajuster la précision imprimée avec np.set_printoptions


J'ai essayé d'ajuster les impressions, mais cela donne la même chose.


@gspr. Cette question concerne une conversion de type réelle, donc non


Quel est le dtype de article * 1 ? Il semble que cela soit élargi à float64 , qui est étrange, mais explicable. Quelle version de numpy utilisez-vous?


@Nullman: Merci pour l'information, c'est pourquoi je n'ai pas vu les chiffres comme dans le poteau ci-dessus, mais bien sûr, l'erreur de précision est toujours présente et pourrait augmenter si la valeur est utilisée pour des calculs.


@gspr: Non, il n'est pas cassé, c'est un phénomène normal. Vous ne pouvez pas représenter des nombres arbitraires avec float . Le système tente simplement d'utiliser la représentation float qui a la plus petite division de la valeur réelle et qui n'a généralement pas de mal.


@Jottbe: Je suis bien conscient de cela. Par conséquent, je suis lié à la question canonique / réponse sur ce sujet. Le commentaire correspond à la manière dont le débordement de la pile affiche un tel avis de duplication possible.


4 Réponses :


0
votes

Je ne peux pas sembler trouver la logique dans ce cas, mais j'ai fait une solution de contournement convertir simplement le numpy.float32 en float et arrondi les chiffres à une décimale spécifique. < / p>


1 commentaires

C'est "parce que" un numéro de point flottant de 32 bits ne peut pas représenter 0,006 exactement, la valeur la plus proche est celle que vous voyez lorsque vous coerce à un flotteur 64 bits (c'est-à-dire en faisant float (article) , comme python a 64 bits flottants nativement). Beaucoup plus de détails ici: docs.python.org/3/taturial/floatingpoint.html



2
votes

Ce que vous observez malheureusement n'est pas évitable. Cela concerne la représentation interne d'un numéro de flotteur. Dans ce cas, il n'a même pas à voir avec les problèmes de calcul, comme suggéré dans des commentaires ici.

(base binaire) Les nombres de flottaisons utilisés par la plupart des langues sont représentés comme (+/- mantisse) * 2 ^ Exponent code>. La partie importante ici est la manipication, qui ne permet pas de représenter tous les chiffres exactement. La plage de valeurs de la manipication et l'exposant dépendent de la longueur de la longueur du flotteur que vous utilisez. L'exposant est responsable des chiffres représentables maximum et minimum, tandis que la Manjusse est responsable de la précision des numéros affichables (parlant de la "granularité" des chiffres). P>

Donc, pour votre question, la manipose c'est plus important. Comme dit c'est comme un tableau de bit. Dans un bit d'octet, un bit a une valeur en fonction de sa position de 1, 2, 4, ... Dans le manipse, il est similaire, mais au lieu de 1, 2, 3, 4, les bits ont la valeur 1/2, 1/4, 1/8, ... p>

Donc si vous voulez représentent 0,75, les bits avec les valeurs 1/2 et 1/4 seraient définis dans votre maniçage et que l'exposant serait 0. C'est en très court. Maintenant, si vous essayez de représenter une valeur de 0,11 dans une représentation à flotteur, vous remarquerez que cela n'est pas possible. Peu importe si vous utilisez Float32 ou Float64: P>

import numpy as np
item=np.float64('0.11')
print('{0:2.60f}'.format(item))
output: 0.110000000000000000555111512312578270211815834045410156250000

item=np.float32('0.11')
print('{0:2.60f}'.format(item))
output: 0.109999999403953552246093750000000000000000000000000000000000


3 commentaires

Notez que le module décimal est idéal pour obtenir l'expansion décimale des flotteurs, par ex. impression (décimal.decimal (0.006)) ou avec un tableau numpy arr.sType (np.dtype (décimal))


Merci pour le conseil. Je n'ai jamais utilisé cela. Mais si vous calculez avec des montants monétaires, c'est probablement une bonne alternative. Il pourrait également calculer avec la classe décimale Tge, mais il devrait ensuite utiliser décimal.decimal ('0.006') ranther que décimal.decimal (0.006) , car dans le dernier Case La valeur est transmise en tant que flotteur et les dommages sont déjà faits.


Sauf que les flotteurs python indigènes sont quelques ordres de magnitude plus rapidement que le module décimal, et NUMPY est encore plus rapide lorsque vous avez quelques milliers de valeurs à utiliser. Les formats de points flottants sont presque toujours la bonne chose à utiliser, ils peuvent simplement être un peu déroutant parfois!



2
votes

La raison pour laquelle vous voyez deux résultats différents est que votre variable élément est dans Numpy.float32, comme vous l'avez dit. Python utilise à l'interne les nombres de points flottants 64 bits, de sorte que xxx

renvoie le résultat (précision inférieur) en 32 bits, tandis que xxx

premier multiplie avec 1 , qui est un entier. Il n'est pas possible de multiplier entier avec flotteur, donc Python convertit à la fois en flotteurs - 64 bits flottants, car vous ne spécifiez rien d'autre. Le résultat est alors un flotteur 64 bits.

Si vous spécifiez un autre type de "1", xxx

renvoie le même résultat que Imprimer (article) , car il n'y a pas de conversion de type et tout peut rester en 32 bits.


0 commentaires

1
votes

Vous n'avez pas précisé exactement ce que le problème est, au-delà de "les chiffres ne correspondent pas". La manière dont vous gérez le point de flottement dépend un peu sur votre application, mais en général, vous ne pouvez pas compter sur la comparaison exactement des numéros de points flottants. Avec quelques exceptions évidentes: 0 fois que tout devrait être 0, 1 fois quelque chose devrait être 1 (il y en a plus, mais permet de les arrêter). Alors pourquoi est 1 * élément différent de élément ? XXX

Droite, cela semble contredire le bon sens. Non, c'est juste dans le mauvais sens. Faites une comparaison effective et tout va toujours bien avec le monde. xxx

Les chiffres sont les mêmes. Cela devrait avoir du sens - augmenter la précision d'un point flottant ne doit pas modifier sa valeur et multiplier par 1 ne doit pas changer de numéro.

Alors, qu'est-ce qui se passe? Numpy convertit un np.float32 à un flotteur python qui imprime avec une belle arrondie. Cependant, item * 1 est un np.float64 qui par défaut montre plus de figures siginificantes. Si vous imprimez les deux avec la même quantité de chiffres significatifs, vous pouvez voir qu'il n'y a pas de différence réelle. xxx

c'est donc ça. Quelles impressions Python ne sont pas censées être une représentation complètement précise des nombres. Les autres réponses entrent dans la raison pour laquelle 0,0006 ne peut pas être représenté exactement.

EDIT L'arrondi ne change pas ceci, il convertit simplement article sur un flotteur python qui imprime avec arrondissement. xxx


0 commentaires