c_url215
c_url215

Reputation: 17

Python: define a function to calculate sin(x)

I have to define a function for calculating sin(), and the program will expand the series until the absolute value of the next term in the series is less than 1.0e-7 using this expression:

Expressing the Function sin x as a Series

This is what I got so far but I know it's way off:

number = input("\n\tEnter X: ")
x_flt = float(number)
x_int = int(x_flt)
x_approx = 0
for i in range(1, x_int+1):
    factor = x_flt * i
def approximate_sin(x):
    '''Insert docstring here.'''
    for a in range():
        x_approx = (-1 ** a * x ** (2 * a + 1)) / factor
    return x_approx
print("\n\tApproximation: {:.10f}".format(float(approximate_sin(x_flt))))

Upvotes: 1

Views: 1975

Answers (4)

blueteeth
blueteeth

Reputation: 3565

Given this is an infinite series, you could create a generator that given x provides the next evaluation by incrementing n each time.

from math import factorial, pow

def sin_gen(x):
    n = 0
    while True:
        result = (pow(-1, n) * pow(x, (2 * n + 1))) / factorial(2 * n + 1)
        yield result
        n += 1

Now you just need to sum each evaluation until the total is as you want.

g = sin_gen(x)
total = 0

for val in g: 
    if abs(val) < 1.0e-7: 
        break 
    total += val

print(total)

Upvotes: 2

kaya3
kaya3

Reputation: 51132

Here's how I would do it, which uses the formula but not directly.

  • (-1) ** n is the previous value multiplied by -1.
  • x ** (2n + 1) is the previous value multiplied by x * x.
  • (2n + 1)! is the previous value multiplied by 2n * (2n + 1).

This means your loop does no power or factorial calculations, which is a bit more efficient. Here it is in Python:

def approx_sin(x, eps=1e-7):
    term = x
    two_n = 0
    total = 0

    while abs(term) >= eps:
        total += term
        two_n += 2
        term *= -x * x / (two_n * (two_n + 1))

    return total

Upvotes: 2

Patrick Haugh
Patrick Haugh

Reputation: 61042

Be careful of -1 ** n, it isn't parsed as you would expect. ** binds more tightly than unary - (has higher precedence) so this expression is parsed like -(1 ** n). Similar to blueteeths solution, I would do something like

from math import factorial, pow
from itertools import takewhile, count

large = lambda y: abs(y) > 1e-7

def sin_gen(x):
    for n in count():
        yield (pow(-1, n) * pow(x, (2 * n + 1))) / factorial(2 * n + 1)


def sin(x):
    return sum(takewhile(large, sin_gen(x)))

print(sin(5))  # -0.9589242932128198

Upvotes: 3

Raymond Hettinger
Raymond Hettinger

Reputation: 226604

Hints:

  • Add a value to range(n). Ten iterations would be a good start.
  • For x_approx use += instead of =.
  • Perhaps look at a worked-out example in the docs.

Upvotes: 1

Related Questions