Come arrotoli un numero in Python?


487

Questo problema mi sta uccidendo. Come si fa a raccogliere un numero UP in Python?

Ho provato a arrotondare (numero) ma ha arrotondato il numero verso il basso. Esempio:

round(2.3) = 2.0 and not 3, what I would like

Ho provato int (numero + .5) ma ha arrotondato di nuovo il numero! Esempio:

int(2.3 + .5) = 2

Poi ho provato a arrotondare (numero + .5) ma non funzionerà in casi limite. Esempio:

WAIT! THIS WORKED!

Si prega di avvisare.


4
round(number + .5)non funziona se il numero è intero. round(3+.5) == 4, quando vuoi davvero 3.
Nearoo,

Risposte:


846

La funzione ceil (soffitto):

import math
print(math.ceil(4.2))

21
Elaborazione: math.ceil restituisce il numero intero più piccolo che è maggiore o uguale al valore di input. Questa funzione considera l'input come float (Python non ha variabili fortemente tipizzate) e la funzione restituisce un float. Se si desidera un int, è possibile costruire un int dal valore restituito, ad es.int(math.ceil(363))
RW Sinnet,

9
@Sinnet: In realtà si potrebbe dire che python è fortemente tipizzato stackoverflow.com/a/11328980/5069869
Bernhard

1
@TheEspinosa: Sì, python è decisamente fortemente tipizzato, è solo che molte funzioni fanno domande sul tipo di alcuni parametri ed eseguono codice diverso a seconda della risposta.
Quamrana,

12
@RWSinnet In Python 3, math.ceilrestituisce un oggetto intero effettivo, non solo un oggetto mobile con valore intero.
Arthur Tacca,

Prenditi cura della precisione del galleggiante, a causa del 10000000 * 0.00136 = 13600.000000000002cemento può aumentare moltomath.ceil(10000000 * 0.00136) = 13601.0
ofthestreet

171

So che questa risposta è per una domanda di qualche tempo fa, ma se non vuoi importare la matematica e vuoi solo arrotondare, questo funziona per me.

>>> int(21 / 5)
4
>>> int(21 / 5) + (21 % 5 > 0)
5

La prima parte diventa 4 e la seconda parte viene valutata "True" se è presente un resto, che in aggiunta True = 1; False = 0. Quindi se non c'è resto, rimane lo stesso numero intero, ma se c'è un resto aggiunge 1.


38
Bello. È inoltre possibile utilizzare //per la divisione di numeri interi, quindi diventa 21 // 5 + (21 % 5 > 0).
naught101

6
Questa è la soluzione migliore se sono coinvolti solo numeri interi. Nessun floats inutile . Bello.
Nico Schlömer,

158

Interessante problema di Python 2.x da tenere a mente:

>>> import math
>>> math.ceil(4500/1000)
4.0
>>> math.ceil(4500/1000.0)
5.0

Il problema è che la divisione di due in Python produce un altro int e viene troncato prima della chiamata sul soffitto. Devi fare di un valore un float (o cast) per ottenere un risultato corretto.

In javascript, lo stesso codice esatto produce un risultato diverso:

console.log(Math.ceil(4500/1000));
5

44
In Python 2.x : int / int -> int e int / float -> float In Python 3.x : int / int può provocare un float
gecco

7
puoi ottenere Python 3.x sul comportamento in alcune versioni di Python 2.x abilitando la "vera divisione", come mostrato qui
Rob Dennis,

110

Se si lavora con numeri interi, un modo per arrotondare per eccesso è sfruttare il fatto che arrotonda per difetto //: basta fare la divisione sul numero negativo, quindi negare la risposta. Nessuna importazione, virgola mobile o condizionale necessaria.

