web-dev-qa-db-fra.com

Python arrondit l'entier à la centaine suivante

Semble qu'on aurait déjà dû lui demander des centaines de fois (les jeux de mots sont amusants =) mais je ne trouve que la fonction pour arrondir les flotteurs. Comment arrondir un entier, par exemple: 130 -> 200?

66
ofko

L'arrondi est généralement effectué sur des nombres à virgule flottante, et ici, vous devez connaître trois fonctions de base: round (arrondit à l'entier le plus proche), math.floor (arrondit toujours vers le bas) et math.ceil (toujours arrondi).

Vous demandez des nombres entiers et des arrondis à des centaines, mais nous pouvons toujours utiliser math.ceil tant que vos nombres sont inférieurs à 253. Utiliser math.ceil, nous divisons simplement par 100 en premier, arrondissons et multiplions par 100 par la suite:

>>> import math
>>> def roundup(x):
...     return int(math.ceil(x / 100.0)) * 100
... 
>>> roundup(100)
100
>>> roundup(101)
200

En divisant par 100 en premier et en multipliant par 100 par la suite, "décale" deux décimales vers la droite et vers la gauche pour que math.ceil fonctionne sur des centaines. Vous pouvez utiliser 10**n au lieu de 100 si vous voulez arrondir à des dizaines (n = 1), milliers (n = 3), etc.

Une autre manière de procéder consiste à éviter les nombres à virgule flottante (ils ont une précision limitée) et à utiliser à la place des entiers uniquement. Les entiers ont une précision arbitraire en Python, ce qui vous permet d'arrondir des nombres de n'importe quelle taille. La règle pour l'arrondi est simple: trouvez le reste après la division avec 100, et ajoutez 100 moins ce reste s'il n'est pas nul:

>>> def roundup(x):
...     return x if x % 100 == 0 else x + 100 - x % 100

Cela fonctionne pour les numéros de toute taille:

>>> roundup(100)
100
>>> roundup(130)
200
>>> roundup(1234567891234567891)
1234567891234567900L

J'ai fait un mini-benchmark des deux solutions:

$ python -m timeit -s 'import math' -s 'x = 130' 'int(math.ceil(x/100.0)) * 100'
1000000 loops, best of 3: 0.364 usec per loop
$ python -m timeit -s 'x = 130' 'x if x % 100 == 0 else x + 100 - x % 100'
10000000 loops, best of 3: 0.162 usec per loop

La solution entière pure est plus rapide d'un facteur deux par rapport au math.ceil Solution.

Thomas a proposé une solution basée sur des nombres entiers qui est identique à celle que j'ai ci-dessus, sauf qu'elle utilise une astuce en multipliant les valeurs booléennes. Il est intéressant de voir qu'il n'y a aucun avantage de vitesse à écrire le code de cette façon:

$ python -m timeit -s 'x = 130' 'x + 100*(x%100>0) - x%100'
10000000 loops, best of 3: 0.167 usec per loop

Pour terminer, permettez-moi de noter également que si vous aviez voulu arrondir 101–149 à 100 et arrondir 150–199 à 200, par exemple, arrondir au le plus proche cent, alors la fonction round intégrée peut le faire pour vous:

>>> int(round(130, -2))
100
>>> int(round(170, -2))
200
117
Martin Geisler

Essaye ça:

int(round(130 + 49, -2))
19
Fred Foo

Il s'agit d'une réponse tardive, mais il existe une solution simple qui combine les meilleurs aspects des réponses existantes: le multiple suivant de 100 À partir de x est x - x % -100 (Ou si vous préférez, x + (-x) % 100).

>>> x = 130
>>> x -= x % -100  # Round x up to next multiple of 100.
>>> x
200

C'est rapide et simple, donne des résultats corrects pour tout entier x (comme la réponse de John Machin) et donne également des résultats raisonnables (modulo les mises en garde habituelles sur la représentation en virgule flottante) si x est un flotteur (comme la réponse de Martin Geisler).

>>> x = 0.1
>>> x -= x % -100
>>> x
100.0
19
Mark Dickinson

Voici un moyen général d'arrondir au multiple le plus proche d'un entier positif:

def roundUpToMultiple(number, multiple):
    num = number + (multiple - 1)
    return num - (num % multiple)

