El día 20 de marzo de 2013 13:19, José Sabater Montes <[email protected]> escribió:
>
> Hola,
>
> El 20/03/2013, a las 11:00, Chema Cortes escribió:
>
>> Supongo que habrá una explicación. Si realizo el siguiente cálculo:
>>
>> In [13]: import math
>>
>> In [14]: math.tan(math.pi/2)
>> Out[14]: 1.633123935319537e+16
>>
>> Aunque no esperaba que me diese la solución correcta de
>> float("+inf")/float("-inf"), me resulta muy corto para el tamaño
>> máximo que podría tener un double:
>>
>> In [16]: sys.float_info.max
>> Out[16]: 1.7976931348623157e+308
>>
>> He comprobado que pasa lo mismo con scala e, incluso, en el buscador
>> de google (tal vez sea que google usa también python):
>>
>> https://www.google.com/search?q=tan(pi%2F2)
>>
>> ¿Existe alguna explicación?
>
>>>> import math
>>>> math.pi/2.
> 1.5707963267948966
>
> Aparentemente la tangente de ese número con esa precisión es exactamente esa 
> calculando con la precisión de un float.
> Para aumentar la precisión creo que hay que usar una librería que ofrezca 
> precisión arbitraria como el módulo "decimal" de la librería estándar o 
> mpmath.
> El problema con "decimal" es que no implementa funciones matemáticas un poco 
> más complejas como las trigonométricas, así que el resultado de la tangente 
> sería el mismo si se usan las mismas funciones que antes.
>
>>>> from decimal import Decimal
>>>> pi_dec = Decimal('3.1415926535897932384626433832795028841971693993751')
>>>> pi_dec
> Decimal('3.1415926535897932384626433832795028841971693993751')
>>>> pi_dec/Decimal('2')
> Decimal('1.570796326794896619231321692')
>>>> math.tan(pi_dec/Decimal('2'))
> 1.633123935319537e+16
>
> Si no me equivoco, las funciones trigonométricas se suelen calcular usando 
> series. Una buena librería de precisión arbitraria (supongo que todas) irá 
> adaptando el número de sumandos a la precisión requerida. Por ejemplo:
>
>>>> from mpmath import *
>>>> tan(1.5707963267948966)
> mpf('16331239353195370.0')
>>>> tan(pi/2)
> mpf('16331239353195370.0')
>
> Aumentamos la precisión
>
>>>> mp.dps = 50
>>>> tan(1.5707963267948966)
> mpf('16331239353195369.755967737041528916530864068104910291')
>>>> tan(pi/2)
> mpf('-1978834901269570871682051952580899049722178117311132.0')
>>>> tan(mpf('1.5707963267948966192313216916397514420985846996875534'))
> mpf('-1978834901269570871682051952580899049722178117311132.0')
>
>
>> ¿Algún modo de ajustar más el resultado a
>> infinito (sin ser la solución trivial de comprobar los parámetros de
>> entrada)?
>
> Creo que la única opción es usar un módulo matemático de precisión arbitraria 
> como mpmath o bigfloat.


Por lo que parece, la tendencia a infinito está en relación con la
precisión del cálculo. Cuanto más digitos de precisión, tanto más
grande será el número

Comprobando con mpmath:

dps    resultado aprox.
------ | -----------------------
10      390115388672.0
15      1.63312393531954e+16
50     -1.97883490126957e+51
100     6.97133053829442e+101
300     1.59802604184178e+301
1000    2.84594257232622e+1001
5000   -1.04829403956079e+5001
10000  -7.59194855601038e+10001
12000   8.19055339712727e+12001
15000   1.18530955294349e+15001
20000   1.34274677646898e+20001
30000  -1.14011942791359e+30001

El que alternen los signos supongo que será cosa del algorítmo de aproximación.


--
Hyperreals *R: http://ch3m4.org/blog
Quarks, bits y otras criaturas infinitesimales
_______________________________________________
Python-es mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/

Responder a