python - logaritmo - ¿Cuál es más exacto, x**. 5 o math.sqrt(x)?
python math gdc (9)
No tengo el mismo comportamiento. Tal vez el error es específico de la plataforma? En amd64 entiendo esto:
Python 2.5.2 (r252:60911, Mar 10 2008, 15:14:55) [GCC 3.3.5 (propolice)] on openbsd4 Type "help", "copyright", "credits" or "license" for more information. >>> import math >>> math.sqrt(8885558) - (8885558**.5) 0.0 >>> (8885558**.5) - math.sqrt(8885558) 0.0
Recientemente descubrí que x**.5
y math.sqrt(x)
no siempre producen el mismo resultado en Python:
Python 2.6.1 (r261:67517, Dec 4 2008, 16:51:00) [MSC v.1500 32 bit (Intel)]
on win32
>>> 8885558**.5 - math.sqrt(8885558)
-4.5474735088646412e-13
Al verificar todos los enteros por debajo de 10 ** 7, los dos métodos produjeron resultados diferentes para casi exactamente el 0.1% de las muestras, aumentando el tamaño del error (lentamente) para números más grandes.
Entonces, la pregunta es, ¿qué método es más preciso?
Tanto la función pow como la función math.sqrt () pueden calcular resultados que son más precisos de lo que puede almacenar el tipo de flotación predeterminado. Creo que los errores que está viendo son el resultado de las limitaciones de las matemáticas de punto flotante en lugar de las imprecisiones de las funciones. Además, ¿desde cuándo es una diferencia de ~ 10 ^ (- 13) un problema al tomar la raíz cuadrada de un número de 7 dígitos? Incluso los cálculos de física más precisos rara vez requieren muchos dígitos significativos ...
Otra razón para usar math.sqrt () es que es más fácil de leer y comprender, lo que generalmente es una buena razón para hacer las cosas de cierta manera.
En teoría, math.sqrt debería tener una mayor precisión que math.pow. Ver el método de Newton para calcular las raíces cuadradas [0]. Sin embargo, la limitación en el número de dígitos decimales del flotador de pitón (o el doble de C) probablemente ocultará la diferencia.
Esto tiene que ser una especie de cosa específica de la plataforma porque obtengo resultados diferentes:
Python 2.5.1 (r251:54863, Jan 13 2009, 10:26:13)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
>>> 8885558**.5 - math.sqrt(8885558)
0.0
¿Qué versión de python estás usando y qué sistema operativo?
Supongo que tiene algo que ver con la promoción y el casting. En otras palabras, como lo está haciendo 8885558 **. 5, 8885558 tiene que ser promovido a flotante. Todo esto se maneja de manera diferente según el sistema operativo, el procesador y la versión de Python. Bienvenido al maravilloso mundo de la aritmética de coma flotante. :-)
Ninguno de los dos es más preciso, ambos divergen de la respuesta real en partes iguales:
>>> (8885558**0.5)**2
8885557.9999999981
>>> sqrt(8885558)**2
8885558.0000000019
>>> 2**1023.99999999999
1.7976931348498497e+308
>>> (sqrt(2**1023.99999999999))**2
1.7976931348498495e+308
>>> ((2**1023.99999999999)**0.5)**2
1.7976931348498499e+308
>>> ((2**1023.99999999999)**0.5)**2 - 2**1023.99999999999
1.9958403095347198e+292
>>> (sqrt(2**1023.99999999999))**2 - 2**1023.99999999999
-1.9958403095347198e+292
http://mail.python.org/pipermail/python-list/2003-November/238546.html
El módulo matemático envuelve las funciones matemáticas de la biblioteca de la plataforma C con los mismos nombres;
math.pow()
es más útil si necesita (o solo quiere) alta compatibilidad con las extensiones C que llamanpow()
C.
__builtin__.pow()
es la implementación del operador infijo**
de Python, y trata con números complejos, potencias enteras ilimitadas y exponenciación modular también (el Cpow()
no maneja ninguno de esos).
** es más completo. math.sqrt
es probablemente solo la implementación C de sqrt, que probablemente esté relacionada con pow
.
Tengo el mismo problema contigo en Win XP Python 2.5.1, mientras que no lo hago en Gentoo Python 2.5.4 de 32 bits. Es una cuestión de implementación de la biblioteca C.
Ahora, en Win, math.sqrt(8885558)**2
da 8885558.0000000019
, mientras que (8885558**.5)**2
da 8885557.9999999981
, que parecen equivaler al mismo épsilon.
Digo que uno realmente no puede decir cuál es la opción "mejor".
Use decimal
para encontrar raíces cuadradas más precisas:
>>> import decimal
>>> decimal.getcontext().prec = 60
>>> decimal.Decimal(8885558).sqrt()
Decimal("2980.86531061032678789963529280900544861029083861907705317042")
Realicé la misma prueba y obtuve los mismos resultados, 10103 diferencias de 10000000. Esto fue usando Python 2.7 en Windows.
La diferencia es una de redondeo. Creo que cuando los dos resultados difieren, es solo un ULP la diferencia más pequeña posible para un flotador. La verdadera respuesta se encuentra entre los dos, pero un float
no tiene la capacidad de representarlo exactamente y debe ser redondeado.
Como se señala en otra respuesta, el módulo decimal
se puede utilizar para obtener una mayor precisión que un float
. Utilicé esto para tener una mejor idea del verdadero error, y en todos los casos el sqrt
fue más cercano que el **0.5
. Aunque no por mucho!
>>> s1 = sqrt(8885558)
>>> s2 = 8885558**0.5
>>> s3 = decimal.Decimal(8885558).sqrt()
>>> s1, s2, s3
(2980.865310610327, 2980.8653106103266, Decimal(''2980.865310610326787899635293''))
>>> s3 - decimal.Decimal(s1)
Decimal(''-2.268290468226740188598632812E-13'')
>>> s3 - decimal.Decimal(s2)
Decimal(''2.2791830406379010009765625E-13'')
Cada vez que se le da a elegir entre dos funciones que están integradas en un lenguaje, la función más específica casi siempre será igual o mejor que la función genérica (ya que si fuera peor, los codificadores lo habrían implementado en términos de la función genérica). Sqrt es más específico que la exponenciación genérica, por lo que puede esperar que sea una mejor opción. Y lo es, al menos en términos de velocidad. En términos de precisión, no está tratando con la precisión suficiente en sus números para poder decir.
Nota: Para aclarar, sqrt es más rápido en Python 3.0. Es más lento en las versiones anteriores de Python. Ver mediciones de JF Sebastians en cuál es más rápido en Python: x **. 5 o math.sqrt (x)? .