diff --git a/Changes b/Changes index 86051eb..517bf8b 100644 --- a/Changes +++ b/Changes @@ -15,3 +15,5 @@ Revision history for Math-Function-Interpolator 0.05 15/06/2014 method closest_three_points exported, could be usefull for the Mathmatician +0.06 18/06/2014 + More intense test added to check module diff --git a/MANIFEST b/MANIFEST index 7414c49..50437e8 100644 --- a/MANIFEST +++ b/MANIFEST @@ -6,6 +6,7 @@ lib/Math/Function/Interpolator/Quadratic.pm Makefile.PL MANIFEST README +t/02-intense_test.t t/01-calculation.t t/00-load.t t/manifest.t diff --git a/lib/Math/Function/Interpolator.pm b/lib/Math/Function/Interpolator.pm index 0de48fa..01669ab 100644 --- a/lib/Math/Function/Interpolator.pm +++ b/lib/Math/Function/Interpolator.pm @@ -26,7 +26,7 @@ Math::Function::Interpolator - Interpolation made easy =head1 VERSION -Version 0.05 +Version 0.06 =head1 SYNOPSIS @@ -54,7 +54,7 @@ HashRef of points for interpolations =cut -our $VERSION = '0.05'; +our $VERSION = '0.06'; # Automatically load all interpolate methods has 'interpolate_classes' => ( diff --git a/t/02-intense_test.t b/t/02-intense_test.t new file mode 100644 index 0000000..0c183d2 --- /dev/null +++ b/t/02-intense_test.t @@ -0,0 +1,142 @@ +use Test::More; +use Test::FailWarnings; +use Test::Exception; + +use Math::Function::Interpolator; + +my $interpolator = Math::Function::Interpolator->new( + points => {1=>2,2=>3,3=>4,4=>5,5=>6} +); + +subtest "closest_three_points" => sub { + plan tests => 9; + my $o = Math::Function::Interpolator->new(points => {1 => 2}); + my @points = (2, 3, 5, 1, 40, 89, 90, 99, 91); + my ($first, $second, $third) = $o->closest_three_points(6, \@points); + is($first, 5, "first number is correct for seek in_between(@points)"); + is($second, 40, "second number is correct for seek in_between(@points)"); + is($third, 89, "third number is correct for seek in_between(@points)"); + ($first, $second, $third) = $o->closest_three_points(0.2, \@points); + is($first, 1, "first number is correct for seek smaller than min(@points)"); + is($second, 2, "second number is correct for seek smaller than min(@points)"); + is($third, 3, "third number is correct for seek smaller than min(@points)"); + ($first, $second, $third) = $o->closest_three_points(100, \@points); + is($first, 90, "first number is correct for seek larger than max(@points)"); + is($second, 91, "second number is correct for seek larger than max(@points)"); + is($third, 99, "third number is correct for seek larger than max(@points)"); +}; + +subtest "general checks for linear" => sub { + plan tests => 4; + my $o; + lives_ok { $o = Math::Function::Interpolator->new(points => {2 => 3, 4 => 5.5}) } "can instantiate object with 2 points"; + lives_ok { $o->linear(2.4) } "can linear given an X"; + throws_ok { $o->linear('abc') } qr/point_x must be numeric/, "dies when X is not a number"; + throws_ok { Math::Function::Interpolator->new(points => {2 => 3,})->linear(1) } qr/cannot interpolate with fewer than 2 data points/, + "cannot linear linear equation with one data point"; +}; + +subtest "verify linear interpolation and extrapolation" => sub { + plan tests => 4; + my $o = Math::Function::Interpolator->new( + points => { + 1 => 3, + 2 => 4.5, + 3 => 6 + }); + is($o->linear(2.4), 5.1, "correctly interpolate y given x=2.4"); + is($o->linear(1.4), 3.6, "correctly interpolate y given x=1.4"); + is($o->linear(3.5), 6.75, "correctly extrapolate y given x=3.6"); + is($o->linear(0.5), 2.25, "correctly extrapolate y given x=0.5"); +}; + +subtest "general checks for quadratic" => sub { + plan tests => 4; + my $o; + lives_ok { $o = Math::Function::Interpolator->new(points => {2 => 3, 4 => 5.5, 6 => 8}) } "can instantiate object with 3 points"; + lives_ok { $o->quadratic(2.4) } "can quadratic given an X"; + throws_ok { $o->quadratic('abc') } qr/point_x must be numeric/, "dies when X is not a number"; + throws_ok { Math::Function::Interpolator->new(points => {2 => 3, 4 => 5})->quadratic(1) } + qr/cannot interpolate with fewer than 3 data points/, + "cannot solve quadratic equation with two data point"; +}; + +subtest "verify quadratic interpolation and extrapolation" => sub { + plan tests => 2; + my $points = { + 6 => 11, + 2 => 3, + -2 => 19, + }; + my $o = Math::Function::Interpolator->new(points => $points); + is($o->quadratic(2.4), 2.72, "correctly interpolate y given x=2.4"); + $points->{4} = 7; + my $o_new = Math::Function::Interpolator->new(points => $points); + lives_ok { $o_new->quadratic(2.4) } "can solve quadratic equation with 4 data points "; +}; + +subtest "general checks for cubic" => sub { + plan tests => 4; + my $o; + lives_ok { $o = Math::Function::Interpolator->new(points => {2 => 3, 4 => 5.5, 6 => 8, 7 => 9, 10 => 14}) } "can instantiate object with 5 points"; + lives_ok { $o->cubic(2.4) } "can cubic given an X"; + throws_ok { $o->cubic('abc') } qr/point_x must be numeric/, "dies when X is not a number"; + throws_ok { Math::Function::Interpolator->new(points => {2 => 3, 4 => 5, 2 => 6, 4 => 11})->cubic(1) } + qr/cannot interpolate with fewer than 5 data points/, "cannot cubic equation with four data point"; +}; + +subtest "cubic interpolation compared to Bloomberg" => sub { + plan tests => 8; + my $points = { + 95 => 0.2780, + 97.5 => 0.2670, + 100 => 0.2563, + 102.5 => 0.2461, + 105 => 0.2364 + }; + my $bb = { + 96 => 0.2736, + 97 => 0.2692, + 98 => 0.2649, + 99 => 0.2606, + 100 => 0.2563, + 101 => 0.2521, + 102 => 0.2481, + 103 => 0.2441, + 104 => 0.2402 + }; + + my $o = Math::Function::Interpolator->new(points => $points); + foreach my $num (96 .. 104) { + next if grep { $_ == $num } keys %$points; + my $test = $o->cubic($num); + my $diff = abs($test - $bb->{$num}); + cmp_ok($diff, "<", 0.0001, "match Bloomberg's interpolation for moneyness[$num] on DAX"); + } +}; + +subtest "cubic extrapolation" => sub { + plan tests => 6; + my $points = { + 95 => 0.2780, + 97.5 => 0.2670, + 100 => 0.2563, + 102.5 => 0.2461, + 105 => 0.2364 + }; + my $o = Math::Function::Interpolator->new(points => $points); + lives_ok { $o->cubic(80) } "can extrapolate"; + my $first = $o->cubic(94); + my $second = $o->cubic(93); + my $third = $o->cubic(90); + cmp_ok($first, "<", $second, "linear extrapolation. In this case, linear increment"); + cmp_ok($second, "<", $third, "linear extrapolation. In this case, linear increment"); + lives_ok { $o->cubic(110) } "can extrapolate"; + $first = $o->cubic(106); + $second = $o->cubic(107); + $third = $o->cubic(110); + cmp_ok($first, ">", $second, "linear extrapolation. In this case, linear decrement"); + cmp_ok($second, ">", $third, "linear extrapolation. In this case, linear decrement"); +}; + +done_testing;