round - python truncate float
¿Cómo verifico la precisión decimal predeterminada al convertir float a str? (4)
Al observar la salida de los números aleatorios convertidos, no he podido entender cómo se determina la longitud de str()
, por ejemplo, bajo Python 3.6.6:
>>> str(.123456789123456789123456789)
''0.12345678912345678''
>>> str(.111111111111111111111111111)
''0.1111111111111111''
Puede optar por este código que realmente simula su situación real:
import random
maxdec=max(map(lambda x:len(str(x)),filter(lambda x:x>.1,[random.random() for i in range(99)])))-2
Aquí estamos probando la longitud de ~ 90 números aleatorios en el intervalo abierto (.1,1) después de la conversión (y deduciendo el 0.
de la izquierda, de ahí el -2
). Python 2.7.5 en un linux de 64 bits me da 12, y Python 3.4.8 y 3.6.6 me dan 17.
Al convertir un float
en un str
, puedo especificar el número de puntos decimales que quiero mostrar
''%.6f'' % 0.1
> ''0.100000''
''%.6f'' % .12345678901234567890
> ''0.123457''
Pero cuando simplemente se llama a str
en un float
en python 2.7, parece que el valor predeterminado es 12 puntos decimales máximo
str(0.1)
>''0.1''
str(.12345678901234567890)
>''0.123456789012''
¿Dónde se define / documenta este número máximo de puntos decimales? ¿Puedo obtener este número mediante programación?
Bueno, si estás buscando una forma de python pura para lograr esto, siempre puedes usar algo como,
len(str(.12345678901234567890).split(''.'')[1])
>>>> 12
No lo pude encontrar en la documentación y lo agregaré aquí si lo hago, pero esta es una solución que al menos siempre puede devolver la precisión si lo quiere saber de antemano.
Como dijiste, siempre parece ser 12
incluso cuando se alimentan puntos flotantes más grandes.
Por lo que pude encontrar, este número puede ser muy variable y, en estos casos, encontrarlo empíricamente parece ser la forma más confiable de hacerlo. Entonces, lo que haría es definir un método simple como este,
def max_floating_point():
counter = 0
current_length = 0
str_rep = ''.1''
while(counter <= current_length):
str_rep += ''1''
current_length = len(str(float(str_rep)).split(''.'')[1])
counter += 1
return current_length
Esto le devolverá la representación de longitud máxima en su sistema actual,
print max_floating_point()
>>>> 12
El número de decimales que se muestra va a variar mucho, y no habrá una manera de predecir cuántos se mostrarán en Python puro. Algunas bibliotecas como numpy
permiten establecer la precisión de la salida.
Esto es simplemente debido a las limitaciones de la representación flotante .
Las partes relevantes del enlace hablan sobre cómo Python elige mostrar flotantes.
Python solo imprime una aproximación decimal al valor decimal verdadero de la aproximación binaria almacenada por la máquina
Python mantiene el número de dígitos manejables al mostrar un valor redondeado en su lugar
Ahora, existe la posibilidad de superposición aquí:
Curiosamente, hay muchos números decimales diferentes que comparten la misma fracción binaria aproximada más cercana
El método para elegir qué valores decimales se mostrarán se cambió en Python 3.1 (pero la última oración implica que esto podría ser un detalle de implementación).
Por ejemplo, los números 0.1 y 0.10000000000000001 se aproximan en 3602879701896397/2 ** 55. Dado que todos estos valores decimales comparten la misma aproximación, cualquiera de ellos podría mostrarse mientras se conserva la evaluación invariante (repr (x)) = = x
Históricamente, el indicador de Python y la función repr () incorporada elegirían la que tiene 17 dígitos significativos, 0.10000000000000001. A partir de Python 3.1, Python (en la mayoría de los sistemas) ahora puede elegir el más corto de estos y simplemente mostrar 0.1.
No creo que esto exista en la especificación del lenguaje python. Sin embargo, la implementación de cpython sí lo especifica. La función float_repr()
, que convierte un float en una cadena, eventualmente llama a una función auxiliar con el formateador ''r''
, que eventualmente llama a una función de utilidad que codifica el formato a lo que se reduce al format(float, ''.16g'')
. Ese código se puede ver here . Tenga en cuenta que esto es para python3.6.
>>> import math
>>> str(math.pi*4)
12.5663706144
dando el número máximo de dígitos de significación (tanto antes como después del decimal) en 16. Parece que en la implementación de python2.7, este valor fue codificado en .12g
. En cuanto a por qué sucedió esto (y falta algo de documentación, se puede encontrar here ).
Entonces, si está tratando de obtener la longitud del formato de un número cuando se imprima, simplemente obtenga su longitud con .12g
.
def len_when_displayed(n):
return len(format(n, ''.12g''))