Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Maclaurin/Taylor Series Calculation of Sin and Cos in Perl
#!/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
@shixilun

This comment has been minimized.

Copy link

@shixilun shixilun commented Jan 4, 2021

The implementation is correct but horribly inefficient.

@druud

This comment has been minimized.

Copy link

@druud druud commented Jan 4, 2021

To compare:

perl -Mstrict -MList::Util=reduce -wE'
  use constant PI => atan2(1,0) * 2;
  sub _c {
    my ( $x, $n, $m )= @_;
    $x+= 2*PI while $x < 0;
    $x-= 2*PI while 2*PI <= $x;
    my $x2= $x * $x;
    $n//= $x;
    my $s= my $d= 1;
    reduce { $a + ($s*= -1) * ($n*= $x2) / ($d*= 2*$b*(2*$b+$m) ) } $n, 1..10;
  }
  sub LU_sin { _c shift, undef, 1 }
  sub LU_cos { _c shift, 1, -1 }
  for ( 2, 3, 4, 6 ) {
    my $x= PI / $_;              
    say "sin(PI/$_)=", LU_sin( $x );
    say "cos(PI/$_)=", LU_cos( $x );
  }
'
sin(PI/2)=1
cos(PI/2)=6.09227631828637e-17
sin(PI/3)=0.866025403784438
cos(PI/3)=0.5
sin(PI/4)=0.707106781186547
cos(PI/4)=0.707106781186547
sin(PI/6)=0.5
cos(PI/6)=0.866025403784439
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment