Perl Advent Calendar 2006-12-16

I'm Approximating a White Christmas

by Jerrad Pierce

If you were searching CPAN for a means of carrying out calculations with indeterminate values (as a model for determining if you'll have an off-white xmas) you might stumble across Number::Uncertainty, which would seem to be just what the Ph.D. ordered. And yet, you probably need to be able to do more than add, subtract and multiply. Seeking a more complete implementation with the full panoply of operators you discover Math::ErrorPropagation. Depending upon your domain, this may be more than sufficient, but in all likelihood you appreciated NumberUncertainty's support for assymetric error and are unsatisified with the limitations of variances. Exasperated, you give it one more try and come up with Number::WithError.

Number:WithError might have a lot of (little used) dependencies1 but it seems to have all of the features one could want including bignum—i.e; Math::BigFloat—compatiblity. You can PEMDAS, SohCahToa, and heap on uncertainty to your heart's desire. Whether or not you end up with anything more accurate than

$ perl -le 'print +("Snow", "!Snow")[rand(2)]'
is another matter entirely.

Code sample output:

x = 4.20e+01 + 1.20e+01 - 0.0e+00
y = 7.0e+00 +/- 2.0e+00

z =  x * y  = 2.94e+02 + 1.19e+02 - 8.4e+01
w =  x / y  = 6.0e+00 + 2.4e+00 - 1.7e+00
e = sqrt(y) = 2.65e+00 +/- 3.8e-01

mod16.pl


   1 #!/usr/bin/perl
   2 #use bignum;
   3 use Number::WithError;
   4 
   5 #The answer is 42, but it might be 54
   6 my $x = Number::WithError->new(42, [12, 0]);
   7 
   8 #Somewhere's about 7
   9 my $y = Number::WithError->new(7, 2);
  10 
  11 printf "x = %s\ny = %s\n\n", $x, $y;
  12 printf "z =  x * y  = %s\n", $z = $x * $y;
  13 printf "w =  x / y  = %s\n", $w = $x / $y;
  14 printf "e = sqrt(y) = %s\n", $e = sqrt($y);
1. Math::Symbolic, Math::Symbolic::Custom::Contains, Math::SymbolicX::Inline, prefork, Params::Util and Test::LectroTest. If you'd rather avoid installing the first three, you can do so by commenting out the following lines in v0.06 of Number::WithError with no apparent side-effects:
  24 use Math::SymbolicX::Inline <<'HERE';
  25 my_tan = tan(arg0)
  26 HERE

The author points out in his use Perl journal that the non-apparent side-effects are some failed tests. As the documentaiton notes though, tan() is never exposed, and must be called as a method. For the following to work you should apply the patch below:

$ perl -MNumber::WithError -le 'print Number::WithError->new(3.14159/4)->tan()'
0.999998673205983
--- Number-WithError-0.06/lib/Number/WithError.pm       Wed Aug 30 07:17:43 2006
+++ WithError.pm        Sun Dec 17 11:34:50 2006
@@ -6,7 +6,7 @@
 use Params::Util qw/_ARRAY _INSTANCE _ARRAY0/;
 use prefork 'Math::BigFloat';
 
-our $VERSION = '0.06';
+our $VERSION = '0.06_20061216';
 
 use base 'Exporter';
 our @EXPORT_OK = qw(
@@ -21,9 +21,10 @@
 our $CFloatCapture = qr/([+-]?)(?=\d|\.\d)(\d*)(\.\d*)?([Ee][+-]?\d+)?/;
 
 # define function "tan"
-use Math::SymbolicX::Inline <<'HERE';
-my_tan = tan(arg0)
-HERE
+#use Math::SymbolicX::Inline <<'HERE';
+#my_tan = tan(arg0)
+#HERE
+sub my_tan { CORE::sin($_[0]) / CORE::cos($_[0]) }
 
 =head1 NAME