Question

La documentation pour le rond() La fonction indique que vous lui transmettez un nombre et que les positions après la décimale sont arrondies.Ainsi il devrait fais ceci:

n = 5.59
round(n, 1) # 5.6

Mais, en réalité, la bonne vieille bizarrerie de la virgule flottante s’installe et vous obtenez :

5.5999999999999996

Aux fins de l'interface utilisateur, je dois afficher 5.6.J'ai fouillé sur Internet et j'en ai trouvé Documentation que cela dépend de mon implémentation de Python.Malheureusement, cela se produit à la fois sur ma machine de développement Windows et sur chaque serveur Linux que j'ai essayé. Voir ici aussi.

À moins de créer ma propre bibliothèque ronde, existe-t-il un moyen de contourner ce problème ?

Était-ce utile?

La solution

Je n'y peux rien sur la façon dont il est stocké, mais au moins le formatage fonctionne correctement :

'%.1f' % round(n, 1) # Gives you '5.6'

Autres conseils

Le formatage fonctionne correctement même sans avoir à arrondir :

"%.1f" % n

Si vous utilisez le module Decimal, vous pouvez approximer sans utiliser la fonction « arrondi ».Voici ce que j'utilise pour arrondir, en particulier lors de l'écriture d'applications monétaires :

Decimal(str(16.2)).quantize(Decimal('.01'), rounding=ROUND_UP)

Cela renverra un nombre décimal qui est 16,20.

round(5.59, 1) fonctionne bien.Le problème est que 5.6 ne peut pas être représenté exactement en virgule flottante binaire.

>>> 5.6
5.5999999999999996
>>> 

Comme le dit Vinko, vous pouvez utiliser le formatage de chaîne pour arrondir l'affichage.

Python a un module pour l'arithmétique décimale si tu en as besoin.

Vous obtenez « 5,6 » si vous le faites str(round(n, 1)) au lieu de juste round(n, 1).

Vous pouvez changer le type de données en entier :

>>> n = 5.59
>>> int(n * 10) / 10.0
5.5
>>> int(n * 10 + 0.5)
56

Et puis affichez le nombre en insérant le séparateur décimal des paramètres régionaux.

Cependant, La réponse de Jimmy est mieux.

Les mathématiques à virgule flottante sont vulnérables à des inexactitudes légères, mais ennuyeuses.Si vous savez travailler avec des nombres entiers ou des virgules fixes, vous aurez la garantie d'une précision.

Jetez un oeil à Module décimal

Decimal «est basé sur un modèle à virgule flottante qui a été conçu avec les gens à l'esprit, et a nécessairement un principe de guidage primordial - les ordinateurs doivent fournir une arithmétique qui fonctionne de la même manière que l'arithmétique que les gens apprennent à l'école.» - Extrait de la spécification arithmétique décimale.

et

Les chiffres décimaux peuvent être représentés exactement.En revanche, des nombres comme 1.1 et 2.2 n'ont pas de représentations exactes en point de flottaison binaire.Les utilisateurs finaux ne s'attendaient généralement pas à ce que 1.1 + 2.2 s'affiche comme 3.3000000000000003 comme il le fait avec le point flottant binaire.

Decimal fournit le type d'opérations qui facilitent l'écriture d'applications nécessitant des opérations en virgule flottante et aussi besoin de présenter ces résultats dans un format lisible par l’homme, par exemple en comptabilité.

C'est effectivement un gros problème.Essayez ce code :

print "%.2f" % (round((2*4.4+3*5.6+3*4.4)/8,2),)

Il affiche 4,85.Ensuite tu fais :

print "Media = %.1f" % (round((2*4.4+3*5.6+3*4.4)/8,1),)

et il montre 4,8.Faites vos calculs à la main, la réponse exacte est 4,85, mais si vous essayez :

print "Media = %.20f" % (round((2*4.4+3*5.6+3*4.4)/8,20),)

vous pouvez voir la vérité :le point flottant est stocké comme la somme finie la plus proche de fractions dont les dénominateurs sont des puissances de deux.

Vous pouvez utiliser l'opérateur de format de chaîne %, similaire à sprintf.

mystring = "%.2f" % 5.5999

imprimer le meunier.

print '%.1f' % 5.59  # returns 5.6

Fonctionne parfaitement

format(5.59, '.1f') # to display
float(format(5.59, '.1f')) #to round

Je fais:

int(round( x , 0))

Dans ce cas, nous arrondissons d’abord correctement au niveau de l’unité, puis nous convertissons en entier pour éviter d’imprimer un float.

donc

>>> int(round(5.59,0))
6

Je pense que cette réponse fonctionne mieux que le formatage de la chaîne, et il me semble également plus logique d'utiliser la fonction round.

Code:

x1 = 5.63
x2 = 5.65
print(float('%.2f' % round(x1,1)))  # gives you '5.6'
print(float('%.2f' % round(x2,1)))  # gives you '5.7'

Sortir:

5.6
5.7

C'est ici que je vois un échec.Et si vous vouliez arrondir ces 2 nombres à une décimale ?23.45 23,55 Mon éducation était qu'en terminant celles-ci, vous devriez obtenir:23.4 23.6 La "règle" étant que vous devriez rassembler si le nombre précédent était étrange, pas rassemblé si le nombre précédent était uniforme.La fonction round en python tronque simplement le 5.

Le problème se pose uniquement lorsque le dernier chiffre est 5.Par exemple.0,045 est stocké en interne sous la forme 0,044999999999999...Vous pouvez simplement incrémenter le dernier chiffre à 6 et arrondir.Cela vous donnera les résultats souhaités.

import re


def custom_round(num, precision=0):
    # Get the type of given number
    type_num = type(num)
    # If the given type is not a valid number type, raise TypeError
    if type_num not in [int, float, Decimal]:
        raise TypeError("type {} doesn't define __round__ method".format(type_num.__name__))
    # If passed number is int, there is no rounding off.
    if type_num == int:
        return num
    # Convert number to string.
    str_num = str(num).lower()
    # We will remove negative context from the number and add it back in the end
    negative_number = False
    if num < 0:
        negative_number = True
        str_num = str_num[1:]
    # If number is in format 1e-12 or 2e+13, we have to convert it to
    # to a string in standard decimal notation.
    if 'e-' in str_num:
        # For 1.23e-7, e_power = 7
        e_power = int(re.findall('e-[0-9]+', str_num)[0][2:])
        # For 1.23e-7, number = 123
        number = ''.join(str_num.split('e-')[0].split('.'))
        zeros = ''
        # Number of zeros = e_power - 1 = 6
        for i in range(e_power - 1):
            zeros = zeros + '0'
        # Scientific notation 1.23e-7 in regular decimal = 0.000000123
        str_num = '0.' + zeros + number
    if 'e+' in str_num:
        # For 1.23e+7, e_power = 7
        e_power = int(re.findall('e\+[0-9]+', str_num)[0][2:])
        # For 1.23e+7, number_characteristic = 1
        # characteristic is number left of decimal point.
        number_characteristic = str_num.split('e+')[0].split('.')[0]
        # For 1.23e+7, number_mantissa = 23
        # mantissa is number right of decimal point.
        number_mantissa = str_num.split('e+')[0].split('.')[1]
        # For 1.23e+7, number = 123
        number = number_characteristic + number_mantissa
        zeros = ''
        # Eg: for this condition = 1.23e+7
        if e_power >= len(number_mantissa):
            # Number of zeros = e_power - mantissa length = 5
            for i in range(e_power - len(number_mantissa)):
                zeros = zeros + '0'
            # Scientific notation 1.23e+7 in regular decimal = 12300000.0
            str_num = number + zeros + '.0'
        # Eg: for this condition = 1.23e+1
        if e_power < len(number_mantissa):
            # In this case, we only need to shift the decimal e_power digits to the right
            # So we just copy the digits from mantissa to characteristic and then remove
            # them from mantissa.
            for i in range(e_power):
                number_characteristic = number_characteristic + number_mantissa[i]
            number_mantissa = number_mantissa[i:]
            # Scientific notation 1.23e+1 in regular decimal = 12.3
            str_num = number_characteristic + '.' + number_mantissa
    # characteristic is number left of decimal point.
    characteristic_part = str_num.split('.')[0]
    # mantissa is number right of decimal point.
    mantissa_part = str_num.split('.')[1]
    # If number is supposed to be rounded to whole number,
    # check first decimal digit. If more than 5, return
    # characteristic + 1 else return characteristic
    if precision == 0:
        if mantissa_part and int(mantissa_part[0]) >= 5:
            return type_num(int(characteristic_part) + 1)
        return type_num(characteristic_part)
    # Get the precision of the given number.
    num_precision = len(mantissa_part)
    # Rounding off is done only if number precision is
    # greater than requested precision
    if num_precision <= precision:
        return num
    # Replace the last '5' with 6 so that rounding off returns desired results
    if str_num[-1] == '5':
        str_num = re.sub('5$', '6', str_num)
    result = round(type_num(str_num), precision)
    # If the number was negative, add negative context back
    if negative_number:
        result = result * -1
    return result

Qu'en est-il de:

round(n,1)+epsilon
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top