Reputation: 23
def sin_x(b):
a = b
if a=="pi" or a=="π":
return 0
else:
x=float(a)
return sin_function(x)
def factorial(b):
if b==0:
out=1
else:
out=1
for i in range(1,b+1):
out*=(i)
i+=1
return out
def sin_function(X):
k=0
sin=0
last_term=(((-1)**k)*(X**(2*k+1)))/factorial(2*k+1)
while abs(last_term)>1*10**(-8):
sin+=last_term
k+=1
last_term=(((-1)**k)*(X**(2*k+1)))/factorial(2*k+1)
return sin
print (sin_x(50))
hello, I'm trying to build a sine function that gives exactly the same value as a calculator without implementing the math function. The main issue I have right now is that whenever the input is bigger than 35, the function starts to give the false value, and several exceptions if I keep increasing the input value. Can someone modify it to make it works exactly as a calculator? (it takes radians as input)
Upvotes: 1
Views: 393
Reputation: 104
I see several possible reasons, the first of which is that the commonly known Taylor expansion for sin(x) is only valid around the origin, more specifically the range [-pi, +pi]. This figure explains why:
Of course, you could shift the Taylor expansion to be based around any point, but it's probably more intuitive to just map the input radians into a value that falls within the above range, e.g. 5*pi/2 should map to pi/2. The following Python code does this:
PI = 3.141592653589793
x = 5*PI/2
pi_factor = int(x / PI)
adj = pi_factors if pi_factor%2 == 0 else pi_factor + 1
rad = x - PI*adj
print(rad)
1.5707963267948966
Next up, your factorial function returns an int, which can lead to unexpected behavior when dividing. To be safe, make it return a float:
return out*1.0
Lastly, I'm not sure what you're trying to do, but the Taylor expansion is simple. Take a look at the expansion for sine on the first page of this tutorial. I've implemented my own version below, which uses your factorial function:
def sin_function(x):
# Doing this instead of math.abs
sym_fact = -1 if x < 0 else 1
y = -x if x < 0 else x
# convert input radians to [-PI, +PI]
PI = 3.141592653589793
pi_factor = int(y / PI)
adj = pi_factor if pi_factor%2 == 0 else pi_factor + 1
rad = y - PI*adj
# Taylor expand, increase num_terms for more precision
total = 0
num_terms = 7
f_sign = 1
for i in range(1,2*num_terms+1,2):
total += f_sign * pow(rad, i)/factorial(i)
f_sign *= -1
return total*sym_fact
The first two lines are exploiting the fact that sin(-x) = -sin(x). I avoided using math.abs() to keep it "pure" Python. If that's not a restriction for you, then the code can be simplified a little with math.abs() and math.pi. Also, you can increase the precision by increasing the number of terms used in the Taylor expansion (currently set to 7). Hope this helps.
Upvotes: 2