Haniken Linner
Haniken Linner

Reputation: 23

sine function in python gets wrong value

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

Answers (1)

E.J. White
E.J. White

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:

enter image description here

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

Related Questions