Exemple d'utilisation:

 >>> roundUpToMultiple (101, 100) 
 200 
 >>> roundUpToMultiple (654, ​​321) 
 963 
17
Luke Woodward

Pour a non négatif, b positif, les deux entiers:

>>> rup = lambda a, b: (a + b - 1) // b * b
>>> [(x, rup(x, 100)) for x in (199, 200, 201)]
[(199, 200), (200, 200), (201, 300)]

pdate La réponse actuellement acceptée s'effondre avec des entiers tels que float (x)/float (y) ne peut pas être représenté avec précision comme un float. Voir ce code:

import math

def geisler(x, y): return int(math.ceil(x / float(y))) * y

def orozco(x, y): return x + y * (x % y > 0) - x % y

def machin(x, y): return (x + y - 1) // y * y

for m, n in (
    (123456789123456789, 100),
    (1234567891234567891, 100),
    (12345678912345678912, 100),
    ):
    print; print m, "m"; print n, "n"
    for func in (geissler, orozco, machin):
        print func(m, n), func.__name__

Sortie:

123456789123456789 m
100 n
123456789123456800 geisler
123456789123456800 orozco
123456789123456800 machin

1234567891234567891 m
100 n
1234567891234568000 geisler <<<=== wrong
1234567891234567900 orozco
1234567891234567900 machin

12345678912345678912 m
100 n
12345678912345680000 geisler <<<=== wrong
12345678912345679000 orozco
12345678912345679000 machin

Et voici quelques horaires:

>\python27\python -m timeit -s "import math;x =130" "int(math.ceil(x/100.0))*100"
1000000 loops, best of 3: 0.342 usec per loop

>\python27\python -m timeit -s "x = 130" "x + 100 * (x % 100 > 0) - x % 100"
10000000 loops, best of 3: 0.151 usec per loop

>\python27\python -m timeit -s "x = 100" "(x + 99) // 100 * 100"
10000000 loops, best of 3: 0.0903 usec per loop
9
John Machin

Si votre int est x: x + 100 - x % 100

Cependant, comme indiqué dans les commentaires, cela retournera 200 si x==100.

Si ce n'est pas le comportement attendu, vous pouvez utiliser x + 100*(x%100>0) - x%100

3
Thomas Orozco

Attention: optimisations prématurées à venir ...

Étant donné que tant de réponses ici font le timing de cela, je voulais ajouter une autre alternative.

Prendre @Martin Geisler

def roundup(x):
    return x if x % 100 == 0 else x + 100 - x % 100

(que je préfère pour plusieurs raisons)

mais en tenant compte de l'action%

def roundup2(x):
    x100= x % 100
    return x if x100 == 0 else x + 100 - x100

Donne une amélioration de la vitesse de ~ 20% par rapport à l'original

def roundup3(x):
    x100 = x % 100
    return x if not x100 else x + 100 - x100

Est encore meilleur et est ~ 36% plus rapide que l'original

enfin, je pensais que je pouvais supprimer l'opérateur not et changer l'ordre des branches en espérant que cela augmenterait également la vitesse, mais j'ai été déconcerté de découvrir qu'il est en fait plus lent de retomber pour être seulement 23% plus rapide que l'original.

def roundup4(x):
    x100 = x % 100
    return x + 100 - x100  if x100 else x


>python -m timeit -s "x = 130" "x if x % 100 == 0 else x + 100 - x % 100"
1000000 loops, best of 3: 0.359 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x if x100 == 0 else x + 100 - x100"
1000000 loops, best of 3: 0.287 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x if not x100 else x + 100 - x100"
1000000 loops, best of 3: 0.23 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x + 100 - x100 if x100 else x"
1000000 loops, best of 3: 0.277 usec per loop

des explications sur les raisons pour lesquelles 3 est plus rapide que 4 seraient les bienvenues.

3
epeleg

Essaye ça:

import math
def ceilm(number,multiple):
    '''Returns a float rounded up by a factor of the multiple specified'''
    return math.ceil(float(number)/multiple)*multiple

Exemple d'utilisation:

>>> ceilm(257,5)
260
>>> ceilm(260,5)
260
2
Sukrit Gupta