Arrotonda il numero al numero intero più vicino


230

Ho cercato di arrotondare numeri float lunghi come:

32.268907563;
32.268907563;
31.2396694215;
33.6206896552;
...

Finora senza successo. Ho provato math.ceil(x), math.floor(x)(anche se sarebbe arrotondato per eccesso o per difetto, che non è quello che sto cercando) e round(x)che non ha funzionato neanche (numeri ancora mobili).

Cosa potevo fare?

MODIFICA: CODICE:

for i in widthRange:
    for j in heightRange:
        r, g, b = rgb_im.getpixel((i, j))
        h, s, v = colorsys.rgb_to_hsv(r/255.0, g/255.0, b/255.0)
        h = h * 360
        int(round(h))
        print(h)

3
Vorrei provareint(x)
The Brofessor

ciò non darebbe errore? valore letterale non valido per int () con base 10:
snh_nl

Risposte:


366
int(round(x))

Lo arrotonderà e lo cambierà in numero intero

MODIFICARE:

Non stai assegnando int (round (h)) a nessuna variabile. Quando si chiama int (round (h)), restituisce il numero intero ma non fa altro; devi cambiare quella riga per:

h = int(round(h))

Per assegnare il nuovo valore a h

MODIFICA 2:

Come ha detto @plowman nei commenti, Python's round()non funziona come ci si aspetterebbe, ed è perché il modo in cui il numero viene memorizzato come variabile di solito non è il modo in cui lo vedi sullo schermo. Esistono molte risposte che spiegano questo comportamento:

round () non sembra arrotondare correttamente

Un modo per evitare questo problema è utilizzare il decimale come indicato da questa risposta: https://stackoverflow.com/a/15398691/4345659

Affinché questa risposta funzioni correttamente senza utilizzare librerie aggiuntive, sarebbe opportuno utilizzare una funzione di arrotondamento personalizzata. Dopo molte correzioni, ho trovato la seguente soluzione, che per quanto ho testato ha evitato tutti i problemi di archiviazione. Si basa sull'utilizzo della rappresentazione di stringhe, ottenuta con repr()(NOT str()!). Sembra confuso ma è stato l'unico modo che ho trovato per risolvere tutti i casi. Funziona con Python2 e Python3.

def proper_round(num, dec=0):
    num = str(num)[:str(num).index('.')+dec+2]
    if num[-1]>='5':
        return float(num[:-2-(not dec)]+str(int(num[-2-(not dec)])+1))
    return float(num[:-1])

test:

>>> print(proper_round(1.0005,3))
1.001
>>> print(proper_round(2.0005,3))
2.001
>>> print(proper_round(3.0005,3))
3.001
>>> print(proper_round(4.0005,3))
4.001
>>> print(proper_round(5.0005,3))
5.001
>>> print(proper_round(1.005,2))
1.01
>>> print(proper_round(2.005,2))
2.01
>>> print(proper_round(3.005,2))
3.01
>>> print(proper_round(4.005,2))
4.01
>>> print(proper_round(5.005,2))
5.01
>>> print(proper_round(1.05,1))
1.1
>>> print(proper_round(2.05,1))
2.1
>>> print(proper_round(3.05,1))
3.1
>>> print(proper_round(4.05,1))
4.1
>>> print(proper_round(5.05,1))
5.1
>>> print(proper_round(1.5))
2.0
>>> print(proper_round(2.5))
3.0
>>> print(proper_round(3.5))
4.0
>>> print(proper_round(4.5))
5.0
>>> print(proper_round(5.5))
6.0
>>> 
>>> print(proper_round(1.000499999999,3))
1.0
>>> print(proper_round(2.000499999999,3))
2.0
>>> print(proper_round(3.000499999999,3))
3.0
>>> print(proper_round(4.000499999999,3))
4.0
>>> print(proper_round(5.000499999999,3))
5.0
>>> print(proper_round(1.00499999999,2))
1.0
>>> print(proper_round(2.00499999999,2))
2.0
>>> print(proper_round(3.00499999999,2))
3.0
>>> print(proper_round(4.00499999999,2))
4.0
>>> print(proper_round(5.00499999999,2))
5.0
>>> print(proper_round(1.0499999999,1))
1.0
>>> print(proper_round(2.0499999999,1))
2.0
>>> print(proper_round(3.0499999999,1))
3.0
>>> print(proper_round(4.0499999999,1))
4.0
>>> print(proper_round(5.0499999999,1))
5.0
>>> print(proper_round(1.499999999))
1.0
>>> print(proper_round(2.499999999))
2.0
>>> print(proper_round(3.499999999))
3.0
>>> print(proper_round(4.499999999))
4.0
>>> print(proper_round(5.499999999))
5.0

