Programs to Compute Trig Functions in Python, JavaScript, & Perl (with Maclaurin Series)

  • December 31, 2020

  • 5 min read

Introduction

Have you ever wondered how your computer calculates certain mathematical functions, like division, or trigonometric functions like sine or cosine? Well, for some of these mathematical functions, there exist useful formulas to calculate very accurate results pretty easily. For sine and cosine, one commonly used formula looks like this:

Maclaurin Series of sin(x)

And for cosine:

Maclaurin Series of cos(x)

Note that the input of each function is in radians, not degrees.

The series used in both formulas is called a Maclaurin series (a type of Taylor series), and can be derived from the sine and cosine functions with a series expansion.

How the Programs Work

I've written programs to implement these two computations in three major scripting languages: Python, JavaScript, and Perl. These programs do not include any built-in trig functions or other utilities except the use of the in-built π constant in some cases. All code is CC0 licensed.

The approach I used creates a generalized function called computeSeries which takes in x as the number to calculate the sine or cosine of, a starting number in the series (x for sine and 1 for cosine), and the exponent and factorial base in the first term of the series (3 for sine and 2 for cosine).

In calculating each series, I found that only about 10 terms in the series were needed to get a decently accurate result.

The programs additionally include utility functions for sine and cosine functions in degrees. The end of each program also includes a few tests of each function, which work as expected.

In Python

Feel free to view the below code as a GitHub Gist.

from math import pi

# round a number (x) to nearest 10 digits
def rounded(x):
    return round(x, 10)

# get the factorial of a number (x)
# factorial(x) is the product of every number from 1 to N inclusive
def factorial(x):
    n = 1; # n is the result
    # multiply n by every number from 1 to x inclusive
    for i in range(2, x + 1):
        n *= i
    return n

""" get the result of the cos and sin formulas
    where the functions are sin(x radians) or cos(x radians),
    n is the start value (n = x for sin, n = 1 for cos), and
    i_start is the exponent and factorial base in the first term """
def computeSeries(x, n, i_start):
    iterations = 20 # iterations is twice the amount of terms to use
    multiplier = 1
    for i in range(i_start, i_start + iterations, 2): # i increases by 2 each term
        multiplier *= -1 # alternates between addition and subtraction each term
        next_term = (x**i) / factorial(i) # each term is (x^i) / i!
        n += multiplier * next_term # add or subtract from final result
    return n

# get sin of x radians
def sin(x):
    return rounded(computeSeries(x, x, 3))

# get cos of x radians
def cos(x):
    return rounded(computeSeries(x, 1, 2))

# get sin of x degrees
def sinDeg(x):
    return sin(x * pi / 180)

# get cos of x degrees
def cosDeg(x):
    return cos(x * pi / 180)

# test the functions
print(sin(pi / 6)); # 0.5
print(sinDeg(45)); # 0.7071
print(sinDeg(52)); # 0.78801

print(cos(pi / 3)); # 0.5
print(cosDeg(45)); # 0.7071
print(cosDeg(52)); # 0.615661

In JavaScript

Feel free to view the below code as a GitHub Gist.

// round a number (x) to nearest 10 digits
const rounded = (x) => {
    return parseFloat(x.toFixed(10));
}

// get the factorial of a number (x)
// factorial(x) is the product of every number from 1 to x inclusive
const factorial = (x) => {
    let n = 1; // n is the result
    // multiply n by every number from 1 to x inclusive
    for(let i = 2; i <= x; i++) {
        n *= i;
    }
    return n;
}

/* get the result of the cos and sin formulas
   where the functions are sin(x radians) or cos(x radians),
   n is the start value (x for sin, 1 for cos), and i_start
   is the exponent and factorial base in the first term */
const computeSeries = (x, n, i_start) => {
    const iterations = 20; // iterations is twice the amount of terms to use
    let multiplier = 1;
    let i = i_start;
    while(i < i_start + iterations) {
        multiplier *= -1; // alternates between addition and subtraction each iteration
        const next_term = (x**i) / factorial(i); // each term is (x^i) / i!
        n += multiplier * next_term // add or subtract from final result
        i += 2 // i increases by 2 each term
    }
    return n
}

// get sin of x radians
const sin = (x) => {
    return rounded(computeSeries(x, x, 3));
}
// get cos of x radians
const cos = (x) => {
    return rounded(computeSeries(x, 1, 2));
}
// get sin of x degrees
const sinDeg = (x) => {
    return sin(x * Math.PI / 180);
}
// get cos of x degrees
const cosDeg = (x) => {
    return cos(x * Math.PI / 180);
}

// test the functions
console.log(sin(Math.PI / 6)); // 0.5
console.log(sinDeg(45)); // 0.7071
console.log(sinDeg(52)); // 0.78801

console.log(cos(Math.PI / 3)); // 0.5
console.log(cosDeg(45)); // 0.7071
console.log(cosDeg(52)); // 0.615661

In Perl

Feel free to view the below code as a GitHub Gist.

#!/usr/bin/perl
use warnings;

$pi = 3.14159265358979323;

# get the factorial of a number (x)
# factorial(x) is the product of every number from 1 to N inclusive
sub factorial {
    my ($x) = @_;
    my $n = 1; # n is the result
    # multiply n by every number from 1 to x inclusive
    my @nums_to_multiply = (1..$x);
    for(@nums_to_multiply){
        $n *= $_;
    }
    return $n;
}

=begin
get the result of the cos and sin formulas
where the functions are sin(x radians) or cos(x radians),
n is the start value (n = x for sin, n = 1 for cos), and
i_start is the exponent and factorial base in the first term
=cut
sub computeSeries {
    $ITERATIONS = 20; # iterations is twice the amount of terms to use
    my ($x, $n, $i_start) = @_;
    my $multiplier = 1;
    $i = $i_start;
    while($i < $i_start + $ITERATIONS) {
        $multiplier *= -1; # alternates between addition and subtraction each term
        $n += $multiplier * (($x**$i) / factorial($i)); # add or subtract ((x^i) / i!) from final result
        $i += 2; # i increases by 2 each term
    }
    return $n;
}

# get sin of x radians
sub mySin {
    my ($x) = @_;
    return computeSeries($x, $x, 3);
}
# get cos of x radians
sub myCos {
    my ($x) = @_;
    return computeSeries($x, 1, 2);
}
# get sin of x degrees
sub sinDeg {
    my ($x) = @_;
    return mySin($x * $pi / 180);
}
# get cos of x degrees
sub cosDeg {
    my ($x) = @_;
    return myCos($x * $pi / 180);
}

# test the functions
print(sin($pi / 6) . "\n"); # 0.5
print(sinDeg(45)   . "\n"); # 0.7071
print(sinDeg(52)   . "\n"); # 0.78801

print(cos($pi / 3) . "\n"); # 0.5
print(cosDeg(45)   . "\n"); # 0.7071
print(cosDeg(52)   . "\n"); # 0.615661

Conclusion

I hope this helps in understanding how computers and languages would go about calculating trigonometric functions like sine and cosine. If you'd like to read more about how exactly mathematical formulas used to calculate the trig functions are derived, I would recommend taking a look at the videos on Taylor and Maclaurin series by Khan Academy.

These programs are all licensed under CC0, so feel free to use any of the code as you wish, without attribution.

Thanks for scrolling.

— Gabriel Romualdo, December 31, 2020