Pregunta

Así que decidí intentar resolver mi tarea de física escribiendo algunos scripts de python para resolver los problemas por mí. Un problema que estoy encontrando es que las cifras significativas no siempre parecen salir bien. Por ejemplo, esto maneja cifras significativas correctamente:

from decimal import Decimal
>>> Decimal('1.0') + Decimal('2.0')
Decimal("3.0")

Pero esto no:

>>> Decimal('1.00') / Decimal('3.00')
Decimal("0.3333333333333333333333333333")

Entonces dos preguntas:

  1. ¿Tengo razón en que esta no es la cantidad esperada de dígitos significativos, o debo repasar los dígitos significativos?
  2. ¿Hay alguna forma de hacer esto sin tener que configurar la precisión decimal manualmente? Por supuesto, estoy seguro de que puedo usar numpy para hacer esto, pero solo quiero saber si hay una manera de hacerlo con el módulo decimal por curiosidad.
¿Fue útil?

Solución

Cambiar la precisión de trabajo decimal a 2 dígitos es no una buena idea, a menos que absolutamente solo vaya a realizar una sola operación.

Siempre debe realizar cálculos con mayor precisión que el nivel de importancia, y solo redondear el resultado final. Si realiza una larga secuencia de cálculos y redondea al número de dígitos significativos en cada paso, los errores se acumularán. El módulo decimal no sabe si una operación en particular es una en una secuencia larga o el resultado final, por lo que se supone que no debe redondearse más de lo necesario. Lo ideal sería utilizar una precisión infinita, pero eso es demasiado caro, por lo que los desarrolladores de Python se conformaron con 28 dígitos.

Una vez que haya llegado al resultado final, lo que probablemente desee es cuantificar:

>>> (Decimal('1.00') / Decimal('3.00')).quantize(Decimal("0.001"))
Decimal("0.333")

Tienes que hacer un seguimiento de la importancia de forma manual. Si desea un seguimiento de significación automático, debe usar aritmética de intervalos. Hay algunas bibliotecas disponibles para Python, incluidas pyinterval y mpmath (que admite precisión arbitraria). También es sencillo implementar la aritmética de intervalos con la biblioteca decimal, ya que admite el redondeo dirigido.

También puede leer el Preguntas frecuentes sobre aritmética decimal: ¿Es la aritmética decimal 'significativa' de la aritmética?

Otros consejos

Los decimales no tirarán lugares decimales como ese. Si realmente quieres limitar la precisión a 2 d.p. a continuación, intente

decimal.getcontext().prec=2

EDITAR: Alternativamente, puedes llamar a cuantizar () cada vez que multipliques o dividas (la suma y la resta conservarán los 2 dps).

Por curiosidad ... ¿es necesario usar el módulo decimal? ¿Por qué no un punto flotante con un redondeo de cifras significativas cuando estás listo para verlas? ¿O está tratando de hacer un seguimiento de las cifras significativas del cálculo (como cuando tiene que hacer un análisis de error de un resultado, calculando el error calculado en función de las incertidumbres que intervinieron en el cálculo)? Si desea una función de redondeo que redondea desde la izquierda del número en lugar de la derecha, intente:

def lround(x,leadingDigits=0): 
    """Return x either as 'print' would show it (the default) 
    or rounded to the specified digit as counted from the leftmost 
    non-zero digit of the number, e.g. lround(0.00326,2) --> 0.0033
    """ 
    assert leadingDigits>=0 
    if leadingDigits==0: 
            return float(str(x)) #just give it back like 'print' would give it
    return float('%.*e' % (int(leadingDigits),x)) #give it back as rounded by the %e format  

Los números se verán bien cuando los imprima o los convierta en cadenas, pero si está trabajando en el indicador y no los imprime explícitamente, pueden parecer un poco extraños:

>>> lround(1./3.,2),str(lround(1./3.,2)),str(lround(1./3.,4))
(0.33000000000000002, '0.33', '0.3333')

El valor predeterminado de decimales es 28 lugares de precisión.
La única forma de limitar la cantidad de dígitos que devuelve es modificando la precisión.

Si entiendo decimal correctamente, la " precisión " es el número de dígitos después del punto decimal en notación decimal .

Parece que quieres algo más: el número de dígitos significativos. Eso es uno más que el número de dígitos después del punto decimal en notación científica .

Me interesaría aprender sobre un módulo de Python que realiza cálculos de punto flotante que tienen en cuenta los dígitos significativos.

¿Qué pasa con el punto flotante?

>>> "%8.2e"%  ( 1.0/3.0 )
'3.33e-01'

Fue diseñado para cálculos de estilo científico con un número limitado de dígitos significativos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top