Fun with series

On #perl6 this morning, rokoteko was curious about doing Taylor series in Perl 6. This sort of thing fascinates me, so I quickly coded up this:

sub sine-power($x) { 
    my $sign = 1; 
    gather for 1, 3 ... * -> $n { 
        take $sign * $x ** $n / [*] (1 ... $n); 
        $sign *= -1; 
    } 
}

That works, and is pretty straightforward. However, it’s got one big glitch in it, IMO. Even if you feed it a Rat input, it will always return a list of Nums, because $x ** $n returns a Num. (Hmmm…. might that be worth changing?)

No problem, you just need to complicate the function a bit by keeping running products for the numerator and denominator:

sub sine-power($x) { 
    my $sign = 1;
    my $x-part = $x;
    my $denom = 1;
    gather for 3, 5 ... * -> $n {
        take $sign * $x-part / $denom;
        $sign *= -1;
        $x-part *= $x * $x;
        $denom *= $n * ($n - 1);
    } 
} 

As a bonus, the new version should be faster.

Let’s see if it works:

> say sine-power(0.1).munch(4).perl;
(1/10, -1/6000, 1/12000000, -1.98412698412698e-11)

> say ([+] sine-power(0.1).munch(3)).perl;
1198001/12000000

> say [+] sine-power(0.1).munch(3);
0.0998334166666667

say sin(0.1);
0.0998334166468282

As you can see, this generates a Rat approximation for sin(0.1) which is accurate to 10 decimal places. Not bad!

Leave a comment