199 votes

Python 3.x arrondi comportement

Je viens de re-lire Ce qui est Nouveau En Python 3.0 et déclare:

La fonction round() arrondi stratégie et le type de retour ont changé. Exacte de la moitié des cas sont maintenant arrondie au même résultat, au lieu de loin de zéro. (Par exemple, ronde(2.5) retourne maintenant 2 plutôt que de 3.)

et la documentation pour les rondes:

Pour les types intégrés de soutien round(), les valeurs sont arrondies à l' plus proche multiple de 10 puissance moins n; si les deux sont multiples également à proximité, l'arrondi se fait vers le même choix

Ainsi, en vertu de la v2.7.3:

In [85]: round(2.5)
Out[85]: 3.0

In [86]: round(3.5)
Out[86]: 4.0

comme je l'avais attendu. Cependant, maintenant, en vertu de la v3.2.3:

In [32]: round(2.5)
Out[32]: 2

In [33]: round(3.5)
Out[33]: 4

Cela semble contre-intuitif, et contrairement à ce que je comprends sur arrondi (et lié à la visite de personnes). L'anglais n'est pas ma langue maternelle, mais jusqu'à ce que j'ai lu cela, je pensais que je savais ce que l'arrondissement entend :-/ j'en suis sûr au moment de la v3 a été introduit, il doit y avoir une discussion d' cela, mais j'ai été incapable de trouver une bonne raison de ma recherche.

  1. Quelqu'un aurait-il aperçu de pourquoi cela a changé à ce point?
  2. Existe-il d'autres langages de programmation grand public (par exemple, C, C++, Java, Perl, ..) qui font ce genre de (pour moi incompatible) arrondi?

Ce qui me manque ici?

Mise à JOUR: @Li-aungYip le commentaire de "l'arrondi" m'a donné le droit de terme de recherche/mots clés de la recherche et j'ai trouvé ce DONC, la question: Pourquoi n' .NET, utilisez l'arrondi par défaut?, donc, je vais lire avec précaution.

181voto

kindall Points 60645

Python 3.0 manière est considéré comme le standard de la méthode d'arrondi ces jours-ci, bien que certaines implémentations de langue ne sont pas sur le bus encore.

Le simple "toujours ronde 0,5" technique se traduit par un léger biais vers le plus grand nombre. Avec un grand nombre de calculs, ceci peut être important. Le Python 3.0 approche élimine ce problème.

Votre perplexité peut dériver à partir d'une idée fausse qu'il existe une seule méthode de l'arrondissement. La norme IEEE 754, le standard international pour les mathématiques à virgule flottante, définit cinq différentes méthodes d'arrondi (celui utilisé par Python 3.0 est la valeur par défaut). Et il en existe d'autres.

Vous n'êtes pas seul, toutefois, ce comportement n'est pas aussi connu qu'il devrait l'être. AppleScript était, si je me souviens bien, un des premiers à adopter cette méthode d'arrondi. L' round commande en AppleScript ne fait offre plusieurs options, mais l'aller-vers-même est la valeur par défaut comme il est dans la norme IEEE 754. Apparemment, l'ingénieur qui a mis en œuvre l' round commande a tellement marre de toutes les demandes de "faire fonctionner comme je l'ai appris à l'école" qu'il a mis en place seulement que: round 2.5 rounding as taught in school est valable AppleScript commande. :-)

45voto

dawg Points 26051

Vous pouvez contrôler le mode d'arrondi que vous obtenez dans Py3000 à l'aide de la Virgule module:

>>> decimal.Decimal('3.5').quantize(decimal.Decimal('1'), 
    rounding=decimal.ROUND_HALF_UP)
>>> Decimal('4')

>>> decimal.Decimal('2.5').quantize(decimal.Decimal('1'),    
    rounding=decimal.ROUND_HALF_EVEN)
>>> Decimal('2')

>>> decimal.Decimal('3.5').quantize(decimal.Decimal('1'), 
    rounding=decimal.ROUND_HALF_DOWN)
>>> Decimal('3')

16voto

skif1979 Points 11

Juste pour ajouter ici une remarque importante à partir de la documentation:

https://docs.python.org/dev/library/functions.html#round

