2012-01-14 47 views
43

Sembra che sia già stato chiesto centinaia (il gioco è divertente =) di volte, ma posso trovare solo la funzione per arrotondare i float. Come arrotondare un numero intero, ad esempio: 130 -> 200?Python arrotonda il numero intero al numero successivo

+0

Vuoi 100 arrotondare fino a 200? – DSM

+0

No, la risposta di Thomas fa proprio quello che mi serve – ofko

+0

La risposta di Thomas * fa * arrotondare 100 fino a 200. È per questo che ho chiesto. – DSM

risposta

78

arrotondamento è in genere fatto su numeri in virgola mobile, e qui ci sono tre funzioni di base che dovreste sapere: round (giri al numero intero più vicino), math.floor (sempre arrotondato per difetto) e math.ceil (sempre arrotondato per eccesso).

interroghi su numeri interi e arrotondamento a centinaia, ma possiamo ancora usare math.ceil finché i numeri più piccolo di 2 . Per utilizzare math.ceil, abbiamo appena dividiamo per 100 prima, radunare, e moltiplicare con 100 dopo:

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

Dividendo per 100 prima e moltiplicare con 100 dopo "sposta" due cifre decimali a destra ea sinistra in modo che math.ceil lavora a centinaia. Si potrebbe utilizzare 10**n invece di 100, se si vuole arrotondare a decine (n = 1), migliaia (n = 3), ecc

Un modo alternativo per farlo è quello di evitare di numeri in virgola mobile (hanno limitato la precisione) e di utilizzare invece solo numeri interi. Gli integer hanno precisione arbitraria in Python, quindi questo ti consente di arrotondare numeri di qualsiasi dimensione. La regola di arrotondamento è semplice: trovare il resto dopo la divisione con 100, e aggiungere 100 meno questo resto se è diverso da zero:

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

Questo funziona per i numeri di qualsiasi dimensione:

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

I ha fatto un mini-punto di riferimento delle due soluzioni:

$ 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 soluzione intera pura è più veloce di un fattore due rispetto alla soluzione math.ceil.

Thomas ha proposto una soluzione basata su un numero identico a quella che ho sopra, tranne che utilizza un trucco moltiplicando i valori booleani. E 'interessante vedere che non v'è alcun vantaggio di velocità di scrittura del codice in questo modo:

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

Come osservazione finale, mi permetta anche notare, che se avessi voluto arrotondare 101-149 a 100 e 150 tondo Da -199 a 200, ad es, Intorno al più vicino cento, allora il built-in round funzione può farlo per voi:

>>> int(round(130, -2)) 
100 
>>> int(round(170, -2)) 
200 
+0

Non sto facendo un normale arrotondamento qui, se fossi sì, userei round() – ofko

+3

@ofko: giusto, vuoi arrotondare. Il 'math.ceil' è il modo canonico per farlo: dividersi e moltiplicarsi per 100 è il modo canonico di fare' round', 'ceil' e' floor' su centinaia. –

+1

Dopo le modifiche recenti, ora ha senso accettare questa risposta. – ofko

13

Prova questo:

int(round(130 + 49, -2)) 
3

Se l'int è x: x + 100 - x % 100

Tuttavia, come sottolineato nei commenti, questo tornerà 200 se x==100.

Se questo non è il comportamento previsto, è possibile utilizzare x + 100*(x%100>0) - x%100

+0

Cosa succede se 'x' è già un multiplo di 100? –

+0

Si potrebbe voler usare le altre soluzioni se non ti piacciono i numeri magici. Se sei preoccupato per le prestazioni, questo tuttavia funziona più velocemente. –

+0

@LukeWoodward Ottimo punto, modifico il numero –

17

Ecco un modo generale di arrotondamento al più vicino multiplo di qualsiasi numero intero positivo:

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

Esempio:

 
>>> roundUpToMultiple(101, 100) 
200 
>>> roundUpToMultiple(654, 321) 
963 
+0

troppo complicato –

+0

equivalente, metodo più corto: 'numero lambda, multiplo: multiplo * (1 + (numero - 1) // multiplo)' –

8

Per a non negativo, b POSI tive, entrambi gli interi:

>>> 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)] 

AggiornaLa risposta correntemente accettato crolla con numeri tali che galleggiante (x)/galleggiante (y) non può essere rappresentato esattamente come float. Vedere questo codice:

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__ 

uscita:

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 

e qui ci sono alcune temporizzazioni:

>\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 
+0

'So che l'OP si trattava di arrotondare un intero '- ma volevo sottolineare che proveresti a utilizzare queste 3 opzioni su (0,5,10) che mi aspetto di restituire 10, quindi i primi due metodi (geisler e orozco) restituiscono 10 come previsto mentre machin restituisce 0 – epeleg

12

Questa è una risposta in ritardo, ma c'è una soluzione semplice che combina gli aspetti migliori della le risposte esistenti: il successivo multiplo di 100 su x è x - x % -100 (o se si preferisce, x + (-x) % 100).

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

Questo è veloce e semplice, dà risultati corretti per qualsiasi intero x (come risposta di John Machin) e inoltre dà risultati ragionevoli-ish (modulo soliti avvertimenti su rappresentazione in virgola mobile) se x è un galleggiante (come la risposta di Martin Geisler).

>>> x = 0.1 
>>> x -= x % -100 
>>> x 
100.0 
+0

la tua soluzione è veloce come quella di Martin ma notazione è più breve Grazie. timeit 'x = 110' 'x - = x% -100' # 100000000 loop, meglio di 3: 9,37 ns per loop VS timeit 'x = 110' 'x + 100 * (x% 100> 0) - x% 100 ' # 100000000 loop, meglio di 3: 9.38 ns per loop – tagoma

1

Prova questo: l'utilizzo

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 

Esempio:

>>> ceilm(257,5) 
260 
>>> ceilm(260,5) 
260 
0

Attenzione: ottimizzazioni prematuri avanti ...

Dal momento che molte delle risposte qui fanno i tempi di questo volevo aggiungere un'altra alternativa.

Prendendo @ Martin Geisler s'

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

(che mi piace di più per diversi motivi)

ma factoring l'azione%

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

produce un miglioramento della velocità ~ 20% sopra l'originale

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

è ancora meglio ed è ~ 36% più velocemente allora l'originale

finalmente stavo pensando che avrei potuto abbandonare l'operatore not e modificare l'ordine dei rami sperando che questo sarebbe anche aumentare la velocità, ma era sconcertato per scoprire che in realtà è più lento tornare indietro per essere solo il 23% più veloce dell'originale.

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 

spiegazioni sul motivo per cui 3 è più veloce di 4 sarebbe il benvenuto.

Problemi correlati