J'ai besoin d'arrondir un flotteur pour être affiché dans une interface utilisateur. Par exemple, à un chiffre significatif:
1234 -> 1000
0,12 -> 0,1
0,012 -> 0,01
0,062 -> 0,06
6253 -> 6000
1999 -> 2000
Existe-t-il une bonne façon de faire cela en utilisant la bibliothèque Python, ou dois-je l'écrire moi-même?
Réponses:
Vous pouvez utiliser des nombres négatifs pour arrondir les entiers:
Ainsi, si vous n'avez besoin que du chiffre le plus significatif:
Vous devrez probablement prendre soin de transformer float en entier s'il est supérieur à 1.
la source
log10
est le seul moyen approprié de déterminer comment l'arrondir.log10(abs(x))
, sinon les nombres négatifs échoueront (et traiterx == 0
séparément bien sûr)round_to_n = lambda x, n: x if x == 0 else round(x, -int(math.floor(math.log10(abs(x)))) + (n - 1))
protège contrex==0
etx<0
Merci @RoyHyunjinHan et @TobiasKienzler. Ne protège pas contre les non définis comme math.inf, ou les déchets comme None, etc.% g dans le formatage de chaîne formatera un flottant arrondi à un certain nombre de chiffres significatifs. Il utilisera parfois la notation scientifique «e», donc reconvertissez la chaîne arrondie en virgule flottante puis via le formatage de chaîne% s.
la source
0.075
à0.08
. Il revient à la0.07
place.round_sig = lambda f,p: float(('%.' + str(p) + 'e') % f)
vous permet d'ajuster le nombre de chiffres significatifs!Si vous voulez avoir autre chose qu'une décimale significative (sinon la même chose que Evgeny):
la source
0.075
de0.08
. Il revient à la0.07
place.round
. docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issuesCette solution est différente de toutes les autres car:
Pour un nombre arbitraire
n
de chiffres significatifs, vous pouvez utiliser:Tester:
Remarque : avec cette solution, il n'est pas possible d'adapter dynamiquement le nombre de chiffres significatifs à partir de l'entrée car il n'y a pas de méthode standard pour distinguer les nombres avec différents nombres de zéros de fin (
3.14 == 3.1400
). Si vous devez le faire, des fonctions non standard comme celles fournies dans le package to-precision sont nécessaires.la source
:g
formateur qui préserve les entiers.2000.0
suggère 5 chiffres significatifs, il faut donc{:g}
recommencer.) En général, les entiers avec des zéros à la fin sont ambigus en ce qui concerne les chiffres significatifs, à moins qu'une technique (comme le surlignage au-dessus du dernier significatif) ne soit utilisée.J'ai créé le package avec précision qui fait ce que vous voulez. Il vous permet de donner vos chiffres des chiffres plus ou moins significatifs.
Il produit également des notations standard, scientifiques et techniques avec un nombre spécifié de chiffres significatifs.
Dans la réponse acceptée, il y a la ligne
Cela spécifie en fait 8 sig figs. Pour le numéro 1234243, ma bibliothèque n'affiche qu'un seul chiffre significatif:
Il arrondira également le dernier chiffre significatif et pourra automatiquement choisir la notation à utiliser si aucune notation n'est spécifiée:
la source
lambda x: to_precision(x, 2)
Pour arrondir un entier à 1 chiffre significatif, l'idée de base est de le convertir en virgule flottante avec 1 chiffre avant le point et de l'arrondir, puis de le reconvertir à sa taille entière d'origine.
Pour ce faire, nous devons connaître la plus grande puissance de 10 inférieure à l'entier. Nous pouvons utiliser le plancher de la fonction log 10 pour cela.
la source
Pour répondre directement à la question, voici ma version utilisant la dénomination de la fonction R :
Ma principale raison pour publier cette réponse sont les commentaires se plaignant que "0,075" arrondit à 0,07 plutôt que 0,08. Ceci est dû, comme l'a souligné "Novice C", à une combinaison d'arithmétique en virgule flottante ayant à la fois une précision finie et une représentation en base 2 . Le nombre le plus proche de 0,075 qui peut réellement être représenté est légèrement plus petit, donc l'arrondi est différent de ce à quoi vous pourriez vous attendre naïvement.
Notez également que cela s'applique à toute utilisation d'arithmétique à virgule flottante non décimale, par exemple C et Java ont tous deux le même problème.
Pour montrer plus en détail, nous demandons à Python de formater le nombre au format «hexadécimal»:
ce qui nous donne:
0x1.3333333333333p-4
. La raison en est que la représentation décimale normale implique souvent des arrondis et que ce n'est donc pas ainsi que l'ordinateur "voit" le nombre. Si vous n'êtes pas habitué à ce format, quelques références utiles sont les documents Python et le standard C .Pour montrer comment ces chiffres fonctionnent un peu, nous pouvons revenir à notre point de départ en faisant:
qui devrait s'imprimer
0.075
.16**13
est parce qu'il y a 13 chiffres hexadécimaux après la virgule décimale, et2**-4
est parce que les exposants hexadécimaux sont en base-2.Maintenant, nous avons une idée de la façon dont les flottants sont représentés, nous pouvons utiliser le
decimal
module pour nous donner plus de précision, nous montrant ce qui se passe:donner:
0.07499999999999999722444243844
et, espérons-le, expliquer pourquoiround(0.075, 2)
évalue0.07
la source
0.074999999999999999
, que voulez - vous attendre à obtenir dans ce cas?J'espère prendre le meilleur de toutes les réponses ci-dessus (moins pouvoir le mettre comme un lambda d'une ligne;)). Vous n'avez pas encore exploré, n'hésitez pas à modifier cette réponse:
la source
J'ai modifié la solution d'indgar pour gérer les nombres négatifs et les petits nombres (y compris zéro).
la source
x == 0
? Si vous aimez un one-liner, justereturn 0 if x==0 else round(...)
.0.970 == 0.97
). Je pense que vous pouvez utiliser certaines des autres solutions d'impression commef'{round_sig(0.9701, sig=3):0.3f}'
si vous voulez que le zéro soit imprimé.Si vous voulez arrondir sans impliquer de chaînes, le lien que j'ai trouvé enfoui dans les commentaires ci-dessus:
http://code.activestate.com/lists/python-tutor/70739/
me semble le meilleur. Ensuite, lorsque vous imprimez avec des descripteurs de mise en forme de chaîne, vous obtenez une sortie raisonnable et vous pouvez utiliser la représentation numérique à d'autres fins de calcul.
Le code du lien est composé de trois lignes: def, doc et return. Il a un bug: vous devez vérifier les logarithmes explosifs. C'est facile. Comparez l'entrée à
sys.float_info.min
. La solution complète est:Cela fonctionne pour n'importe quelle valeur numérique scalaire, et n peut être un
float
si vous avez besoin de décaler la réponse pour une raison quelconque. Vous pouvez en fait repousser la limite à:sans provoquer d'erreur, si pour une raison quelconque vous travaillez avec des valeurs minuscules.
la source
Je n'arrive pas à penser à quoi que ce soit qui puisse gérer cela hors de la boîte. Mais c'est assez bien géré pour les nombres à virgule flottante.
Les nombres entiers sont plus compliqués. Ils ne sont pas stockés en base 10 en mémoire, donc les endroits importants ne sont pas une chose naturelle à faire. C'est assez simple à implémenter une fois qu'il s'agit d'une chaîne.
Ou pour les entiers:
Si vous souhaitez créer une fonction qui gère n'importe quel nombre, ma préférence serait de les convertir en chaînes et de rechercher une décimale pour décider quoi faire:
Une autre option consiste à vérifier le type. Ce sera beaucoup moins flexible et ne jouera probablement pas bien avec d'autres nombres tels que des
Decimal
objets:la source
La réponse affichée était la meilleure disponible lorsqu'elle a été donnée, mais elle présente un certain nombre de limites et ne produit pas de chiffres significatifs techniquement corrects.
numpy.format_float_positional prend directement en charge le comportement souhaité. Le fragment suivant renvoie le flottant
x
formaté à 4 chiffres significatifs, la notation scientifique étant supprimée.la source
print(*[''.join([np.format_float_positional(.01*a*n,precision=2,unique=False,fractional=False,trim='k',pad_right=5) for a in [.99, .999, 1.001]]) for n in [8,9,10,11,12,19,20,21]],sep='\n')
. Je n'ai pas vérifié Dragon4 lui-même.J'ai rencontré cela aussi, mais j'avais besoin de contrôler le type d'arrondi. Ainsi, j'ai écrit une fonction rapide (voir code ci-dessous) qui peut prendre en compte la valeur, le type d'arrondi et les chiffres significatifs souhaités.
la source
Utilisation du formatage nouveau style python 2.6+ (car% -style est obsolète):
Dans python 2.7+, vous pouvez omettre les premiers
0
s.la source
Cette fonction effectue un arrondi normal si le nombre est supérieur à 10 ** (- decimal_positions), sinon ajoute plus de décimales jusqu'à ce que le nombre de positions décimales significatives soit atteint:
J'espère que ça aide.
la source
https://stackoverflow.com/users/1391441/gabriel , est-ce que ce qui suit répond à votre préoccupation concernant rnd (.075, 1)? Avertissement: renvoie la valeur sous forme de flottant
la source
Cela renvoie une chaîne, de sorte que les résultats sans parties fractionnaires et les petites valeurs qui apparaîtront autrement en notation E s'affichent correctement:
la source
Étant donné une question si bien répondue, pourquoi ne pas en ajouter une autre
Cela convient un peu mieux à mon esthétique, bien que beaucoup de ceux ci-dessus soient comparables
Cela fonctionne pour les nombres individuels et les tableaux numpy, et devrait fonctionner correctement pour les nombres négatifs.
Il y a une étape supplémentaire que nous pourrions ajouter - np.round () renvoie un nombre décimal même si arrondi est un entier (c'est-à-dire que pour significantFigures = 2, nous pourrions nous attendre à récupérer -460 mais à la place nous obtenons -460.0). Nous pouvons ajouter cette étape pour corriger cela:
Malheureusement, cette dernière étape ne fonctionnera pas pour un tableau de nombres - je vous laisse cela à vous, cher lecteur, de déterminer si vous en avez besoin.
la source
Le package / bibliothèque sigfig couvre cela. Après l' installation, vous pouvez effectuer les opérations suivantes:
la source
la source