Note

Le comportement de round() pour les flotteurs peuvent être surprenants: par exemple, round(2.675, 2) donne de 2,67 à la place de l'2.68. Ce n'est pas un bug: c'est une conséquence du fait que la plupart des fractions décimales ne peut pas être exactement comme dans un flotteur. Voir L'Arithmétique À Virgule Flottante: Questions et les Limitations pour plus d'informations.

Ne soyez donc pas surpris d'obtenir les résultats suivants en Python 3.2:

>>> round(0.25,1), round(0.35,1), round(0.45,1), round(0.55,1)
(0.2, 0.3, 0.5, 0.6)

>>> round(0.025,2), round(0.035,2), round(0.045,2), round(0.055,2)
(0.03, 0.04, 0.04, 0.06)

7voto

narnie Points 568

J'ai récemment eu des problèmes avec cela, aussi. Donc, j'ai développé un module python 3 qui a 2 fonctions trueround() et trueround_precision() adresse et à donner le même arrondissement de comportement ont été utilisés à partir de l'école primaire (pas l'arrondi). Voici le module. Il suffit d'enregistrer le code et le copier ou de les importer. Remarque: le trueround_precision module peut changer l'arrondissement de comportement selon les besoins selon les ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP, et ROUND_05UP drapeaux en décimal (module de voir que les modules de documentation pour plus d'info). Pour les fonctions ci-dessous, voir les docstrings ou de l'utilisation de l'aide(trueround) et de l'aide(trueround_precision) si copiés dans les services d'un interprète pour plus de documentation.

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

def trueround(number, places=0):
    '''
    trueround(number, places)

    example:

        >>> trueround(2.55, 1) == 2.6
        True

    uses standard functions with no import to give "normal" behavior to 
    rounding so that trueround(2.5) == 3, trueround(3.5) == 4, 
    trueround(4.5) == 5, etc. Use with caution, however. This still has 
    the same problem with floating point math. The return object will 
    be type int if places=0 or a float if places=>1.

    number is the floating point number needed rounding

    places is the number of decimal places to round to with '0' as the
        default which will actually return our interger. Otherwise, a
        floating point will be returned to the given decimal place.

    Note:   Use trueround_precision() if true precision with
            floats is needed

    GPL 2.0
    copywrite by Narnie Harshoe <signupnarnie@gmail.com>
    '''
    place = 10**(places)
    rounded = (int(number*place + 0.5if number>=0 else -0.5))/place
    if rounded == int(rounded):
        rounded = int(rounded)
    return rounded

def trueround_precision(number, places=0, rounding=None):
    '''
    trueround_precision(number, places, rounding=ROUND_HALF_UP)

    Uses true precision for floating numbers using the 'decimal' module in
    python and assumes the module has already been imported before calling
    this function. The return object is of type Decimal.

    All rounding options are available from the decimal module including 
    ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, 
    ROUND_HALF_UP, ROUND_UP, and ROUND_05UP.

    examples:

        >>> trueround(2.5, 0) == Decimal('3')
        True
        >>> trueround(2.5, 0, ROUND_DOWN) == Decimal('2')
        True

    number is a floating point number or a string type containing a number on 
        on which to be acted.

    places is the number of decimal places to round to with '0' as the default.

    Note:   if type float is passed as the first argument to the function, it
            will first be converted to a str type for correct rounding.

    GPL 2.0
    copywrite by Narnie Harshoe <signupnarnie@gmail.com>
    '''
    from decimal import Decimal as dec
    from decimal import ROUND_HALF_UP
    from decimal import ROUND_CEILING
    from decimal import ROUND_DOWN
    from decimal import ROUND_FLOOR
    from decimal import ROUND_HALF_DOWN
    from decimal import ROUND_HALF_EVEN
    from decimal import ROUND_UP
    from decimal import ROUND_05UP

    if type(number) == type(float()):
        number = str(number)
    if rounding == None:
        rounding = ROUND_HALF_UP
    place = '1.'
    for i in range(places):
        place = ''.join([place, '0'])
    return dec(number).quantize(dec(place), rounding=rounding)

Espérons que cela aide,

Narnie

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X