File Coverage

blib/lib/Math/Derivative.pm
Criterion Covered Total %
statement 14 51 27.4
branch 0 8 0.0
condition n/a
subroutine 5 7 71.4
pod 2 2 100.0
total 21 68 30.8


line stmt bran cond sub pod time code
1             # functions for calculating derivatives of data
2             # $Id: Derivative.pm,v 1.1 1995/12/26 16:26:59 willijar Exp $
3             =head1 NAME
4              
5             Math::Derivative - Numeric 1st and 2nd order differentiation
6              
7             =head1 SYNOPSIS
8              
9             use Math::Derivative qw(Derivative1 Derivative2);
10              
11             @dydx = Derivative1(\@x, \@y);
12             @d2ydx2 = Derivative2(\@x, \@y);
13             @d2ydx2 = Derivative2(\@x, \@y, $yp0, $ypn);
14              
15             =head1 DESCRIPTION
16              
17             This Perl package exports functions for performing numerical first
18             (B) and second B) order differentiation on
19             vectors of data.
20              
21             =head2 FUNCTIONS
22              
23             The functions must be imported by name.
24              
25             =head3 Derivative1()
26              
27             Take the references to two arrays containing the x and y ordinates of
28             the data, and return an array of the 1st derivative at the given x ordinates.
29              
30             =head3 Derivative2()
31              
32             Take references to two arrays containing the x and y ordinates of the
33             data and return an array of the 2nd derivative at the given x ordinates.
34              
35             You may optionally give values to use as the first dervivatives at the
36             start and end points of the data. If you don't, first derivative values
37             will be calculated from the arrays for you.
38              
39             =head1 AUTHOR
40              
41             John A.R. Williams B
42             John M. Gamble B (current maintainer)
43              
44             =cut
45              
46             package Math::Derivative;
47              
48 1     1   21344 use 5.8.3;
  1         4  
49 1     1   6 use Exporter;
  1         1  
  1         113  
50             our(@ISA, @EXPORT_OK);
51             @ISA = qw(Exporter);
52             @EXPORT_OK = qw(Derivative1 Derivative2);
53              
54             our $VERSION = 0.04;
55              
56 1     1   7 use strict;
  1         11  
  1         30  
57 1     1   5 use warnings;
  1         2  
  1         40  
58 1     1   6 use Carp;
  1         1  
  1         602  
59              
60             sub Derivative1
61             {
62 0     0 1   my ($x, $y) = @_;
63 0           my @y2;
64 0           my $n = $#{$x};
  0            
65              
66 0 0         croak "X and Y array lengths don't match." unless ($n == $#{$y});
  0            
67              
68 0           $y2[0] = ($y->[1] - $y->[0])/($x->[1] - $x->[0]);
69 0           $y2[$n] = ($y->[$n] - $y->[$n-1])/($x->[$n] - $x->[$n-1]);
70              
71 0           for (my $i=1; $i<$n; $i++)
72             {
73 0           $y2[$i] = ($y->[$i+1] - $y->[$i-1])/($x->[$i+1] - $x->[$i-1]);
74             }
75              
76 0           return @y2;
77             }
78              
79             sub Derivative2
80             {
81 0     0 1   my ($x, $y, $yp1, $ypn) = @_;
82 0           my $n = $#{$x};
  0            
83 0           my (@y2, @u);
84 0           my ($qn, $un);
85              
86 0 0         croak "X and Y array lengths don't match." unless ($n == $#{$y});
  0            
87              
88 0 0         if (defined $yp1)
89             {
90 0           $y2[0] = -0.5;
91 0           $u[0] = (3/($x->[1] - $x->[0])) * (($y->[1] - $y->[0])/($x->[1] - $x->[0]) - $yp1);
92             }
93             else
94             {
95 0           $y2[0] = 0;
96 0           $u[0] = 0;
97             }
98              
99 0           for (my $i = 1; $i < $n; $i++)
100             {
101 0           my $sig = ($x->[$i] - $x->[$i-1])/($x->[$i+1] - $x->[$i-1]);
102 0           my $p = $sig * $y2[$i-1] + 2.0;
103              
104 0           $y2[$i] = ($sig - 1.0)/$p;
105 0           $u[$i] = (6.0 * ( ($y->[$i+1] - $y->[$i])/($x->[$i+1] - $x->[$i]) -
106             ($y->[$i] - $y->[$i-1])/($x->[$i] - $x->[$i-1])
107             )/
108             ($x->[$i+1] - $x->[$i-1]) - $sig * $u[$i-1])/$p;
109             }
110              
111 0 0         if (defined $ypn)
112             {
113 0           $qn = 0.5;
114 0           $un = (3.0/($x->[$n]-$x->[$n-1])) *
115             ($ypn - ($y->[$n] - $y->[$n-1])/($x->[$n] - $x->[$n-1]));
116             }
117             else
118             {
119 0           $qn = 0;
120 0           $un = 0;
121             }
122              
123 0           $y2[$n] = ($un - $qn * $u[$n-1])/($qn * $y2[$n-1] + 1.0);
124              
125 0           for(my $i = $n-1; $i >= 0; --$i)
126             {
127 0           $y2[$i] = $y2[$i] * $y2[$i+1] + $u[$i];
128             }
129              
130 0           return @y2;
131             }
132              
133             1;