rounded_up = -(-numerator // denominator)

Per esempio:

>>> print(-(-101 // 5))
21

1
Che dire quando non è necessario eseguire alcuna operazione matematica? Cioè hai solo un numero.
Klik,

2
@Klik: allora puoi semplicemente dividere per 1 ==> - (-num // 1) e stai ottenendo la tua risposta :-) Buona giornata! David Bau: proposta molto bella!
Marco smdm,

10
Ho cronometrato tutte le risposte qui e questo è stato cinque volte più veloce del successivo migliore (math.ceil). @Andreas ha avuto lo stesso tempo
mini totent

@minitotent Non è sorprendente poiché è una semplice divisione di interi e un paio di operazioni a ciclo singolo. Questo è il tipo di risposta che ti dà un lavoro: comprendere non solo la lingua, ma tutti gli strati di astrazioni sottostanti.
Nearoo,

Bello! Ho sempre usato (num + den - 1) // den, il che va bene per intinput con denominatori positivi, ma fallisce se floatè coinvolto anche un singolo non integrale (numeratore o denominatore); questo è più magico, ma funziona sia per ints che per floats. Per i piccoli numeratori, è anche più veloce (su CPython 3.7.2), anche se stranamente, quando solo il numeratore è abbastanza grande da richiedere la matematica basata su array, il tuo approccio è più lento; non è chiaro il perché, poiché il lavoro di divisione dovrebbe essere simile e due negazioni unarie dovrebbero essere più economiche di addizione + sottrazione.
ShadowRanger

56

Potrebbe interessarti anche numpy:

>>> import numpy as np
>>> np.ceil(2.3)
3.0

Non sto dicendo che è meglio della matematica, ma se stavi già usando numpy per altri scopi, puoi mantenere coerente il tuo codice.

Ad ogni modo, ho trovato solo un dettaglio. Uso parecchio numpy e sono rimasto sorpreso dal fatto che non sia stato menzionato, ma ovviamente la risposta accettata funziona perfettamente.


3
Anche usare numpy è bello. Il più semplice sarebbe con la matematica poiché fa già parte delle librerie di Python integrate. Ha più senso. Invece, come hai detto, se usi molto intorpidito per altri problemi, allora ha senso e coerenza usare numpy.ceil :-) Buon suggerimento!
Marco smdm,

30

Utilizzaremath.ceil per arrotondare:

>>> import math
>>> math.ceil(5.4)
6.0

NOTA : l'ingresso deve essere float.

Se hai bisogno di un numero intero, chiama intper convertirlo:

>>> int(math.ceil(5.4))
6

A proposito, usare math.floorper arrotondare per difetto e roundper arrotondare al numero intero più vicino.

>>> math.floor(4.4), math.floor(4.5), math.floor(5.4), math.floor(5.5)
(4.0, 4.0, 5.0, 5.0)
>>> round(4.4), round(4.5), round(5.4), round(5.5)
(4.0, 5.0, 5.0, 6.0)
>>> math.ceil(4.4), math.ceil(4.5), math.ceil(5.4), math.ceil(5.5)
(5.0, 5.0, 6.0, 6.0)

1
L'input non deve necessariamente essere un float se si utilizza Python 3: se ceil() ne occuperà internamente
Guiva


11

Sono sorpreso che nessuno abbia suggerito

(numerator + denominator - 1) // denominator

per la divisione di numeri interi con arrotondamento per eccesso. Usato per essere il modo comune per C / C ++ / CUDA (cfr. divup)


2
Rilevante solo per le lingue tipizzate staticamente. Se il denominatore è un float sei morto.
Bharel,

Questo funziona anche in modo coerente solo se il denominatore è positivo; se il denominatore è negativo, è necessario aggiungere 1invece di sottrarlo o capovolgere i segni sia del numeratore che del denominatore prima di eseguire la matematica.
ShadowRanger

7

Il valore arrotondato deve essere float

a = 8 
b = 21
print math.ceil(a / b)
>>> 0

ma

print math.ceil(float(a) / b)
>>> 1.0

6

Prova questo:

a = 211.0
print(int(a) + ((int(a) - a) != 0))

1
Intelligente. L' ((int(a) - a) != 0)espressione ritorna 1ogni volta che è anecessario arrotondare per eccesso. Potresti voler espandere la tua risposta e spiegare come funziona.
Tom Aranda,

@TomAranda Qualcuno può spiegare come un'espressione booleana valuta un valore per favore?
Bowen Liu,

6
>>> def roundup(number):
...     return round(number+.5)
>>> roundup(2.3)
3
>>> roundup(19.00000000001)
20

Questa funzione non richiede moduli.


E se il tuo numero fosse 3, allora arrotonderebbe per 4
eccesso

15
Funziona solo nel 99% di tutti i casi. Non ci hai pensato bene. Tali soluzioni dovrebbero essere evitate a tutti i costi.
Nearoo,

quindi invece di +.5 fai +49999999 abbastanza buono per me.
FlyingZebra1

5

Le risposte di cui sopra sono corrette, tuttavia, importare il mathmodulo solo per questa funzione di solito mi sembra un po 'eccessivo. Fortunatamente, c'è un altro modo per farlo:

g = 7/5
g = int(g) + (not g.is_integer())

Truee Falsesono interpretati come 1e 0in una dichiarazione che coinvolge numeri in Python. g.is_interger()fondamentalmente si traduce in g.has_no_decimal()o g == int(g). Quindi si legge l'ultima affermazione in inglese round g down and add one if g has decimal.


1
E se hai voglia, puoi usare int(g) + (g % 1 > 0)invece ;-)
Nearoo

from math import ceilsembra risolvere l'importazione dell'intero modulo matematico :)
SH7890

@ SH7890 Temo che la linea non sia molto diversa import mathin termini di ciò che accade dietro le quinte. Lascia cadere tutti i simboli tranne ceil.
Nearoo,

5

Senza importare la matematica // usando l'ambiente di base:

a) metodo / metodo di classe

