Necesito redondear un flotador para que se muestre en una interfaz de usuario. Por ejemplo, a una cifra 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 Python, o tengo que escribirlo yo mismo?
Respuestas:
Puede usar números negativos para redondear enteros:
Por lo tanto, si solo necesita el dígito más significativo:
Probablemente tenga que encargarse de convertir el flotador en entero si es mayor que 1.
fuente
log10
es la única forma adecuada de determinar cómo redondearlo.log10(abs(x))
, de lo contrario los números negativos fallarán (y tratarán porx == 0
separado, por supuesto)round_to_n = lambda x, n: x if x == 0 else round(x, -int(math.floor(math.log10(abs(x)))) + (n - 1))
protegex==0
yx<0
gracias @RoyHyunjinHan y @TobiasKienzler. No protege contra indefinidos como math.inf o basura como None, etc.% g en el formato de cadena formateará un flotante redondeado a un número de cifras significativas. A veces usará la notación científica 'e', por lo tanto, vuelva a convertir la cadena redondeada en flotante mediante el formato de cadena% s.
fuente
0.075
a0.08
. Regresa en su0.07
lugar.round_sig = lambda f,p: float(('%.' + str(p) + 'e') % f)
le permite ajustar la cantidad de dígitos significativos!Si desea tener otro decimal distinto de 1 (de lo contrario, lo mismo que Evgeny):
fuente
0.075
a0.08
. Regresa en su0.07
lugar.round
. docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issuesEsta solución es diferente de todas las demás porque:
Para un número arbitrario
n
de cifras significativas, puede usar:Prueba:
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 proporcionadas en el paquete de precisión .fuente
:g
formateador que preserva los enteros.2000.0
sugiere 5 dígitos significativos, por lo que tiene que pasar de{:g}
nuevo.) En general, los enteros con ceros finales son ambiguos con respecto a las cifras significativas, a menos que se utilice alguna técnica (como el renglón anterior al último significativo).He creado el paquete con precisión que hace lo que quieres. Le permite dar a sus 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.
Eso realmente especifica 8 higos sig. Para el número 1234243, mi biblioteca solo muestra una cifra significativa:
También redondeará la última cifra significativa y puede elegir automáticamente qué notación usar si no se especifica una notación:
fuente
lambda x: to_precision(x, 2)
Para redondear un número entero a 1 cifra significativa, la idea básica es convertirlo a un punto flotante con 1 dígito antes del punto y redondearlo, luego convertirlo nuevamente 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 el piso de la función log 10 para esto.
fuente
Para responder directamente a la pregunta, aquí está mi versión usando nombres de la función R :
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":
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:
que debería imprimirse
0.075
.16**13
es porque hay 13 dígitos hexadecimales después del punto decimal, y2**-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:dando:
0.07499999999999999722444243844
y con suerte explicando por quéround(0.075, 2)
evalúa a0.07
fuente
0.074999999999999999
, lo que se puede esperar para conseguir en ese caso?Con suerte, tomando la mejor de todas las respuestas anteriores (menos poder ponerlo como una lambda de una línea;)). Todavía no lo he explorado, siéntase libre de editar esta respuesta:
fuente
Modifiqué la solución de indgar para manejar números negativos y números pequeños (incluido cero).
fuente
x == 0
? Si amas una frase, soloreturn 0 if x==0 else round(...)
.0.970 == 0.97
). Creo que podría usar algunas de las otras soluciones de impresión, comof'{round_sig(0.9701, sig=3):0.3f}'
si quisiera imprimir el cero.Si desea redondear sin involucrar cadenas, el enlace que encontré enterrado en los comentarios anteriores:
http://code.activestate.com/lists/python-tutor/70739/
me parece lo 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 tiene tres líneas: def, doc y return. Tiene un error: debe verificar la existencia de logaritmos explosivos. Eso es fácil. Compare la entrada a
sys.float_info.min
. La solución completa es:Funciona para cualquier valor numérico escalar, y n puede ser un
float
si necesita cambiar la respuesta por alguna razón. En realidad, puede empujar el límite para:sin provocar un error, si por alguna razón está trabajando con valores minúsculos.
fuente
No puedo pensar en nada que pueda manejar esto fuera de la caja. Pero está bastante bien manejado para números de coma flotante.
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. Sin embargo, es bastante trivial implementar una vez que son una cadena.
O para enteros:
Si desea crear una función que maneje cualquier número, mi preferencia sería convertirlos en cadenas y buscar un lugar decimal para decidir qué hacer:
Otra opción es verificar el tipo. Esto será mucho menos flexible y probablemente no jugará bien con otros números como los
Decimal
objetos:fuente
La respuesta publicada fue la mejor disponible cuando se dio, pero tiene una serie de limitaciones y no produce cifras significativas técnicamente correctas.
numpy.format_float_positional admite el comportamiento deseado directamente. El siguiente fragmento devuelve el flotador
x
formateado a 4 cifras significativas, con la notación científica suprimida.fuente
print(*[''.join([np.format_float_positional(.01*a*n,precision=2,unique=False,fractional=False,trim='k',pad_right=5) for a in [.99, .999, 1.001]]) for n in [8,9,10,11,12,19,20,21]],sep='\n')
. No revisé Dragon4 en sí mismo.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 tener en cuenta el valor, el tipo de redondeo y los dígitos significativos deseados.
fuente
Usando el formato de estilo nuevo de Python 2.6+ (ya que el estilo% está en desuso):
En python 2.7+ puedes omitir los
0
s principales .fuente
Esta función realiza una ronda normal si el número es mayor que 10 ** (- decimales_posiciones), de lo contrario agrega más decimales hasta que se alcanza el número de posiciones decimales significativas:
Espero eso ayude.
fuente
https://stackoverflow.com/users/1391441/gabriel , ¿aborda lo siguiente su preocupación sobre rnd (.075, 1)? Advertencia: devuelve el valor como flotante
fuente
Esto devuelve una cadena, de modo que los resultados sin partes fraccionarias, y los valores pequeños que de otro modo aparecerían en la notación E se muestran correctamente:
fuente
Ante una pregunta tan bien respondida, ¿por qué no agregar otra?
Esto se adapta un poco mejor a mi estética, aunque muchos de los anteriores son comparables
Esto funciona para números individuales y matrices numpy, y debería funcionar bien para números negativos.
Hay un paso adicional que podríamos agregar: np.round () devuelve un número decimal incluso si redondeado es un entero (es decir, para cifras significativas = 2 podríamos esperar obtener -460, pero en su lugar obtenemos -460.0). Podemos agregar este paso para corregir eso:
Desafortunadamente, este paso final no funcionará para una variedad de números; se lo dejaré a usted, querido lector, para que lo descubra si lo necesita.
fuente
El paquete / biblioteca sigfig cubre esto. Después de la instalación , puede hacer lo siguiente:
fuente
fuente