A continuación explícase como redondear números en Python redondeando ou redondeando a un número par. Suponse que os números son de tipo flotante en coma flotante ou enteiro int.
- función integrada (por exemplo, en linguaxe de programación):
round()
- Redondea os decimais a calquera número de díxitos.
- Redondea os enteiros a calquera número de díxitos.
- round() redondea a un número par, non a un redondeo común
- biblioteca estándar
decimal
quantize()
Decimal
Creando un obxecto- Redondeo de decimais a calquera número de díxitos e redondeo a números pares
- Redondeo de números enteiros a calquera número de díxitos e redondeo a números pares
- Definir unha nova función
- Redondea os decimais a calquera número de díxitos.
- Redondea os enteiros a calquera número de díxitos
- Nota: Para valores negativos
Teña en conta que, como se mencionou anteriormente, a función integrada de redondeo non é un redondeo xeral, senón un redondeo a un número par. Consulte a continuación para obter máis detalles.
función integrada (por exemplo, en linguaxe de programación):round()
Round() ofrécese como unha función integrada. Pódese usar sen importar ningún módulo.
O primeiro argumento é o número orixinal e o segundo é o número de díxitos (a cantos díxitos se redondea).
Redondea os decimais a calquera número de díxitos.
O seguinte é un exemplo de procesamento para o tipo flotante de coma flotante.
Se o segundo argumento se omite, arredondarase a un número enteiro. O tipo tamén se converte nun tipo int enteiro.
f = 123.456 print(round(f)) # 123 print(type(round(f))) # <class 'int'>
Se se especifica o segundo argumento, devolve un tipo flotante de coma flotante.
Se se especifica un número enteiro positivo, especifícase a cifra decimal; se se especifica un número enteiro negativo, especifícase o lugar do número enteiro. -1 redondea á décima máis próxima, -2 redondea á centésima máis próxima e 0 redondea a un número enteiro (o primeiro lugar), pero devolve un tipo flotante, a diferenza de cando se omite.
print(round(f, 1)) # 123.5 print(round(f, 2)) # 123.46 print(round(f, -1)) # 120.0 print(round(f, -2)) # 100.0 print(round(f, 0)) # 123.0 print(type(round(f, 0))) # <class 'float'>
Redondea os enteiros a calquera número de díxitos.
O seguinte é un exemplo de procesamento para o tipo enteiro int.
Se se omite o segundo argumento, ou se se especifica 0 ou un número enteiro positivo, o valor orixinal devólvese tal e como está. Se se especifica un número enteiro negativo, arredondarase ao enteiro correspondente. En ambos casos, devólvese un tipo int enteiro.
i = 99518 print(round(i)) # 99518 print(round(i, 2)) # 99518 print(round(i, -1)) # 99520 print(round(i, -2)) # 99500 print(round(i, -3)) # 100000
round() redondea a un número par, non a un redondeo común
Teña en conta que o redondeo coa función round() incorporada en Python 3 redondea a un número par, non a un redondeo xeral.
Tal e como está escrito na documentación oficial, 0,5 redondea a 0, 5 a 0, etc.
print('0.4 =>', round(0.4)) print('0.5 =>', round(0.5)) print('0.6 =>', round(0.6)) # 0.4 => 0 # 0.5 => 0 # 0.6 => 1 print('4 =>', round(4, -1)) print('5 =>', round(5, -1)) print('6 =>', round(6, -1)) # 4 => 0 # 5 => 0 # 6 => 10
A definición de redondeo a un número par é a seguinte.
Se a fracción é inferior a 0,5, redondea por abaixo; se a fracción é maior que 0,5, arredéiaa cara arriba; se a fracción é exactamente 0,5, redondea ao número par entre o redondeo cara abaixo e o redondeo cara arriba.
Rounding – Wikipedia
0,5 non sempre está truncado.
print('0.5 =>', round(0.5)) print('1.5 =>', round(1.5)) print('2.5 =>', round(2.5)) print('3.5 =>', round(3.5)) print('4.5 =>', round(4.5)) # 0.5 => 0 # 1.5 => 2 # 2.5 => 2 # 3.5 => 4 # 4.5 => 4
Nalgúns casos, a definición de redondeo a un número par nin sequera se aplica ao procesamento despois de dous decimais.
print('0.05 =>', round(0.05, 1)) print('0.15 =>', round(0.15, 1)) print('0.25 =>', round(0.25, 1)) print('0.35 =>', round(0.35, 1)) print('0.45 =>', round(0.45, 1)) # 0.05 => 0.1 # 0.15 => 0.1 # 0.25 => 0.2 # 0.35 => 0.3 # 0.45 => 0.5
Isto débese ao feito de que os decimais non se poden representar exactamente como números de coma flotante, como se indica na documentación oficial.
O comportamento de round() para números de coma flotante pode sorprendelo:Por exemplo, round(2,675, 2) darache 2,67 en lugar de 2,68 como se esperaba. Isto non é un erro.:Isto é o resultado do feito de que a maioría dos decimais non se poden representar exactamente mediante números de coma flotante.
round() — Built-in Functions — Python 3.10.2 Documentation
Se queres conseguir un redondeo xeral ou un redondeo preciso dos decimais a números pares, podes usar a cuantificación decimal estándar da biblioteca (descrita a continuación) ou definir unha nova función.
Tamén teña en conta que round() en Python 2 non se redondea a un número par, senón que se redondea.
quantize() do decimal da biblioteca estándar
O módulo decimal da biblioteca estándar pódese usar para manexar números decimais exactos en coma flotante.
Usando o método quantize() do módulo decimal, é posible redondear números especificando o modo de redondeo.
- decimal quantize() — Decimal fixed point and floating point arithmetic — Python 3.10.2 Documentation
- Rounding modes — Decimal fixed point and floating point arithmetic — Python 3.10.2 Documentation
Os valores establecidos para o redondeo dos argumentos do método quantize() teñen os seguintes significados, respectivamente.
ROUND_HALF_UP
:Redondeo xeralROUND_HALF_EVEN
:Redondeo a números pares
O módulo decimal é unha biblioteca estándar, polo que non se precisa instalación adicional, pero é necesario importar.
from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN
Creación dun obxecto decimal
Decimal() pódese usar para crear obxectos de tipo Decimal.
Se especificas un tipo flotante como argumento, podes ver como se trata realmente o valor.
print(Decimal(0.05)) # 0.05000000000000000277555756156289135105907917022705078125 print(type(Decimal(0.05))) # <class 'decimal.Decimal'>
Como se mostra no exemplo, 0,05 non se trata exactamente como 0,05. Esta é a razón pola que a función incorporada round() descrita anteriormente redondeou a un valor diferente do esperado para os valores decimais, incluíndo 0,05 no exemplo.
Dado que 0,5 é a metade (-1 potencia de 2), pódese expresar exactamente en notación binaria.
print(Decimal(0.5)) # 0.5
Se especifica o tipo de cadea str en lugar do tipo flotante, tratarase como o tipo decimal do valor exacto.
print(Decimal('0.05')) # 0.05
Redondeo de decimais a calquera número de díxitos e redondeo a números pares
Chama a quantize() desde un obxecto de tipo Decimal para redondear o valor.
O primeiro argumento de quantize() é unha cadea co mesmo número de díxitos que o número de díxitos que quere atopar, como “0,1” ou “0,01”.
Ademais, o argumento ROUNDING especifica o modo de redondeo; se se especifica ROUND_HALF_UP, utilízase o redondeo xeral.
f = 123.456 print(Decimal(str(f)).quantize(Decimal('0'), rounding=ROUND_HALF_UP)) # 123 print(Decimal(str(f)).quantize(Decimal('0.1'), rounding=ROUND_HALF_UP)) # 123.5 print(Decimal(str(f)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)) # 123.46
A diferenza da función integrada round(), 0,5 redondéase a 1.
print('0.4 =>', Decimal(str(0.4)).quantize(Decimal('0'), rounding=ROUND_HALF_UP)) print('0.5 =>', Decimal(str(0.5)).quantize(Decimal('0'), rounding=ROUND_HALF_UP)) print('0.6 =>', Decimal(str(0.6)).quantize(Decimal('0'), rounding=ROUND_HALF_UP)) # 0.4 => 0 # 0.5 => 1 # 0.6 => 1
Se o argumento redondeo está definido como ROUND_HALF_EVEN, o redondeo realízase a números pares como na función incorporada round().
Como se mencionou anteriormente, se se especifica un tipo flotante de coma flotante como argumento de Decimal(), trátase como un obxecto Decimal cun valor igual ao valor real do tipo flotante, polo que o resultado de usar o quantize() método será diferente do que se espera, igual que a función incorporada round().
print('0.05 =>', round(0.05, 1)) print('0.15 =>', round(0.15, 1)) print('0.25 =>', round(0.25, 1)) print('0.35 =>', round(0.35, 1)) print('0.45 =>', round(0.45, 1)) # 0.05 => 0.1 # 0.15 => 0.1 # 0.25 => 0.2 # 0.35 => 0.3 # 0.45 => 0.5 print('0.05 =>', Decimal(0.05).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.15 =>', Decimal(0.15).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.25 =>', Decimal(0.25).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.35 =>', Decimal(0.35).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.45 =>', Decimal(0.45).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) # 0.05 => 0.1 # 0.15 => 0.1 # 0.25 => 0.2 # 0.35 => 0.3 # 0.45 => 0.5
Se o argumento de Decimal() se especifica como unha cadea de tipo str, trátase como un obxecto Decimal de exactamente ese valor, polo que o resultado é o esperado.
print('0.05 =>', Decimal(str(0.05)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.15 =>', Decimal(str(0.15)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.25 =>', Decimal(str(0.25)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.35 =>', Decimal(str(0.35)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.45 =>', Decimal(str(0.45)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) # 0.05 => 0.0 # 0.15 => 0.2 # 0.25 => 0.2 # 0.35 => 0.4 # 0.45 => 0.4
Dado que 0.5 pódese manexar correctamente polo tipo flotante, non hai ningún problema en especificar o tipo flotante como argumento de Decimal() cando se redondea a un número enteiro, pero é máis seguro especificar o tipo de cadea str cando se redondea a un decimal.
Por exemplo, 2,675 é en realidade 2,67499…. en tipo flotante. Polo tanto, se queres redondear a dúas cifras decimais, debes especificar unha cadea a Decimal(), se non, o resultado será diferente do resultado esperado se redondea ao número enteiro máis próximo (ROUND_HALF_UP) ou a un número par (ROUND_HALF_EVEN). ).
print(Decimal(2.675)) # 2.67499999999999982236431605997495353221893310546875 print(Decimal(2.675).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)) # 2.67 print(Decimal(str(2.675)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)) # 2.68 print(Decimal(2.675).quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN)) # 2.67 print(Decimal(str(2.675)).quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN)) # 2.68
Teña en conta que o método quantize() devolve un número de tipo Decimal, polo que se quere operar cun número de tipo flotante, cómpre convertelo a un tipo flotante usando float(), se non, producirase un erro.
d = Decimal('123.456').quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) print(d) # 123.46 print(type(d)) # <class 'decimal.Decimal'> # print(1.2 + d) # TypeError: unsupported operand type(s) for +: 'float' and 'decimal.Decimal' print(1.2 + float(d)) # 124.66
Redondeo de números enteiros a calquera número de díxitos e redondeo a números pares
Se queres redondear a un díxito enteiro, especificando algo como ’10’ como primeiro argumento non che dará o resultado desexado.
i = 99518 print(Decimal(i).quantize(Decimal('10'), rounding=ROUND_HALF_UP)) # 99518
Isto débese a que quantize() realiza o redondeo segundo o expoñente do obxecto Decimal, pero o expoñente de Decimal(’10’) é 0, non 1.
Podes especificar un expoñente arbitrario usando E como cadea de expoñentes (por exemplo, ‘1E1’). O expoñente do expoñente pódese comprobar no método as_tuple.
print(Decimal('10').as_tuple()) # DecimalTuple(sign=0, digits=(1, 0), exponent=0) print(Decimal('1E1').as_tuple()) # DecimalTuple(sign=0, digits=(1,), exponent=1)
Tal e como está, o resultado estará en notación exponencial usando E. Se queres usar a notación normal, ou se queres operar co tipo int enteiro despois de redondear, usa int() para converter o resultado.
print(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)) # 9.952E+4 print(int(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))) # 99520 print(int(Decimal(i).quantize(Decimal('1E2'), rounding=ROUND_HALF_UP))) # 99500 print(int(Decimal(i).quantize(Decimal('1E3'), rounding=ROUND_HALF_UP))) # 100000
Se o redondeo do argumento se define en ROUND_HALF_UP, producirase un redondeo xeral, por exemplo, 5 redondearase a 10.
print('4 =>', int(Decimal(4).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))) print('5 =>', int(Decimal(5).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))) print('6 =>', int(Decimal(6).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))) # 4 => 0 # 5 => 10 # 6 => 10
Por suposto, non hai ningún problema se o especificas como cadea.
Definir unha nova función
O método de uso do módulo decimal é preciso e seguro, pero se non estás cómodo coa conversión de tipos, podes definir unha nova función para lograr o redondeo xeral.
Hai moitas formas posibles de facelo, por exemplo, a seguinte función.
def my_round(val, digit=0): p = 10 ** digit return (val * p * 2 + 1) // 2 / p
Se non precisa especificar o número de díxitos e redondear sempre ao primeiro decimal, pode utilizar unha forma máis sinxela.
my_round_int = lambda x: int((x * 2 + 1) // 2)
Se precisa ser preciso, é máis seguro usar decimal.
O seguinte é só para referencia.
Redondea os decimais a calquera número de díxitos.
print(int(my_round(f))) # 123 print(my_round_int(f)) # 123 print(my_round(f, 1)) # 123.5 print(my_round(f, 2)) # 123.46
A diferenza da rolda, 0,5 pasa a ser 1 segundo o redondeo xeral.
print(int(my_round(0.4))) print(int(my_round(0.5))) print(int(my_round(0.6))) # 0 # 1 # 1
Redondea os enteiros a calquera número de díxitos
i = 99518 print(int(my_round(i, -1))) # 99520 print(int(my_round(i, -2))) # 99500 print(int(my_round(i, -3))) # 100000
A diferenza da rolda, 5 pasa a ser 10 segundo o redondeo común.
print(int(my_round(4, -1))) print(int(my_round(5, -1))) print(int(my_round(6, -1))) # 0 # 10 # 10
Nota: Para valores negativos
Na función de exemplo anterior, -0,5 redondéase a 0.
print(int(my_round(-0.4))) print(int(my_round(-0.5))) print(int(my_round(-0.6))) # 0 # 0 # -1
Hai varias formas de pensar sobre o redondeo de valores negativos, pero se queres converter -0,5 en -1, podes modificalo do seguinte xeito, por exemplo
import math def my_round2(val, digit=0): p = 10 ** digit s = math.copysign(1, val) return (s * val * p * 2 + 1) // 2 / p * s print(int(my_round2(-0.4))) print(int(my_round2(-0.5))) print(int(my_round2(-0.6))) # 0 # -1 # -1