Infine, la risposta corretta sarebbe:

# Having proper_round defined as previously stated
h = int(proper_round(h))

EDIT 3:

test:

>>> proper_round(6.39764125, 2)
6.31 # should be 6.4
>>> proper_round(6.9764125, 1)
6.1  # should be 7

Il gotcha qui è che il decdecimo decimale può essere 9 e se la dec+1decima cifra> = 5 il 9 diventerà uno 0 e un 1 dovrebbe essere portato alla dec-1decima cifra.

Se lo prendiamo in considerazione, otteniamo:

def proper_round(num, dec=0):
    num = str(num)[:str(num).index('.')+dec+2]
    if num[-1]>='5':
      a = num[:-2-(not dec)]       # integer part
      b = int(num[-2-(not dec)])+1 # decimal part
      return float(a)+b**(-dec+1) if a and b == 10 else float(a+str(b))
    return float(num[:-1])

Nella situazione sopra descritta b = 10e la versione precedente si concatenerebbe ae bciò comporterebbe una concatenazione di 10dove scomparire lo 0 finale. Questa versione si trasforma bnella giusta cifra decimale basata su dec, come carry corretto.


2
print ("4.5)", int (round (4.5))) # mi ha dato 4 print ("5.5)", int (round (5.5))) # mi ha dato 6
:,

È legato alla versione di Python. Mi dà 5 e 6 usando Python 2.7.9 e, come hai detto, 4 e 6 usando Python 3.4.2
francisco sollima,

1
Vale la pena notare: questa soluzione non arrotonda come probabilmente ti aspetti. Ad esempio, int(round(4.5))arrotonda per difetto a 4, mentre int(round(4.500001))per arrotondare correttamente a 5.
plowman

Se vuoi un numero intero, allora round(x)è sufficiente in Python 3.6.2 (e forse anche nelle versioni inferiori). Il risultato è già di tipo int. Nota: round(x, n)sarà di tipo float.
Elmex80s

1
Questo non funziona per 112439.50093565206. Dà o / p -> 11253.0. Accidenti strano .. !!!!
Ajj

24

Usa round(x, y). Arrotonderà il numero fino al decimale desiderato.

Per esempio:

>>> round(32.268907563, 3)
32.269

20

round(value,significantDigit)è la soluzione ordinaria, tuttavia ciò non funziona come ci si aspetterebbe da una prospettiva matematica quando si concludono i valori rotondi 5. Se la 5cifra è nella cifra immediatamente successiva a quella in cui si è arrotondati, questi valori vengono arrotondati solo a volte come previsto (vale 8.005a dire arrotondare a due cifre decimali 8.01). Per alcuni valori dovuti alle stranezze della matematica in virgola mobile, vengono invece arrotondati per difetto!

vale a dire

>>> round(1.0005,3)
1.0
>>> round(2.0005,3)
2.001
>>> round(3.0005,3)
3.001
>>> round(4.0005,3)
4.0
>>> round(1.005,2)
1.0
>>> round(5.005,2)
5.0
>>> round(6.005,2)
6.0
>>> round(7.005,2)
7.0
>>> round(3.005,2)
3.0
>>> round(8.005,2)
8.01

Strano.

Supponendo che il tuo intento sia quello di fare il tradizionale arrotondamento per la statistica nelle scienze, questo è un comodo wrapper per far roundfunzionare la funzione come previsto, necessitando di importcose extra come Decimal.

>>> round(0.075,2)

0.07

>>> round(0.075+10**(-2*5),2)

0.08

Aha! Quindi in base a questo possiamo fare una funzione ...

