Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I avoid catastrophic cancellation for small numbers in f(x) = (1-cos(x))/x**2 in Python 3.7?

How do I avoid catastrophic cancellation for small numbers in f(x) = (1-cos(x))/x**2 in Python 3.7?

This is what I tried so far (the key, I know, is some trigonometric identity that enables you to avoid the cancellation, and I also know, having used L'Hopital's rule, that the limit→0 for f(x) is 0.5, so the correct program output is something very close to 0.5, which is what you do get if you use x = 1.2e-4 for example, but you get cancellation with smaller numbers like 1.2e-8, and I need to make it so this doesn't happen).

from math import *
def f(x):     #these are all the same function using different identities  
   a = (1-(sin(x)/tan(x)))/(x**2)
   b = (1-(sin(2*x)/(2*sin(x))))/(x**2)
   c = (1-((1-((tan(x/2))**2))/(1+(tan(x/2))**2)))/(x**2)
   d = (sin(x)**2+cos(x)**2-cos(x))/(x**2)
   e = (sin(x)**2+cos(x)**2-(sin(2*x)/(2*sin(x))))/(x**2)
   return a, b, c, d, e

print(k(1.2e-8))
#Output: (0.0, 0.7709882115452477, 0.0, 0.0, 0.0) - whereas need 0.5000...
like image 600
Corwin of Amber Avatar asked Nov 16 '25 09:11

Corwin of Amber


1 Answers

Like this:

sin(x)/x * tan(x/2)/x

It does the job right up to the end, x = 1e-308 is still OK.

Unfortunately I cannot offer much insight into why it works well.

like image 150
harold Avatar answered Nov 18 '25 21:11

harold