float - round python 3
Cómo redondear un número a figuras significativas en Python (12)
Necesito redondear un flotador para que se muestre en una IU. Por ejemplo, a una figura significativa:
1234 -> 1000
0.12 -> 0.1
0.012 -> 0.01
0.062 -> 0.06
6253 -> 6000
1999 -> 2000
¿Hay una buena manera de hacer esto usando la biblioteca de Python, o tengo que escribirla yo mismo?
% g en el formato de cadena formateará un flotador redondeado a algunas figuras significativas. A veces usará la notación científica ''e'', por lo tanto, convierta la cadena redondeada a un punto flotante y luego a través del formato de cadena% s.
>>> ''%s'' % float(''%.1g'' % 1234)
''1000''
>>> ''%s'' % float(''%.1g'' % 0.12)
''0.1''
>>> ''%s'' % float(''%.1g'' % 0.012)
''0.01''
>>> ''%s'' % float(''%.1g'' % 0.062)
''0.06''
>>> ''%s'' % float(''%.1g'' % 6253)
''6000.0''
>>> ''%s'' % float(''%.1g'' % 1999)
''2000.0''
He creado el to-precision que hace que haga lo que quiere. Te permite dar a tus números cifras más o menos significativas.
También genera notación estándar, científica y de ingeniería con un número específico de cifras significativas.
En la respuesta aceptada, está la línea
>>> round_to_1(1234243)
1000000.0
Eso realmente especifica 8 sig higos. Para el número 1234243 mi biblioteca solo muestra una figura significativa:
>>> from to_precision import to_precision
>>> to_precision(1234243, 1, ''std'')
''1000000''
>>> to_precision(1234243, 1, ''sci'')
''1e6''
>>> to_precision(1234243, 1, ''eng'')
''1e6''
También redondeará la última cifra significativa y puede elegir automáticamente qué notación usar si no se especifica una notación:
>>> to_precision(599, 2)
''600''
>>> to_precision(1164, 2)
''1.2e3''
Me encontré con esto también, pero necesitaba control sobre el tipo de redondeo. Por lo tanto, escribí una función rápida (vea el código a continuación) que puede tomar en cuenta el valor, el tipo de redondeo y los dígitos significativos deseados.
import decimal
from math import log10, floor
def myrounding(value , roundstyle=''ROUND_HALF_UP'',sig = 3):
roundstyles = [ ''ROUND_05UP'',''ROUND_DOWN'',''ROUND_HALF_DOWN'',''ROUND_HALF_UP'',''ROUND_CEILING'',''ROUND_FLOOR'',''ROUND_HALF_EVEN'',''ROUND_UP'']
power = -1 * floor(log10(abs(value)))
value = ''{0:f}''.format(value) #format value to string to prevent float conversion issues
divided = Decimal(value) * (Decimal(''10.0'')**power)
roundto = Decimal(''10.0'')**(-sig+1)
if roundstyle not in roundstyles:
print(''roundstyle must be in list:'', roundstyles) ## Could thrown an exception here if you want.
return_val = decimal.Decimal(divided).quantize(roundto,rounding=roundstyle)*(decimal.Decimal(10.0)**-power)
nozero = (''{0:f}''.format(return_val)).rstrip(''0'').rstrip(''.'') # strips out trailing 0 and .
return decimal.Decimal(nozero)
for x in list(map(float, ''-1.234 1.2345 0.03 -90.25 90.34543 9123.3 111''.split())):
print (x, ''rounded UP: '',myrounding(x,''ROUND_UP'',3))
print (x, ''rounded normal: '',myrounding(x,sig=3))
Modifiqué la solución de indgar para manejar números negativos y números pequeños (incluido cero).
def round_sig(x, sig=6, small_value=1.0e-9):
return round(x, sig - int(floor(log10(max(abs(x), abs(small_value))))) - 1)
No puedo pensar en nada que sea capaz de manejar esto de la caja. Pero se maneja bastante bien para los números de coma flotante.
>>> round(1.2322, 2)
1.23
Los enteros son más complicados. No se almacenan como base 10 en la memoria, por lo que los lugares importantes no son algo natural de hacer. Sin embargo, es bastante trivial implementar una vez que son una cadena.
O para enteros:
>>> def intround(n, sigfigs):
... n = str(n)
... return n[:sigfigs] + (''0'' * (len(n)-(sigfigs)))
>>> intround(1234, 1)
''1000''
>>> intround(1234, 2)
Si desea crear una función que maneje cualquier número, mi preferencia sería convertirlos a cadenas y buscar un lugar decimal para decidir qué hacer:
>>> def roundall1(n, sigfigs):
... n = str(n)
... try:
... sigfigs = n.index(''.'')
... except ValueError:
... pass
... return intround(n, sigfigs)
Otra opción es verificar el tipo. Esto será mucho menos flexible y probablemente no funcionará bien con otros números como objetos Decimal
:
>>> def roundall2(n, sigfigs):
... if type(n) is int: return intround(n, sigfigs)
... else: return round(n, sigfigs)
Para redondear un entero a 1 cifra significativa, la idea básica es convertirlo en un punto flotante con 1 dígito antes del punto y redondearlo, luego convertirlo a su tamaño entero original.
Para hacer esto necesitamos saber la potencia más grande de 10 menos que el número entero. Podemos usar floor de la función log 10 para esto.
from math import log10, floor def round_int(i,places): if i == 0: return 0 isign = i/abs(i) i = abs(i) if i < 1: return 0 max10exp = floor(log10(i)) if max10exp+1 < places: return i sig10pow = 10**(max10exp-places+1) floated = i*1.0/sig10pow defloated = round(floated)*sig10pow return int(defloated*isign)
Puedes usar números negativos para enteros redondos:
>>> round(1234, -3)
1000.0
Por lo tanto, si solo necesitas el dígito más significativo:
>>> from math import log10, floor
>>> def round_to_1(x):
... return round(x, -int(floor(log10(abs(x)))))
...
>>> round_to_1(0.0232)
0.02
>>> round_to_1(1234243)
1000000.0
>>> round_to_1(13)
10.0
>>> round_to_1(4)
4.0
>>> round_to_1(19)
20.0
Probablemente tengas que encargarte de convertir el flotante en un entero si es más grande que 1.
Si desea redondear sin involucrar cadenas, el enlace que encontré está enterrado en los comentarios anteriores:
code.activestate.com/lists/python-tutor/70739
me parece mejor Luego, cuando imprime con cualquier descriptor de formato de cadena, obtiene un resultado razonable y puede usar la representación numérica para otros fines de cálculo.
El código en el enlace es de tres líneas: def, doc y return. Tiene un error: es necesario verificar si hay logaritmos explosivos. Eso es fácil. Compare la entrada con sys.float_info.min
. La solución completa es:
import sys,math
def tidy(x, n):
"""Return ''x'' rounded to ''n'' significant digits."""
y=abs(x)
if y <= sys.float_info.min: return 0.0
return round( x, int( n-math.ceil(math.log10(y)) ) )
Funciona para cualquier valor numérico escalar, yn puede ser float
si necesita cambiar la respuesta por algún motivo. En realidad puedes empujar el límite a:
sys.float_info.min*sys.float_info.epsilon
sin provocar un error, si por alguna razón estás trabajando con valores minúsculos.
Si desea tener un decimal diferente a 1 (de lo contrario, es igual a Evgeny):
>>> from math import log10, floor
>>> def round_sig(x, sig=2):
... return round(x, sig-int(floor(log10(abs(x))))-1)
...
>>> round_sig(0.0232)
0.023
>>> round_sig(0.0232, 1)
0.02
>>> round_sig(1234243, 3)
1230000.0
Uso de formato de estilo nuevo de python 2.6+ (ya que% -style está en desuso):
>>> "{0}".format(float("{0:.1g}".format(1216)))
''1000.0''
>>> "{0}".format(float("{0:.1g}".format(0.00356)))
''0.004''
En Python 2.7+ puedes omitir los 0
s principales.
def round_to_n(x, n):
if not x: return 0
power = -int(math.floor(math.log10(abs(x)))) + (n - 1)
factor = (10 ** power)
return round(x * factor) / factor
round_to_n(0.075, 1) # 0.08
round_to_n(0, 1) # 0
round_to_n(-1e15 - 1, 16) # 1000000000000001.0
Esperemos que tome la mejor de todas las respuestas anteriores (menos poder ponerlo como una línea lambda;)). Aún no ha explorado, puede editar esta respuesta:
round_to_n(1e15 + 1, 11) # 999999999999999.9
print(''{:g}''.format(float(''{:.1g}''.format(12.345))))
Esta solución es diferente de todas las demás porque:
- resuelve exactamente la pregunta OP
- no necesita ningún paquete adicional
- no necesita ninguna función auxiliar u operación matemática definida por el usuario
Para un número arbitrario n
de cifras significativas, puede usar:
print(''{:g}''.format(float(''{:.{p}g}''.format(i, p=n))))
Prueba:
a = [1234, 0.12, 0.012, 0.062, 6253, 1999, -3.14, 0., -48.01, 0.75]
b = [''{:g}''.format(float(''{:.1g}''.format(i)))) for i in a]
# b == [''1000'', ''0.1'', ''0.01'', ''0.06'', ''6000'', ''2000'', ''-3'', ''0'', ''-50'', ''0.8'']
Nota : con esta solución, no es posible adaptar el número de cifras significativas dinámicamente desde la entrada porque no hay una forma estándar de distinguir números con diferentes números de ceros finales ( 3.14 == 3.1400
). Si necesita hacerlo, entonces se necesitan funciones no estándar como las provistas en el paquete to-precision .