significativas - Truncando flotadores en Python
truncar a 2 decimales python (23)
>>> piso ((1.23658945) * 10 ** 4) / 10 ** 4
1.2365
# dividir y multiplicar por 10 ** cantidad de dígitos deseados
Quiero eliminar los dígitos de un flotador para tener una cantidad fija de dígitos después del punto, como:
1.923328437452 -> 1.923
Necesito dar salida como una cadena a otra función, no imprimir.
También quiero ignorar los dígitos perdidos, no los rodeo.
Aquí hay una manera fácil:
def truncate(num, res=3):
return (floor(num*pow(10, res)+0.5))/pow(10, res)
para num = 1.923328437452, esta salidas 1.923
El resultado de la round
es un flotador, así que ten cuidado (ejemplo es de Python 2.6):
>>> round(1.923328437452, 3)
1.923
>>> round(1.23456, 3)
1.2350000000000001
Estará mejor cuando use una cadena formateada:
>>> "%.3f" % 1.923328437452
''1.923''
>>> "%.3f" % 1.23456
''1.235''
En mi prompt de Python 2.7:
>>> int(1.923328437452 * 1000)/1000.0 1.923
Hay una solución fácil en python 3. Dónde cortar I se define con una variable de ayuda decPlace para que sea fácil de adaptar.
f = 1.12345
decPlace= 4
f_cut = int(f * 10**decPlace) /10**decPlace
Salida:
f = 1.1234
Espero eso ayude.
Hice algo como esto:
from math import trunc
def truncate(number, decimals=0):
if decimals < 0:
raise ValueError(''truncate received an invalid value of decimals ({})''.format(decimals))
elif decimals == 0:
return trunc(number)
else:
factor = float(10**decimals)
return trunc(number*factor)/factor
La manera verdaderamente pithónica de hacerlo es
from decimal import *
with localcontext() as ctx:
ctx.rounding = ROUND_DOWN
print Decimal(''1.923328437452'').quantize(Decimal(''0.001''))
Muchas de las respuestas dadas para esta pregunta son completamente erróneas. O bien redondean flotadores (en lugar de truncar) o no funcionan para todos los casos.
Este es el principal resultado de Google cuando busco ''Python Truncate Float'', un concepto que es muy sencillo y que merece mejores respuestas. Estoy de acuerdo con Hatchkins en que utilizar el módulo decimal
es la manera pitónica de hacerlo, por lo que doy aquí una función que creo que responde correctamente la pregunta, y que funciona como se espera para todos los casos.
Como nota al margen, los valores fraccionarios, en general, no pueden ser representados exactamente por variables binarias de coma flotante (ver here una discusión de esto), que es la razón por la cual mi función devuelve una cadena.
from decimal import Decimal, localcontext, ROUND_DOWN
def truncate(number, places):
if not isinstance(places, int):
raise ValueError("Decimal places must be an integer.")
if places < 1:
raise ValueError("Decimal places must be at least 1.")
# If you want to truncate to 0 decimal places, just do int(number).
with localcontext() as context:
context.rounding = ROUND_DOWN
exponent = Decimal(str(10 ** - places))
return Decimal(str(number)).quantize(exponent).to_eng_string()
Primero, la función, para aquellos que solo quieren un código de copiar y pegar:
def truncate(f, n):
''''''Truncates/pads a float f to n decimal places without rounding''''''
s = ''{}''.format(f)
if ''e'' in s or ''E'' in s:
return ''{0:.{1}f}''.format(f, n)
i, p, d = s.partition(''.'')
return ''.''.join([i, (d+''0''*n)[:n]])
Esto es válido en Python 2.7 y 3.1+. Para las versiones anteriores, no es posible obtener el mismo efecto de "redondeo inteligente" (al menos, no sin un montón de código complicado), pero el redondeo a 12 lugares decimales antes del truncamiento funcionará la mayor parte del tiempo:
def truncate(f, n):
''''''Truncates/pads a float f to n decimal places without rounding''''''
s = ''%.12f'' % f
i, p, d = s.partition(''.'')
return ''.''.join([i, (d+''0''*n)[:n]])
Explicación
El núcleo del método subyacente es convertir el valor en una cadena con total precisión y luego cortar todo más allá del número deseado de caracteres. El último paso es fácil; se puede hacer con manipulación de cadenas
i, p, d = s.partition(''.'')
''.''.join([i, (d+''0''*n)[:n]])
o el módulo decimal
str(Decimal(s).quantize(Decimal((0, (1,), -n)), rounding=ROUND_DOWN))
El primer paso, la conversión a una cadena, es bastante difícil porque hay algunos pares de literales de coma flotante (es decir, lo que se escribe en el código fuente) que producen la misma representación binaria y, sin embargo, se truncarán de forma diferente. Por ejemplo, considere 0.3 y 0.29999999999999998. Si escribe 0.3
en un programa de Python, el compilador lo codifica utilizando el formato de punto flotante IEEE en la secuencia de bits (suponiendo un flotador de 64 bits)
0011111111010011001100110011001100110011001100110011001100110011
Este es el valor más cercano a 0.3 que se puede representar con precisión como un flotante IEEE. Pero si escribe 0.29999999999999998
en un programa de Python, el compilador lo traduce exactamente en el mismo valor . En un caso, quería decir que se trunca (a un dígito) como 0.3
, mientras que en el otro caso significaba que se truncaba como 0.2
, pero Python solo puede dar una respuesta. Esta es una limitación fundamental de Python, o de hecho cualquier lenguaje de programación sin evaluación diferida. La función de truncamiento solo tiene acceso al valor binario almacenado en la memoria de la computadora, no a la cadena que realmente ingresó en el código fuente. 1
Si decodifica la secuencia de bits de nuevo en un número decimal, nuevamente usando el formato IEEE de coma flotante de 64 bits, obtiene
0.2999999999999999888977697537484345957637...
por lo tanto, una implementación ingenua generaría 0.2
, aunque probablemente eso no sea lo que usted desea. Para obtener más información sobre el error de representación de coma flotante, consulte el tutorial de Python .
Es muy raro trabajar con un valor de coma flotante que esté tan cerca de un número redondo y, sin embargo, intencionalmente no sea igual a ese número redondo. Por lo tanto, al truncar, probablemente tenga sentido elegir la representación decimal "más bonita" de todas las que correspondan al valor en memoria. Python 2.7 y posteriores (pero no 3.0) incluyen un sofisticado algoritmo para hacer justamente eso , al que podemos acceder a través de la operación de formateo de cadenas por defecto.
''{}''.format(f)
La única advertencia es que esto actúa como una especificación de formato g
, en el sentido de que usa notación exponencial ( 1.23e+4
) si el número es lo suficientemente grande o pequeño. Entonces el método tiene que atrapar este caso y manejarlo de manera diferente. Hay algunos casos en los que el uso de una especificación de formato f
lugar causa un problema, como tratar de truncar 3e-10
a 28 dígitos de precisión (produce 0.0000000002999999999999999980
), y todavía no estoy seguro de cuál es la mejor manera de manejarlos.
Si realmente está trabajando con float
s que están muy cerca de los números redondos pero intencionalmente no iguales a ellos (como 0.29999999999999998 o 99.959999999999994), esto producirá algunos falsos positivos, es decir redondeará los números que no deseó redondear. En ese caso, la solución es especificar una precisión fija.
''{0:.{1}f}''.format(f, sys.float_info.dig + n + 2)
El número de dígitos de precisión que se deben usar aquí realmente no importa, solo necesita ser lo suficientemente grande como para garantizar que cualquier redondeo realizado en la conversión de cadena no "aumente" el valor de su buena representación decimal. Creo que sys.float_info.dig + n + 2
puede ser suficiente en todos los casos, pero si no fuera así, debería aumentarse 2, y no hace daño hacerlo.
En versiones anteriores de Python (hasta 2.6, o 3.0), el formato de número de punto flotante era mucho más crudo, y regularmente producía cosas como
>>> 1.1
1.1000000000000001
Si esta es su situación, si desea utilizar representaciones decimales "bonitas" para el truncamiento, todo lo que puede hacer (hasta donde yo sé) es elegir un número de dígitos, menos que la precisión completa representable mediante un float
, y redondos el número a tantos dígitos antes de truncarlo. Una elección típica es 12,
''%.12f'' % f
pero puedes ajustar esto para que se adapte a los números que estás usando.
1 Bueno ... mentí. Técnicamente, puede instruir a Python para volver a analizar su propio código fuente y extraer la parte correspondiente al primer argumento que pasa a la función de truncamiento. Si ese argumento es un literal de punto flotante, puede cortarlo en un cierto número de lugares después del punto decimal y devolverlo. Sin embargo, esta estrategia no funciona si el argumento es una variable, lo que lo hace bastante inútil. Lo siguiente se presenta solo para el valor de entretenimiento:
def trunc_introspect(f, n):
''''''Truncates/pads the float f to n decimal places by looking at the caller''s source code''''''
current_frame = None
caller_frame = None
s = inspect.stack()
try:
current_frame = s[0]
caller_frame = s[1]
gen = tokenize.tokenize(io.BytesIO(caller_frame[4][caller_frame[5]].encode(''utf-8'')).readline)
for token_type, token_string, _, _, _ in gen:
if token_type == tokenize.NAME and token_string == current_frame[3]:
next(gen) # left parenthesis
token_type, token_string, _, _, _ = next(gen) # float literal
if token_type == tokenize.NUMBER:
try:
cut_point = token_string.index(''.'') + n + 1
except ValueError: # no decimal in string
return token_string + ''.'' + ''0'' * n
else:
if len(token_string) < cut_point:
token_string += ''0'' * (cut_point - len(token_string))
return token_string[:cut_point]
else:
raise ValueError(''Unable to find floating-point literal (this probably means you called {} with a variable)''.format(current_frame[3]))
break
finally:
del s, current_frame, caller_frame
Generalizar esto para manejar el caso en el que se pasa una variable parece una causa perdida, ya que tendría que retroceder a través de la ejecución del programa hasta que encuentre el literal de punto flotante que dio valor a la variable. Si hay incluso uno. La mayoría de las variables se inicializarán a partir de la entrada del usuario o expresiones matemáticas, en cuyo caso la representación binaria es todo lo que hay.
Script de Python simple -
n = 1.923328437452
n = float(n*1000)
n /= 1000
Si te apetece algo de matemática, esto funciona para los números + ve:
>>> v = 1.923328437452
>>> v - v % 1e-3
1.923
Si te refieres a la hora de imprimir, lo siguiente debería funcionar:
print ''%.3f'' % number
Solo quería mencionar que el viejo truco de "hacer ronda () con piso ()" de
round(f) = floor(f+0.5)
se puede dar vuelta para hacer floor () de round ()
floor(f) = round(f-0.5)
Aunque ambas reglas rompen con los números negativos, entonces usarla es menos que ideal:
def trunc(f, n):
if f > 0:
return "%.*f" % (n, (f - 0.5*10**-n))
elif f == 0:
return "%.*f" % (n, f)
elif f < 0:
return "%.*f" % (n, (f + 0.5*10**-n))
También soy un novato de pitón y después de hacer uso de algunos pedazos y piezas aquí, ofrezco mis dos centavos
print str(int(time.time()))+str(datetime.now().microsecond)[:3]
str (int (time.time ())) tomará el tiempo de época como int y lo convertirá en cadena y se unirá a ... str (datetime.now (). microsecond) [: 3] que devuelve solo los microsegundos, convertir para encadenar y truncar a los primeros 3 caracteres
Tu puedes hacer:
def truncate(f, n):
return math.floor(f * 10 ** n) / 10 ** n
pruebas:
>>> f=1.923328437452
>>> [truncate(f, n) for n in range(5)]
[1.0, 1.9, 1.92, 1.923, 1.9233]
Una función general y simple de usar:
def truncate_float(number, length):
"""Truncate float numbers, up to the number specified
in length that must be an integer"""
number = number * pow(10, length)
number = int(number)
number = float(number)
number /= pow(10, length)
return number
int (16.5); esto dará un valor entero de 16, es decir, trunc, no podrá especificar decimales, pero supongo que puedes hacerlo por
import math;
def trunc(invalue, digits):
return int(invalue*math.pow(10,digits))/math.pow(10,digits);
usar numpy.round
import numpy as np
precision = 3
floats = [1.123123123, 2.321321321321]
new_float = np.round(floats, precision)
# value value to be truncated
# n number of values after decimal
value = 0.999782
n = 3
float(int(value*1en))*1e-n
def trunc(f,n):
return (''%.16f'' % f)[:(n-16)]
def trunc(num, digits):
sp = str(num).split(''.'')
return ''.''.join([sp[0], sp[1][:digits]])
Esto debería funcionar. Debería darte el truncamiento que estás buscando.
n = 1.923328437452
str(n)[:4]
round(1.923328437452, 3)
Consulte la documentación de Python sobre los tipos estándar . Tendrá que desplazarse un poco hacia abajo para acceder a la función de ronda. Esencialmente, el segundo número indica cuántos lugares decimales redondear.