def ceil(fl): 
  return int(fl) + (1 if fl-int(fl) else 0)

def ceil(self, fl): 
  return int(fl) + (1 if fl-int(fl) else 0)

b) lambda:

ceil = lambda fl:int(fl)+(1 if fl-int(fl) else 0)

5

Per coloro che vogliono arrotondare a / be ottenere numeri interi:

Un'altra variante che utilizza la divisione di interi è

def int_ceil(a, b):
    return (a - 1) // b + 1

>>> int_ceil(19, 5)
4
>>> int_ceil(20, 5)
4
>>> int_ceil(21, 5)
5

3

Nel caso in cui qualcuno stia cercando di arrotondare per eccesso a un decimale specifico:

import math
def round_up(n, decimals=0):
    multiplier = 10 ** decimals
    return math.ceil(n * multiplier) / multiplier

1

Sono sorpreso di non aver ancora visto questa risposta round(x + 0.4999), quindi la metterò giù. Nota che funziona con qualsiasi versione di Python. Le modifiche apportate allo schema di arrotondamento di Python hanno reso le cose difficili. Vedi questo post .

Senza importare, utilizzo:

def roundUp(num):
    return round(num + 0.49)

testCases = list(x*0.1 for x in range(0, 50))

print(testCases)
for test in testCases:
    print("{:5.2f}  -> {:5.2f}".format(test, roundUp(test)))

Perché questo funziona

Dai documenti

Per i tipi predefiniti che supportano round (), i valori sono arrotondati al multiplo più vicino di 10 alla potenza meno n; se due multipli sono ugualmente vicini, l'arrotondamento viene effettuato verso la scelta pari

Pertanto 2.5 viene arrotondato a 2 e 3.5 viene arrotondato a 4. In caso contrario, è possibile arrotondare per eccesso aggiungendo 0,5, ma vogliamo evitare di arrivare a metà. Quindi, se aggiungi 0,4999 ti avvicinerai, ma con abbastanza margine da arrotondare a quello che ti aspetteresti normalmente. Naturalmente, ciò fallirà se x + 0.4999è uguale a [n].5000, ma è improbabile.


2
Usando 0.4999, non riuscirà a dare un risultato corretto per qualsiasi input tra ???. 0000 e ???. 0001 (intervallo aperto), non solo esattamente ???. 0001. Ad esempio, se lo provi con 3.00005, otterrai un risultato di 3 anziché il previsto 4. Naturalmente puoi ridurre la probabilità che ciò accada aggiungendo sempre più cifre fino alla massima precisione dei float, ma qual è il punto che se ci sono soluzioni più robuste e intuitive a portata di mano, come l'utilizzo math.ceil()?
Blubberdiblub,

