Formal power series: Difference between revisions
Content added Content deleted
m (→{{header|Racket}}: s->z in Lazy) |
(Added Perl Implementation) |
||
Line 1,093: | Line 1,093: | ||
<lang parigp>sin('x) |
<lang parigp>sin('x) |
||
cos('x)</lang> |
cos('x)</lang> |
||
=={{header|Perl}}== |
|||
Although true Lazy Lists *can* be implemented using perl (using the builtin "tie" function), I felt that doing so would make the example harder to understand. |
|||
Instead, I chose to implement delayed evaluation with a generator function and a cache. |
|||
Creating a new arithmetic type in perl is relatively easy, using the "overload" module which comes with perl. |
|||
This was partly inspired by the perl6 example, but is far from being a direct translation. |
|||
<lang perl> |
|||
package FPS; |
|||
use strict; |
|||
use warnings; |
|||
use Math::BigRat; |
|||
sub new { |
|||
my $class = shift; |
|||
return bless {@_}, $class unless @_ == 1; |
|||
my $arg = shift; |
|||
return bless { more => $arg }, $class if 'CODE' eq ref $arg; |
|||
return bless { coeff => $arg }, $class if 'ARRAY' eq ref $arg; |
|||
bless { coeff => [$arg] }, $class; |
|||
} |
|||
sub coeff { |
|||
my ($self, $i) = @_; |
|||
my $cache = ($self->{coeff} ||= []); |
|||
my $more = $self->{more}; |
|||
for my $j ( @$cache .. $i ) { |
|||
last unless $more; |
|||
$cache->[$j] = $more->($j, $self); |
|||
} |
|||
$cache->[$i] or 0; |
|||
} |
|||
sub invert { |
|||
my $orig = shift; |
|||
ref($orig)->new( sub { |
|||
my ($i, $self) = @_; |
|||
unless( $i ) { |
|||
my $a0 = $orig->coeff(0); |
|||
die "Cannot invert power series with zero constant term." |
|||
unless $a0; |
|||
(Math::BigRat->new(1) / $a0); |
|||
} else { |
|||
my $sum = 0; |
|||
my $terms = $self->{coeff}; |
|||
for my $j (1 .. $i) { |
|||
$sum += $orig->coeff($j) * $terms->[$i - $j]; |
|||
} |
|||
-$terms->[0] * $sum; |
|||
} |
|||
} ); |
|||
} |
|||
sub fixargs { |
|||
my ($x, $y, $swap) = @_; |
|||
my $class = ref $x; |
|||
$y = $class->new($y) unless UNIVERSAL::isa($y, $class); |
|||
($x, $y) = ($y, $x) if $swap; |
|||
($class, $x, $y); |
|||
} |
|||
use overload '+' => sub { |
|||
my ($class, $x, $y) = &fixargs; |
|||
$class->new( sub { $x->coeff($_[0]) + $y->coeff($_[0]) } ); |
|||
}, '-' => sub { |
|||
my ($class, $x, $y) = &fixargs; |
|||
$class->new( sub { $x->coeff($_[0]) - $y->coeff($_[0]) } ); |
|||
}, '*' => sub { |
|||
my ($class, $x, $y) = &fixargs; |
|||
$class->new( sub { |
|||
my $i = shift; |
|||
my $sum = 0; |
|||
$sum += $x->coeff($_) * $y->coeff($i-$_) for 0..$i; |
|||
$sum; |
|||
} ); |
|||
}, '/' => sub { |
|||
my ($class, $x, $y) = &fixargs; |
|||
$x * $y->invert; |
|||
}, '""' => sub { |
|||
my $self = shift; |
|||
my $str = $self->coeff(0); |
|||
for my $i (1..10) { |
|||
my $c = $self->coeff($i); |
|||
next unless $c; |
|||
$str .= ($c < 0) ? (" - " . (-$c)) : (" + ".$c); |
|||
$str .= "x^$i"; |
|||
} |
|||
$str; |
|||
}; |
|||
sub differentiate { |
|||
my $orig = shift; |
|||
ref($orig)->new( sub { |
|||
my $i = shift; |
|||
($i+1) * $orig->coeff($i); |
|||
} ); |
|||
} |
|||
sub integrate { |
|||
my $orig = shift; |
|||
ref($orig)->new( coeff => [0], more => sub { |
|||
my $i = shift; |
|||
$orig->coeff($i-1) / Math::BigRat->new($i); |
|||
} ); |
|||
} |
|||
my $sin = __PACKAGE__->new; |
|||
my $cos = 1 - $sin->integrate; |
|||
%$sin = %{$cos->integrate}; |
|||
my $tan = $sin / $cos; |
|||
my $exp = __PACKAGE__->new(); |
|||
%$exp = (%{$exp->integrate}, coeff => [1]); |
|||
print "sin(x) ~= $sin\n"; |
|||
print "cos(x) ~= $cos\n"; |
|||
print "tan(x) ~= $tan\n"; |
|||
print "exp(x) ~= $exp\n"; |
|||
print "sin^2 + cos^s = ", $sin*$sin + $cos*$cos, "\n"; |
|||
1; |
|||
__END__ |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
sin(x) ~= 0 + 1x^1 - 1/6x^3 + 1/120x^5 - 1/5040x^7 + 1/362880x^9 |
|||
cos(x) ~= 1 - 1/2x^2 + 1/24x^4 - 1/720x^6 + 1/40320x^8 - 1/3628800x^10 |
|||
tan(x) ~= 0 + 1x^1 + 1/3x^3 + 2/15x^5 + 17/315x^7 + 62/2835x^9 |
|||
exp(x) ~= 1 + 1x^1 + 1/2x^2 + 1/6x^3 + 1/24x^4 + 1/120x^5 + 1/720x^6 + 1/5040x^7 + 1/40320x^8 + 1/362880x^9 + 1/3628800x^10 |
|||
sin^2 + cos^s = 1 |
|||
</pre> |
|||
=={{header|Perl 6}}== |
=={{header|Perl 6}}== |