def roundTraditional(val,digits):
   return round(val+10**(-len(str(val))-1), digits)

Fondamentalmente questo aggiunge un valore garantito per essere inferiore alla cifra meno indicata della stringa su cui stai cercando di utilizzare round. Aggiungendo quella piccola quantità preserva il roundcomportamento della maggior parte dei casi, assicurando al contempo se la cifra inferiore a quella a cui viene arrotondato viene arrotondata per 5eccesso e se è 4arrotondata per eccesso.

L'approccio dell'uso è 10**(-len(val)-1)stato deliberato, in quanto è il numero più piccolo che è possibile aggiungere per forzare lo spostamento, garantendo anche che il valore aggiunto non cambi mai l'arrotondamento anche se .manca il decimale . Potrei usare solo 10**(-len(val))con un condizionale if (val>1)per sottrarre di 1più ... ma è più semplice sottrarre sempre il 1dato che non cambierà molto l'intervallo applicabile di numeri decimali che questa soluzione alternativa può gestire correttamente. Questo approccio fallirà se i tuoi valori raggiungono i limiti del tipo, questo fallirà, ma per quasi l'intero intervallo di valori decimali validi dovrebbe funzionare.

Puoi anche usare la libreria decimale per farlo, ma il wrapper che propongo è più semplice e può essere preferito in alcuni casi.


Modifica: Grazie Blckknght per aver sottolineato che il 5caso marginale si verifica solo per determinati valori. Anche una versione precedente di questa risposta non era abbastanza esplicita che il comportamento di arrotondamento dispari si verifica solo quando la cifra immediatamente inferiore alla cifra che stai arrotondando ha un5 .


Non sono sicuro del motivo per cui pensi che i decimali con 5l'ultima cifra arrotondino sempre per eccesso. Questo non è il caso di un test rapido ho appena fatto con i numeri come 1.5, 2.5, 3.5e così via e 1.05, 1.15, 1.25, 1.35arrotondando al primo decimale. Il primo set (arrotondamento a metà esatto a piccoli numeri interi) sempre arrotondato a un numero intero pari. Quest'ultimo set non arrotonda in modo coerente, probabilmente a causa di inesatte rappresentazioni binarie di alcuni dei valori. I float che hanno esatte rappresentazioni binarie come 1.25round hanno una cifra anche meno significativa, ma gli altri sembrano arrotondare casualmente.
Blckknght,

Interessante ... hai ragione. round(4.0005,3)4.0e round(1.0005,3)1.0, ma round(2.0005,3)2.001e round(3.0005,3)3.001. Ma è proprio per questo che la mia soluzione proposta è necessaria ... non sai cosa aspettarti dal round di borsa, in questo caso significativo!
Jason R. Mick,

Grazie per questo. La tua funzione sarà utile quando si presenta questo problema.
TMWP

1
Intendevi avere , digitsalla fine di quella dichiarazione di reso? Nessun gioco di parole previsto. ( Media intendo)
user3342816

Ah, giusto, in effetti avrebbe dovuto essere lì. Buona cattura ... sorpreso che nessun altro lo avesse notato! Salverà coloro che utilizzano la soluzione un po 'di frustrazione. :-)
Jason R. Mick,

15

Per aspetti positivi, prova

int(x + 0.5)

Per farlo funzionare anche per i negativi, prova

int(x + (0.5 if x > 0 else -0.5))

int()funziona come una funzione da pavimento e quindi puoi sfruttare questa proprietà. Questo è sicuramente il modo più veloce.


4
non funziona per i negativi>>> x=-0.999 >>> int(x), round(x), int(x+0.5) (0, -1.0, 0)
user2907934

3
Se ti interessano i casi angolari, non utilizzare la tecnica "aggiungi 0,5 e piano" - ci sono alcuni valori che potrebbero non arrotondare come ti aspetti! Vedi stackoverflow.com/a/47302585/2732969 per un take C ++ e la risposta stackoverflow.com/a/38744026/2732969 proprio in questa domanda.
Anon,