@blubberdiblub Nella mia risposta dichiaro Without importing I use:. Ho anche detto che fallirà se x + 0.4999è uguale a [n].5000.
Klik,

4
Sì, affermi nella tua risposta che la tua soluzione è senza importazione, ma non ne vedo il valore. Il mathmodulo math.ceil()è nella libreria standard, quindi disponibile ovunque per tutti gli scopi pratici senza installare materiale aggiuntivo. E riguardo alla tua menzione di quando fallisce, questo è incompleto nella tua risposta, poiché fallisce per un intero intervallo, non solo per un singolo punto. Tecnicamente, potresti sostenere di essere corretto, come dici se e non iff , ma farà impressione sul lettore occasionale che è meno probabile di quanto non sia in realtà.
Blubberdiblub,

0

Per farlo senza alcuna importazione:

>>> round_up = lambda num: int(num + 1) if int(num) != num else int(num)
>>> round_up(2.0)
2
>>> round_up(2.1)
3

0

So che risale a un bel po 'di tempo fa, ma ho trovato una risposta abbastanza interessante, quindi ecco qui:

-round(-x-0.5)

Questo risolve i casi di bordi e funziona sia per i numeri positivi che per quelli negativi e non richiede l'importazione di alcuna funzione

Saluti


2
Questo sarà ancora arrotondato per -round(-x-0.3) = x
difetto

0

quando si opera 4500/1000 in Python, il risultato sarà 4, perché per Python predefinito si assume come intero il risultato, logicamente: 4500/1000 = 4.5 -> int (4.5) = 4 e il ceil di 4 ovviamente è 4

usando 4500 / 1000.0 il risultato sarà 4.5 e ceil di 4,5 -> 5

Usando javascript riceverai 4.5 come risultato di 4500/1000, perché javascript assume solo il risultato come "tipo numerico" e restituisce un risultato direttamente come float

In bocca al lupo!!


Questo è vero solo in Python 2.x. In Python 3, la divisione con un singolo /si traduce sempre in un float, quindi 4500/1000è sempre 4.5.
Nearoo,

0

Se non vuoi importare nulla, puoi sempre scrivere la tua semplice funzione come:

def RoundUP(num): if num== int(num): return num return int(num + 1)


2
Questo non funziona se num è 2.05. Devi avere almeno tante cifre con un 9 quanto il tuo input, lasciandoti con uno 0,999 ... che è 1. Ma poi il tuo caso d'angolo 2 viene nuovamente arrotondato. - Beh, immagino che ci sia una ragione per cui math.ceil è lì.
Johannes Maria Frank,

-1

È possibile utilizzare la progettazione del piano e aggiungerne 1. 2.3 // 2 + 1


2
oppure usa ceil()invece di fare stranamente il contrario e poi compensare
guiva

2
Questo non funzionerà. Ad esempio:from math import ceil; assert 4 // 2 + 1 == ceil(4 / 2)
Carl Thomé,

-1

Penso che stai confondendo i meccanismi di funzionamento tra int()e round().

int()tronca sempre i numeri decimali se viene fornito un numero mobile; mentre round(), nel caso di 2.5dove 2e 3siano entrambi a uguale distanza da 2.5, Python ritorna qualunque sia più lontano dal punto 0.

round(2.5) = 3
int(2.5) = 2

"arrotondamento per eccesso" significa che ad esempio 2.3viene trasformato in 3, che non accade in nessuno dei tuoi esempi.
Nearoo,

-2

Mia condivisione

Ho testato l' print(-(-101 // 5)) = 21esempio sopra.

Ora per arrotondare per eccesso:

101 * 19% = 19.19

Non posso usare, **quindi ho diffuso il moltiplicare per divisione:

(-(-101 //(1/0.19))) = 20

-3

Sono fondamentalmente un principiante in Python, ma se stai solo cercando di arrotondare invece di giù perché non farlo:

round(integer) + 1

2
Questo non funzionerà per nessun numero intero i dove 2.5 <numero intero <3. Il valore desiderato dopo l'arrotondamento è 3 ma la tua espressione lo trasformerà in 4.
Pranav Shukla

1
Penso che intendi round(integer + 0.5)questo che faccio spesso
Klik,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.