web-dev-qa-db-fra.com

Un moyen facile de trouver des décimales

Existe-t-il un moyen simple ou une fonction intégrée pour trouver les décimales d'un nombre à virgule flottante?

Le nombre est analysé à partir d'une chaîne, donc une façon consiste à compter les chiffres après le '.' signe, mais cela me semble assez maladroit. Existe-t-il une possibilité d'extraire les informations nécessaires d'un objet float ou Decimal?

SOLUTION (l'un d'eux, bien sûr :))

J'ai choisi d'utiliser la classe python decimal.Decimal pour m'aider avec mon problème:

e = abs(Decimal(string_value).as_Tuple().exponent)

REMARQUE: cela ne fonctionne que lorsque le paramètre à partir duquel la décimale est construite est une chaîne et non un flottant (ce qui entraînerait des inexactitudes en virgule flottante).

Merci beaucoup pour toutes les autres contributions.

42
Constantinius

Pour répéter ce que les autres ont dit (parce que je l'avais déjà tapé!), Je ne suis même pas sûr qu'une telle valeur serait significative dans le cas d'un nombre à virgule flottante, en raison de la différence entre la représentation décimale et binaire; souvent un nombre représentable par un nombre fini de chiffres décimaux n'aura qu'une représentation infinie en binaire.

Dans le cas d'un decimal.Decimal, vous pouvez récupérer l'exposant en utilisant le as_Tuple, qui retourne un tuple nommé avec les attributs sign, digits et exponent:

>>> d = decimal.Decimal('56.4325')
>>> d.as_Tuple().exponent
-4
>>> d = decimal.Decimal('56.43256436')
>>> d.as_Tuple().exponent
-8

La négation de l'exposant est le nombre de chiffres après le point décimal, sauf si l'exposant est supérieur à 0.

47
senderle

Une manière naïve (vulnérable à une utilisation localisée mentionnée par @jglouie) est

len(foo.split('.')[1])

où foo est une chaîne comme "23.512999238".

ÉDITER

Comme @Thomas Jung et @Mark Ransom l'ont mentionné, c'est plutôt naïf pour certains cas d'angle, qui doivent être traités comme ...

import re
from locale import localeconv
dec_pt = localeconv()['decimal_point']
decrgx = re.compile("\d+(%s\d+)?e(-|\+)(\d+)" % dec_pt)
if decrgx.search(foo):
    # still figuring this out
    raise NotImplementedError, "e notation not implemented"
else:
    digits = len(foo.split(dec_pt)[-1])
12
Mike Pennington

"le nombre de décimales" n'est pas une propriété d'un nombre à virgule flottante, en raison de la façon dont elles sont stockées et gérées en interne.

Vous pouvez obtenir autant de décimales que vous le souhaitez à partir d'un nombre à virgule flottante. La question est de savoir quelle précision vous voulez. Lors de la conversion d'un nombre à virgule flottante en chaîne, une partie du processus décide de la précision.

Essayez par exemple:

1.1 - int(1.1)

Et vous verrez que la réponse est:

0.10000000000000009

Donc, dans ce cas, le nombre de décimales est 17. Ce n'est probablement pas le nombre que vous recherchez.

Vous pouvez cependant arrondir le nombre à un certain nombre de décimales avec "arrondir":

round(3.1415 - int(3.1415), 3)

Dans ce cas, le nombre de décimales est réduit à 3.

Vous ne pouvez pas obtenir "le nombre de décimales d'un flotteur", mais vous pouvez décider de la précision et du nombre que vous souhaitez.

La conversion d'un flottant en chaîne est une façon de prendre une telle décision.

10
Alexander

La bibliothèque décimale sert à travailler avec des nombres décimaux, comme dans la comptabilité. Il n'a pas de fonction intrinsèque pour renvoyer le nombre de décimales. C'est particulièrement un problème lorsque vous réalisez que le contexte sous lequel il s'exécute le définit selon ce que l'utilisateur souhaite.

Si vous obtenez une chaîne, vous pouvez la convertir en décimale, mais cela ajoutera des zéros pour vous rendre à votre précision ou utilisera le paramètre d'arrondi pour la tronquer.

Votre meilleur pari serait probablement de diviser le point dans votre chaîne et de compter le nombre de caractères dans la sous-chaîne résultante.

4
Spencer Rathbun

Si vous savez que vous n'aurez pas de problèmes d'analyse (ou si vous laissez python lui-même ou une autre bibliothèque gérer cela pour vous, espérons-le, gérer les problèmes de localisation) ... il suffit de l'analyser et utilisez modf . La valeur de retour est une paire de valeurs, dont l'une est la partie intégrale, l'autre est la partie fractionnaire.

1
jkerian

J'avais besoin de quelque chose comme ça et j'ai testé certains d'entre eux, le plus rapide que j'ai découvert était:

str(number)[::-1].find('.')

En raison du problème de virgule flottante, tous les modules modulo m'ont donné de faux résultats même avec Decimal (nombre) (notez que j'en avais besoin dans un script pour fixer les prix d'une base de données entière)

len(str(Decimal(str(number))) % Decimal(1))) - 2

La nécessité de mettre une chaîne en décimal est assez mal à l'aise lorsque nous avons des flottants ou quelque chose comme ça.

Voici mon "banc": https://repl.it/FM8m/17

1
Jérémy JOKE

Le moyen le plus rapide que j'ai trouvé pour les chiffres de calc après la virgule décimale et en arrondissant le nombre est

Calculer les chiffres:

a=decimal.Decimal('56.9554362669143476');
lenstr = len(str(a).split(".")[1])

Calc, chèque et arrondi:

a=decimal.Decimal('56.9554362669143476');
a = round(float(a),5) if len(str(a).split(".")[1]) > 5 else float(a)

Comparaison:

$ python2 -mtimeit 'import decimal; a=decimal.Decimal('56.9554362669143476'); round(float(a),5) if a.as_Tuple().exponent < -5 else float(a)'
10000 loops, best of 3: 32.4 usec per loop
$ python -mtimeit 'import decimal; a=decimal.Decimal('56.9554362669143476'); a = round(float(a),5) if len(str(a).split(".")[1]) > 5 else float(a)'
100000 loops, best of 3: 16.7 usec per loop
1
George

Étant donné que Python les nombres à virgule flottante sont représentés en interne sous forme binaire plutôt que décimale, il n'y a vraiment pas de raccourci autre que la conversion en décimal. La seule façon intégrée de le faire est de convertir en chaîne. Vous pourrait écrire votre propre code pour effectuer une conversion décimale et compter les chiffres, mais ce serait une duplication d'efforts.

1
Mark Ransom