Para responder directamente a la pregunta, aquí está mi versión usando nombres de la función R :
import math
def signif(x, digits=6):
if x == 0 or not math.isfinite(x):
return x
digits -= math.ceil(math.log10(abs(x)))
return round(x, digits)
Mi razón principal para publicar esta respuesta son los comentarios quejándose de que "0.075" se redondea a 0.07 en lugar de 0.08. Esto se debe, como lo señaló "Novato C", a una combinación de aritmética de coma flotante que tiene precisión finita y una representación de base 2 . El número más cercano a 0.075 que puede representarse realmente es un poco más pequeño, por lo tanto, el redondeo sale de manera diferente de lo que cabría esperar ingenuamente.
También tenga en cuenta que esto se aplica a cualquier uso de aritmética de coma flotante no decimal, por ejemplo, C y Java tienen el mismo problema.
Para mostrar con más detalle, le pedimos a Python que formatee el número en formato "hexadecimal":
0.075.hex()
lo que nos da: 0x1.3333333333333p-4
. La razón para hacer esto es que la representación decimal normal a menudo implica redondeo y, por lo tanto, no es cómo la computadora realmente "ve" el número. Si no está acostumbrado a este formato, un par de referencias útiles son las documentación de Python y el C estándar .
Para mostrar cómo funcionan un poco estos números, podemos volver a nuestro punto de partida haciendo lo siguiente:
0x13333333333333 / 16**13 * 2**-4
que debería imprimirse 0.075
. 16**13
es porque hay 13 dígitos hexadecimales después del punto decimal, y 2**-4
es porque los exponentes hexadecimales son base-2.
Ahora tenemos una idea de cómo se representan los flotadores, podemos usar el decimal
módulo para darnos más precisión, mostrándonos lo que está sucediendo:
from decimal import Decimal
Decimal(0x13333333333333) / 16**13 / 2**4
dando: 0.07499999999999999722444243844
y con suerte explicando por qué round(0.075, 2)
evalúa a0.07