Avevo bisogno di un metodo rapido, non doveva essere accurato e non avrebbe avuto molti casi angolari e l'errore nei casi angolari non è importante nel mio scenario. Quindi questo è sicuramente il mio approccio per alcuni casi speciali in cui la velocità è la priorità. Non raccomandare per precisione o accuratezza.
Agente M

11

Python non sta facendo il giro a metà per pareggiare , come prescritto dall'IEEE 754 ?

Fare attenzione a ridefinire o utilizzare l'arrotondamento "non standard" ...

(Vedi anche https://stackoverflow.com/a/33019948/109839 )


2
Questa risposta non è chiara. Round half to evennon è assolutamente prescritto da IEEE 754, ma è invece solo una delle numerose opzioni di arrotondamento descritte dalla norma . Round to nearest, ties away from zero(vale a dire il comportamento che la maggior parte delle persone si aspetta) è anche un'opzione ed è l'impostazione predefinita, ad esempio in C / C ++.
tel

Sono d'accordo, la formulazione è piuttosto confusa. Quello che intendevo dire che Python sta arrotondando la metà a heven (vedi la tabella alla fine di docs.python.org/3.7/library/… dove roundè spiegato) e lo sta facendo secondo il modo in cui è prescritta "arrotondare la metà a pari" lavorare (o descritto) secondo lo standard.
Mapio,

8

Puoi anche usare numpy supponendo che se stai usando python3.x ecco un esempio

import numpy as np
x = 2.3
print(np.rint(x))
>>> 2.0

7

La tua soluzione sta chiamando senza specificare il secondo argomento (numero di cifre decimali)

>>> round(0.44)
0
>>> round(0.64)
1

che è un risultato molto migliore di

>>> int(round(0.44, 2))
0
>>> int(round(0.64, 2))
0

Dalla documentazione di Python su https://docs.python.org/3/library/functions.html#round

round (numero [, ndigits])

Restituisce il numero arrotondato per specificare la precisione dopo il punto decimale. Se ndigits viene omesso o è None, restituisce il numero intero più vicino al suo input.

Nota

Il comportamento di round () per i float può essere sorprendente: ad esempio round (2.675, 2) fornisce 2,67 invece del previsto 2,68. Questo non è un bug: è il risultato del fatto che la maggior parte delle frazioni decimali non può essere rappresentata esattamente come un float. Vedi Aritmetica in virgola mobile: problemi e limitazioni per ulteriori informazioni.


1

Se hai bisogno (ad esempio) di un'approssimazione di due cifre per A, allora int(A*100+0.5)/100.0 farà quello che stai cercando.

Se è necessaria un'approssimazione di tre cifre, moltiplicare e dividere per 1000 e così via.


1

Qualcosa del genere dovrebbe anche funzionare

import numpy as np    

def proper_round(a):
    '''
    given any real number 'a' returns an integer closest to 'a'
    '''
    a_ceil = np.ceil(a)
    a_floor = np.floor(a)
    if np.abs(a_ceil - a) < np.abs(a_floor - a):
        return int(a_ceil)
    else:
        return int(a_floor)

0

A tal fine, suggerirei di fare quanto segue:

int(round(x))

Questo ti darà il numero intero più vicino.

Spero che questo ti aiuti!!


0

Uso e posso consigliare la seguente soluzione (python3.6):

y = int(x + (x % (1 if x >= 0 else -1)))

Funziona bene per i mezze numeri (positivi e negativi) e funziona anche più velocemente di int (round (x)):

round_methods = [lambda x: int(round(x)), 
                 lambda x: int(x + (x % (1 if x >= 0 else -1))),
                 lambda x: np.rint(x).astype(int),
                 lambda x: int(proper_round(x))]

for rm in round_methods:
    %timeit rm(112.5)
Out:
201 ns ± 3.96 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
159 ns ± 0.646 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
925 ns ± 7.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
1.18 µs ± 8.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

for rm in round_methods:
    print(rm(112.4), rm(112.5), rm(112.6))
    print(rm(-12.4), rm(-12.5), rm(-12.6))
    print('=' * 11)

Out:
112 112 113
-12 -12 -13
===========
112 113 113
-12 -13 -13
===========
112 112 113
-12 -12 -13
===========
112 113 113
-12 -13 -13
===========
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.