File Coverage

blib/lib/Number/WithError.pm
Criterion Covered Total %
statement 433 478 90.5
branch 151 196 77.0
condition 61 71 85.9
subroutine 41 43 95.3
pod 25 25 100.0
total 711 813 87.4


line stmt bran cond sub pod time code
1             package Number::WithError;
2              
3 8     8   150853 use 5.006;
  8         29  
  8         362  
4 8     8   76 use strict;
  8         29  
  8         266  
5 8     8   42 use warnings;
  8         14  
  8         272  
6 8     8   7539 use Params::Util qw/_ARRAY _INSTANCE _ARRAY0/;
  8         46875  
  8         721  
7 8     8   7287 use prefork 'Math::BigFloat';
  8         8165  
  8         47  
8              
9             our $VERSION = '1.01';
10              
11 8     8   542 use base 'Exporter';
  8         15  
  8         58814  
12             our @EXPORT_OK = qw(
13             witherror
14             witherror_big
15             );
16             our %EXPORT_TAGS = (
17             all => \@EXPORT_OK,
18             );
19              
20             our $CFloat = qr/[+-]?(?=\d|\.\d)\d*(?:\.\d*)?(?:[Ee][+-]?\d+)?/;
21             our $CFloatCapture = qr/([+-]?)(?=\d|\.\d)(\d*)(\.\d*)?([Ee][+-]?\d+)?/;
22              
23             # define function "tan"
24             #use Math::Symbolic;
25             #use Math::SymbolicX::Inline <<'HERE';
26             #HERE
27             #my_tan = tan(arg0)
28 101     101   343 sub _my_tan { return CORE::sin($_[0]) / CORE::cos($_[0]) }
29              
30             =head1 NAME
31              
32             Number::WithError - Numbers with error propagation and scientific rounding
33              
34             =head1 SYNOPSIS
35              
36             use Number::WithError;
37            
38             my $num = Number::WithError->new(5.647, 0.31);
39             print $num . "\n";
40             # prints '5.65e+00 +/- 3.1e-01'
41             # (I.e. it automatically does scientific rounding)
42            
43             my $another = $num * 3;
44             print $another . "\n";
45             # propagates the error assuming gaussian errors
46             # prints '1.69e+01 +/- 9.3e-01'
47            
48             # trigonometric functions also work:
49             print sin($another) . "\n";
50             # prints '-9.4e-01 +/- 3.1e-01'
51            
52             my $third = $another ** $num;
53             print $third. "\n";
54             # propagates both errors into one.
55             # prints '8.7e+06 +/- 8.1e+06'
56            
57             # shortcut for the constructor:
58             use Number::WithError 'witherror';
59             $num = witherror('0.00032678', ['2.5e-5', '3e-5'], 5e-6);
60             # can deal with any number of errors, even with asymmetric errors
61             print $num . "\n";
62             # prints '3.268e-04 + 2.5e-05 - 3.00e-05 +/- 5.0e-06'
63             # Note: It may be annyoing that they don't all have the same
64             # exponent, but they *do* all have the sam significant digit!
65              
66             =head1 DESCRIPTION
67              
68             This class is a container class for numbers with a number of associated
69             symmetric and asymmetric errors. It overloads practically all common
70             arithmetic operations and trigonometric functions to propagate the
71             errors. It can do proper scientific rounding (as explained in more
72             detail below in the documentation of the C<significant_digit()> method).
73              
74             You can use L<Math::BigFloat> objects as the internal representation
75             of numbers in order to support arbitrary precision calculations.
76              
77             Errors are propagated using Gaussian error propagation.
78              
79             With a notable exception, the test suite covers way over ninety percent of
80             the code. The remaining holes are mostly difficult-to-test corner cases and
81             sanity tests. The comparison routines are the exception
82             for which there will be more extensive tests in a future release.
83              
84             =head1 OVERLOADED INTERFACE
85              
86             This module uses L<overload> to enable the use of the ordinary Perl arithmetic
87             operators on objects. All overloaded operations are also availlable via
88             methods. Here is a list of overloaded operators and the equivalent methods.
89             The assignment forms of arithmetic operators (e.g. C<+=>) are availlable
90             if their normal counterpart is overloaded.
91              
92             =over 2
93              
94             =item *
95              
96             Addition: C<$x + $y> implemented by the C<$x-E<gt>add($y)> method.
97              
98             =item *
99              
100             Increment: C<$x++> implemented by the C<$x-E<gt>add(1)> method.
101              
102             =item *
103              
104             Subtraction: C<$x - $y> implemented by the C<$x-E<gt>subtract($y)> method
105              
106             =item *
107              
108             Decrement: C<$x--> implemented by the C<$x-E<gt>subtract(1)> method.
109              
110             =item *
111              
112             Multiplication: C<$x * $y> implemented by the C<$x-E<gt>multiply($y)> method.
113              
114             =item *
115              
116             Division: C<$x / $y> implemented by the C<$x-E<gt>divide($y)> method.
117              
118             =item *
119              
120             Exponentiation: C<$x ** $y> implemented by the C<$x-E<gt>exponentiate($y)> method.
121              
122             =item *
123              
124             Sine: C<sin($x)> implemented by the C<$x-E<gt>sin()> method.
125              
126             =item *
127              
128             Cosine: C<cos($x)> implemented by the C<$x-E<gt>cos()> method.
129              
130             =item *
131              
132             Stringification C<"$x"> is implemented by the C<$x-E<gt>round()> method.
133              
134             =item *
135              
136             Cast to a number (i.e. numeric context) is implemented by the C<$x-E<gt>number()> method.
137              
138             =item *
139              
140             Boolean context is implemented by the C<$x-E<gt>number()> method.
141              
142             =item *
143              
144             Unary minus C<-$x> is implemented by the C<$x-E<gt>multiply(-1)> method.
145              
146             =item *
147              
148             Logical not is implemented via a boolean context.
149              
150             =item *
151              
152             Absolute value C<abs($x)> is implemented via C<$x-E<gt>abs()>.
153              
154             =item *
155              
156             Natural logarithm C<log($x)> is implemented via C<$x-E<gt>log()>.
157              
158             =item *
159              
160             Square Root C<sqrt($x)> is implemented via C<$x-E<gt>sqrt()>.
161              
162             =item *
163              
164             Numeric comparison operators C<$x == $y>, C<$x != $y>, etc. are implemented via C<$x-$<gt>numeric_cmp($y)>.
165              
166             =item *
167              
168             String comparison operators C<$x eq $y>, C<$x ne $y>, etc. are implemented via C<$x-$<gt>full_cmp($y)>. They might not do what you expect. Please read the documentation.
169              
170             =back
171              
172             Here's a list of overloadable operations that aren't overloaded in the context of
173             this module:
174              
175             << >> x . & ^ | atan2 int
176              
177             =head1 CONSTRUCTORS
178              
179             All constructors accept L<Math::BigFloat> objects in place of numbers.
180              
181             =head2 new
182              
183             This is the basic constructor for C<Number::WithError> objects.
184              
185             New objects can be created in one of two ways:
186              
187             =over 2
188              
189             =item *
190              
191             The first argument is expected to be the number itself. Then come
192             zero or more errors. Errors can either be a number, a reference to
193             an array of two numbers, or C<undef>. In the former case, the number
194             is treated as an uncertainty which has the same magnitude in both
195             directions. (I.e. C<+/- x>) In case of an array reference, the first
196             number is treated as the upper error boundary and the second as the
197             lower boundary. (I.e. C<+x, -y>) C<undef> is treated as zero error.
198              
199             =item *
200              
201             The second way to create objects is passing a single string to the
202             constructor which is efficiently parsed into a number and any number
203             of errors. I'll explain the format with an example:
204              
205             133.14e-5 +/- .1e-4 + 0.00002 - 1.0e-5 +/- .2e-4
206              
207             In this example, the first number is parsed as the actual number.
208             The following number is treated as a symmetric error (C<.1e-4>)
209             The two following numbers are treated as the upper and lower
210             boundary for a single error. Then comes another ordinary error.
211             It is also legal to define the lower boundary of an error before
212             the upper boundary. (I.e. C<-1.0e-5 +0.00002>)
213              
214             Whitespace is insignificant.
215              
216             For the sake of completeness, I'll mention the regular expression
217             that is used to match numbers. It's taken from the official Perl
218             FAQ to match floating point numbers:
219              
220             [+-]?(?=\d|\.\d)\d*(?:\.\d*)?(?:[Ee][+-]?\d+)?
221              
222             Don't worry if you don't understand it. Just run a few tests to
223             see if it'll accept your numbers. Or go read C<perldoc -q float>
224             or pick up a book on C and read up on how they define floating
225             point numbers.
226              
227             =back
228              
229             Note that trailing zeros currently have no effect. (Yes, this is
230             a B<BUG>!)
231              
232             The constructor returns a new object of this class or undef if
233             something went wrong.
234              
235             =cut
236              
237             sub new {
238 5967     5967 1 131471 my $proto = shift;
239 5967   66     20780 my $class = ref($proto)||$proto;
240              
241             # clone
242 5967 100 100     15312 if (ref($proto) and not @_) {
243 280         630 my $num = $proto->{num};
244 280 100       630 $num = $num->copy() if ref($num);
245 280         1065 my $err = [];
246 280         442 foreach (@{$proto->{errors}}) {
  280         704  
247 2053 100       5483 push @$err, ref($_) eq 'ARRAY' ? [map {ref($_) ? $_->copy() : $_} @$_] : (ref($_) ? $_->copy() : $_)
  1594 100       3996  
    100          
248             }
249 280         1981 return bless {num => $num, errors => $err} => $class;
250             }
251              
252 5687 100       11102 return undef if not @_;
253              
254 5683         6222 my $num = shift;
255 5683 100       10633 return undef if not defined $num;
256              
257 5679 100       10295 if (not @_) {
258 2160         3996 return _parse_string($num, $class);
259             }
260              
261 3519         5203 my $errors = [];
262 3519         9344 my $self = {
263             num => $num,
264             errors => $errors,
265             };
266 3519         6964 bless $self => $class;
267              
268              
269 3519         7267 while (@_) {
270 33828         37926 my $err = shift;
271 33828 100       71918 if (_ARRAY($err)) {
272 16750 100       24775 if (@$err == 1) {
273 3433   50     12501 push @$errors, CORE::abs($err->[0] || 0);
274             }
275             else {
276 13317   50     69354 push @$errors, [CORE::abs($err->[0] || 0), CORE::abs($err->[1] || 0)];
      50        
277             }
278             }
279             else {
280 17078   100     61260 push @$errors, CORE::abs($err || 0);
281             }
282             }
283              
284 3519         10841 return $self;
285             }
286              
287              
288             # This parses a string into an object
289             sub _parse_string {
290 2160     2160   2431 my $str = shift;
291 2160         2362 my $class = shift;
292              
293 2160 50       15036 return undef unless $str =~ /\G\s*($CFloat)/cgo;
294 2160         4168 my $num = $1;
295 2160         3323 my $err = [];
296 2160         2566 while (1) {
297 2208 100       12267 if ($str =~ /\G \s* \+ \s* \/ \s* \- \s* ($CFloat)/cgxo) {
    100          
    100          
298 36         188 push @$err, CORE::abs($1);
299             }
300             elsif ($str =~ / \G \s* \+ \s* ($CFloat) \s* \- \s* ($CFloat)/cgxo) {
301 8         48 push @$err, [CORE::abs($1), CORE::abs($2)];
302             }
303             elsif ($str =~ /\G \s* \- \s* ($CFloat) \s* \+ \s* ($CFloat)/cgxo) {
304 4         24 push @$err, [CORE::abs($2), CORE::abs($1)];
305             }
306             else {
307 2160         2895 last;
308             }
309             }
310 2160         13398 return bless { num => $num, errors => $err } => $class;
311             }
312              
313             =head2 new_big
314              
315             This is an alternative constructor for C<Number::WithError>
316             objects. It works exactly like C<new> except that it makes all
317             internal numbers instances of C<Math::BigFloat> for high precision
318             calculations.
319              
320             The module does not load C<Math::BigFloat> at compile time to avoid
321             loading a big module that isn't needed all the time. Instead, this
322             module makes use of the L<prefork> pragma and loads C<Math::BigFloat>
323             when needed at run-time.
324              
325             =cut
326              
327             sub new_big {
328 90     90 1 234556 my $obj = shift()->new(@_);
329              
330 90 100       229 return undef if not defined $obj;
331              
332 86         4423 require Math::BigFloat;
333 86         54886 $obj->{num} = Math::BigFloat->new($obj->{num});
334              
335 86         98613 foreach my $e (@{$obj->{errors}}) {
  86         236  
336 122 100       4205 if (_ARRAY0($e)) {
337 16         42 @$e = map { Math::BigFloat->new($_) } @$e;
  32         1450  
338             }
339             else {
340 106         302 $e = Math::BigFloat->new($e);
341             }
342             }
343 86         7084 return $obj;
344             }
345              
346              
347             =head2 witherror
348              
349             This constructor is B<not> a method. It is a subroutine that
350             can be exported to your namespace on demand. It works exactly
351             as the C<new()> method except it's a subroutine and shorter.
352              
353             I'm normally not for this kind of shortcut in object-oriented
354             code, but if you have to create a large number of
355             C<Number::WithError> numbers, you'll appreciate it. Trust
356             me.
357              
358             Note to authors of subclasses: If you inherit from this module,
359             you'll need to implement your own C<witherror()> because otherwise,
360             it will still return objects of this class, not your subclass.
361              
362             =cut
363              
364 5088     5088 1 1872045 sub witherror { Number::WithError->new(@_) }
365              
366              
367             =head2 witherror_big
368              
369             This is also B<not> a method. It does the same as C<witherror()>.
370             It can also be optionally be exported to your namespace.
371              
372             It uses the C<new_big> constructor instead of the C<new>
373             constructor used by C<witherror()>.
374              
375             =cut
376              
377 18     18 1 32920 sub witherror_big { Number::WithError->new_big(@_) }
378              
379              
380             # This is a helper routine which applies the code ref it
381             # expects as last argument to the rest of its arguments after
382             # making sure the second argument is an object.
383             sub _apply {
384 501     501   722 my $self = shift;
385 501         657 my $sub = pop;
386 501         521 my $obj;
387 501 50       3429 if ( _INSTANCE($_[0], 'Number::WithError') ) {
388 501         744 $obj = shift;
389             }
390             else {
391 0         0 my $obj = $self->new(@_);
392             }
393 501 50       1094 return undef if not defined $obj;
394              
395 501         1095 return $sub->($self, $obj, 0);
396             }
397              
398              
399             #########################################################
400              
401             =head1 ARITHMETIC METHODS
402              
403             All of these methods implement an arithmetic operation on the
404             object and the method's first parameter.
405              
406             The methods aren't mutators. That means they don't modify the
407             object itself, but return the result of the operation as a
408             new object.
409              
410             All of the methods accept either a plain number,
411             a C<Number::WithError> object or anything that
412             is understood by the constructors as argument,
413              
414             All errors are correctly propagated using Gaussian Error
415             Propagation. The formulae used for this are mentioned in the
416             individual methods' documentation.
417              
418             =head2 add
419              
420             Adds the object B<a> and the argument B<b>. Returns a new object B<c>.
421              
422             Formula: C<c = a + b>
423              
424             Error Propagation: C<err_c = sqrt( err_a^2 + err_b^2 )>
425              
426             =cut
427              
428 101     101 1 846 sub add { push @_, \&_addition; goto &_apply; }
  101         287  
429              
430             sub _addition {
431 303     303   1912 my $o1 = shift;
432 303         341 my $o2 = shift;
433 303         367 my $switch = shift;
434 303 100       1524 $o2 = $o1->new($o2) if not _INSTANCE($o2, 'Number::WithError');
435              
436 303         589 my $e1 = $o1->{errors};
437 303         393 my $e2 = $o2->{errors};
438 303         390 my $n1 = $o1->{num};
439 303         406 my $n2 = $o2->{num};
440              
441 303         510 my $errs = [];
442 303         636 my $res = {errors => $errs};
443              
444 303         685 $res->{num} = $n1 + $n2;
445              
446 303         383 my $l1 = $#$e1;
447 303         375 my $l2 = $#$e2;
448 303 100       618 my $len = $l1 > $l2 ? $l1 : $l2;
449              
450 303         585 foreach (0..$len) {
451 3926   100     9086 my $le1 = $e1->[$_] || 0;
452 3926   100     9552 my $le2 = $e2->[$_] || 0;
453 3926         6021 my $ary1 = _ARRAY0 $le1;
454 3926         5287 my $ary2 = _ARRAY0 $le2;
455              
456 3926 100 100     12848 if (!$ary1 and !$ary2) {
    100          
457 2040         5217 push @$errs, CORE::sqrt($le1**2 + $le2**2);
458             }
459             elsif ($ary1) {
460 1268 100       1780 if ($ary2) {
461             # both
462 214         1001 push @$errs, [ CORE::sqrt($le1->[0]**2 + $le2->[0]**2), CORE::sqrt($le1->[1]**2 + $le2->[1]**2) ];
463             }
464             else {
465             # 1 not 2
466 1054         4764 push @$errs, [ CORE::sqrt($le1->[0]**2 + $le2**2), CORE::sqrt($le1->[1]**2 + $le2**2) ];
467             }
468             }
469             else {
470             # $ary2 not 1
471 618         2611 push @$errs, [ CORE::sqrt($le1**2 + $le2->[0]**2), CORE::sqrt($le1**2 + $le2->[1]**2) ];
472             }
473             }
474              
475 303 50       665 if (not defined $switch) {
476 0         0 $o1->{errors} = $errs;
477 0         0 $o1->{num} = $res->{num};
478 0         0 return $o1;
479             }
480             else {
481 303         668 bless $res => ref($o1);
482 303         1197 return $res;
483             }
484             }
485              
486             #########################################################
487              
488             =head2 subtract
489              
490             Subtracts the argument B<b> from the object B<a>. Returns a new object B<c>.
491              
492             Formula: C<c = a - b>
493              
494             Error Propagation: C<err_c = sqrt( err_a^2 + err_b^2 )>
495              
496             =cut
497              
498 100     100 1 977 sub subtract { push @_, \&_subtraction; goto &_apply; }
  100         307  
499              
500             sub _subtraction {
501 300     300   1734 my $o1 = shift;
502 300         348 my $o2 = shift;
503 300 100       1473 $o2 = $o1->new($o2) if not _INSTANCE($o2, 'Number::WithError');
504              
505 300         548 my $switch = shift;
506              
507 300         474 my $e1 = $o1->{errors};
508 300         406 my $e2 = $o2->{errors};
509 300         373 my $n1 = $o1->{num};
510 300         375 my $n2 = $o2->{num};
511              
512 300         400 my $errs = [];
513 300         627 my $res = {errors => $errs};
514              
515 300 100       602 if ($switch) {
516 100         175 ($n1, $n2) = ($n2, $n1);
517 100         210 ($e1, $e2) = ($e2, $e1);
518             }
519 300         672 $res->{num} = $n1 - $n2;
520              
521 300         414 my $l1 = $#$e1;
522 300         372 my $l2 = $#$e2;
523 300 100       553 my $len = $l1 > $l2 ? $l1 : $l2;
524              
525 300         570 foreach (0..$len) {
526 3699   100     17193 my $le1 = $e1->[$_] || 0;
527 3699   100     7807 my $le2 = $e2->[$_] || 0;
528 3699         5617 my $ary1 = _ARRAY0 $le1;
529 3699         5200 my $ary2 = _ARRAY0 $le2;
530              
531 3699 100 100     12386 if (!$ary1 and !$ary2) {
    100          
532 1939         5055 push @$errs, CORE::sqrt($le1**2 + $le2**2);
533             }
534             elsif ($ary1) {
535 789 100       1237 if ($ary2) {
536             # both
537 207         951 push @$errs, [ CORE::sqrt($le1->[0]**2 + $le2->[0]**2), CORE::sqrt($le1->[1]**2 + $le2->[1]**2) ];
538             }
539             else {
540             # 1 not 2
541 582         2492 push @$errs, [ CORE::sqrt($le1->[0]**2 + $le2**2), CORE::sqrt($le1->[1]**2 + $le2**2) ];
542             }
543             }
544             else {
545             # $ary2 not 1
546 971         4374 push @$errs, [ CORE::sqrt($le1**2 + $le2->[0]**2), CORE::sqrt($le1**2 + $le2->[1]**2) ];
547             }
548             }
549              
550 300 50       686 if (not defined $switch) {
551 0         0 $o1->{errors} = $errs;
552 0         0 $o1->{num} = $res->{num};
553 0         0 return $o1;
554             }
555             else {
556 300         644 bless $res => ref($o1);
557 300         1119 return $res;
558             }
559             }
560              
561             #########################################################
562              
563             =head2 multiply
564              
565             Multiplies the object B<a> and the argument B<b>. Returns a new object B<c>.
566              
567             Formula: C<c = a * b>
568              
569             Error Propagation: C<err_c = sqrt( b^2 * err_a^2 + a^2 * err_b^2 )>
570              
571             =cut
572              
573 100     100 1 786 sub multiply { push @_, \&_multiplication; goto &_apply; }
  100         247  
574              
575             sub _multiplication {
576 300     300   1634 my $o1 = shift;
577 300         306 my $o2 = shift;
578 300         346 my $switch = shift;
579 300 100       1430 $o2 = $o1->new($o2) if not _INSTANCE($o2, 'Number::WithError');
580              
581 300         560 my $e1 = $o1->{errors};
582 300         392 my $e2 = $o2->{errors};
583 300         384 my $n1 = $o1->{num};
584 300         354 my $n2 = $o2->{num};
585              
586 300         419 my $errs = [];
587 300         600 my $res = {errors => $errs};
588              
589 300         629 $res->{num} = $n1 * $n2;
590              
591 300         347 my $l1 = $#$e1;
592 300         379 my $l2 = $#$e2;
593 300 100       574 my $len = $l1 > $l2 ? $l1 : $l2;
594              
595 300         525 foreach (0..$len) {
596 3627   100     8000 my $le1 = $e1->[$_] || 0;
597 3627   100     7995 my $le2 = $e2->[$_] || 0;
598 3627         5031 my $ary1 = _ARRAY0 $le1;
599 3627         4560 my $ary2 = _ARRAY0 $le2;
600              
601 3627 100 100     11564 if (!$ary1 and !$ary2) {
    100          
602 1850         5160 push @$errs, CORE::sqrt( ($n2*$le1)**2 + ($n1*$le2)**2 );
603             }
604             elsif ($ary1) {
605 1140 100       1555 if ($ary2) {
606             # both
607 196         912 push @$errs, [ CORE::sqrt( ($n2*$le1->[0])**2 + ($n1*$le2->[0])**2), CORE::sqrt( ($n2*$le1->[1])**2 + ($n1*$le2->[1])**2) ];
608             }
609             else {
610             # 1 not 2
611 944         4267 push @$errs, [ CORE::sqrt( ($n2*$le1->[0])**2 + ($n1*$le2)**2), CORE::sqrt( ($n2*$le1->[1])**2 + ($n1*$le2)**2) ];
612             }
613             }
614             else {
615             # $ary2 not 1
616 637         2897 push @$errs, [ CORE::sqrt( ($n2*$le1)**2 + ($n1*$le2->[0])**2), CORE::sqrt( ($n2*$le1)**2 + ($n1*$le2->[1])**2) ];
617             }
618             }
619              
620 300 50       621 if (not defined $switch) {
621 0         0 $o1->{errors} = $errs;
622 0         0 $o1->{num} = $res->{num};
623 0         0 return $o1;
624             }
625             else {
626 300         655 bless $res => ref($o1);
627 300         1056 return $res;
628             }
629             }
630              
631             #########################################################
632              
633             =head2 divide
634              
635             Divides the object B<a> by the argument B<b>. Returns a new object B<c>.
636              
637             Formula: C<c = a / b>
638              
639             Error Propagation: C<err-c = sqrt( err_a^2 / b^2 + a^2 * err_b^2 / b^4 )>
640              
641             =cut
642              
643 100     100 1 964 sub divide { push @_, \&_division; goto &_apply; }
  100         281  
644              
645             sub _division {
646 300     300   1679 my $o1 = shift;
647 300         326 my $o2 = shift;
648 300         355 my $switch = shift;
649 300 100       1620 $o2 = $o1->new($o2) if not _INSTANCE($o2, 'Number::WithError');
650              
651 300         585 my $e1 = $o1->{errors};
652 300         429 my $e2 = $o2->{errors};
653 300         384 my $n1 = $o1->{num};
654 300         390 my $n2 = $o2->{num};
655              
656 300         445 my $errs = [];
657 300         648 my $res = {errors => $errs};
658              
659 300 100       582 if ($switch) {
660 100         173 ($n1, $n2) = ($n2, $n1);
661 100         197 ($e1, $e2) = ($e2, $e1);
662             }
663              
664 300         680 $res->{num} = $n1 / $n2;
665              
666 300         367 my $l1 = $#$e1;
667 300         366 my $l2 = $#$e2;
668 300 100       566 my $len = $l1 > $l2 ? $l1 : $l2;
669              
670 300         511 foreach (0..$len) {
671 3779   100     13094 my $le1 = $e1->[$_] || 0;
672 3779   100     8242 my $le2 = $e2->[$_] || 0;
673 3779         6264 my $ary1 = _ARRAY0 $le1;
674 3779         5374 my $ary2 = _ARRAY0 $le2;
675              
676 3779 100 100     13498 if (!$ary1 and !$ary2) {
    100          
677 1974         6234 push @$errs, CORE::sqrt( ($le1/$n2)**2 + ($le2*$n1/$n2**2)**2 );
678             }
679             elsif ($ary1) {
680 723 100       1036 if ($ary2) {
681             # both
682 205         1019 push @$errs, [ CORE::sqrt( ($le1->[0]/$n2)**2 + ($le2->[0]*$n1/$n2**2)**2), CORE::sqrt( ($le1->[1]/$n2)**2 + ($le2->[1]*$n1/$n2**2)**2) ];
683             }
684             else {
685             # 1 not 2
686 518         2684 push @$errs, [ CORE::sqrt( ($le1->[0]/$n2)**2 + ($le2*$n1/$n2**2)**2), CORE::sqrt( ($le1->[1]/$n2)**2 + ($le2*$n1/$n2**2)**2) ];
687             }
688             }
689             else {
690             # $ary2 not 1
691 1082         6006 push @$errs, [ CORE::sqrt( ($le1/$n2)**2 + ($le2->[0]*$n1/$n2**2)**2), CORE::sqrt( ($le1/$n2)**2 + ($le2->[1]*$n1/$n2**2)**2) ];
692             }
693             }
694              
695 300 50       603 if (not defined $switch) {
696 0         0 $o1->{errors} = $errs;
697 0         0 $o1->{num} = $res->{num};
698 0         0 return $o1;
699             }
700             else {
701 300         680 bless $res => ref($o1);
702 300         1082 return $res;
703             }
704             }
705              
706             ###################################
707              
708             =head2 exponentiate
709              
710             Raises the object B<a> to the power of the argument B<b>. Returns a new object B<c>.
711             Returns C<undef> if B<a> is negative because the error cannot be propagated in that
712             case. (Can't take log of a negative value.)
713              
714             Also, please have a look at the error propagation formula below. Exponentiation and
715             logarithms are operations that can become numerically unstable very easily.
716              
717             Formula: C<c = a ^ b>
718              
719             Error Propagation: C<err-c = sqrt( b^2 * a^(b-1) * err_a^2 + ln(a)^2 * a^b * err_b^2 )>
720              
721             =cut
722              
723 100     100 1 1200 sub exponentiate { push @_, \&_exponentiation; goto &_apply; }
  100         268  
724              
725             sub _exponentiation {
726 300     300   2257 my $o1 = shift;
727 300         342 my $o2 = shift;
728 300         351 my $switch = shift;
729 300 100       1746 $o2 = $o1->new($o2) if not _INSTANCE($o2, 'Number::WithError');
730              
731 300         574 my $e1 = $o1->{errors};
732 300         428 my $e2 = $o2->{errors};
733 300         386 my $n1 = $o1->{num};
734 300         375 my $n2 = $o2->{num};
735              
736 300         418 my $errs = [];
737 300         707 my $res = {errors => $errs};
738              
739 300 100       601 if ($switch) {
740 100         175 ($n1, $n2) = ($n2, $n1);
741 100         186 ($e1, $e2) = ($e2, $e1);
742             }
743              
744 300 50       748 return undef if $n1 < 0;
745              
746 300         906 $res->{num} = $n1 ** $n2;
747              
748 300         395 my $l1 = $#$e1;
749 300         369 my $l2 = $#$e2;
750 300 100       587 my $len = $l1 > $l2 ? $l1 : $l2;
751              
752 300         603 my $sh1 = $n2*$n1**($n2-1);
753 300         653 my $sh2 = CORE::log($n1)*$n1**$n2;
754              
755 300         553 foreach (0..$len) {
756 1930   100     5287 my $le1 = $e1->[$_] || 0;
757 1930   100     4047 my $le2 = $e2->[$_] || 0;
758 1930         3042 my $ary1 = _ARRAY0 $le1;
759 1930         3000 my $ary2 = _ARRAY0 $le2;
760              
761 1930 100 100     6818 if (!$ary1 and !$ary2) {
    100          
762 989         2965 push @$errs, CORE::sqrt( ($sh1*$le1)**2 + ($sh2*$le2)**2 );
763             }
764             elsif ($ary1) {
765 394 100       653 if ($ary2) {
766             # both
767 110         624 push @$errs, [ CORE::sqrt( ($sh1*$le1->[0])**2 + ($sh2*$le2->[0])**2), CORE::sqrt( ($sh1*$le1->[1])**2 + ($sh2*$le2->[1])**2) ];
768             }
769             else {
770             # 1 not 2
771 284         1526 push @$errs, [ CORE::sqrt( ($sh1*$le1->[0])**2 + ($sh2*$le2)**2), CORE::sqrt( ($sh1*$le1->[1])**2 + ($sh2*$le2)**2) ];
772             }
773             }
774             else {
775             # $ary2 not 1
776 547         2691 push @$errs, [ CORE::sqrt( ($sh1*$le1)**2 + ($sh2*$le2->[0])**2), CORE::sqrt( ($sh1*$le1)**2 + ($sh2*$le2->[1])**2) ];
777             }
778             }
779              
780 300 50       625 if (not defined $switch) {
781 0         0 $o1->{errors} = $errs;
782 0         0 $o1->{num} = $res->{num};
783 0         0 return $o1;
784             }
785             else {
786 300         583 bless $res => ref($o1);
787 300         1121 return $res;
788             }
789              
790             }
791              
792             ###################################
793              
794             =head1 METHODS FOR BUILTIN FUNCTIONS
795              
796             These methods calculate functions of the object and return the result
797             as a new object.
798              
799             =head2 sqrt
800              
801             Calculates the square root of the object B<a> and returns the result as a new object B<c>.
802             Returns undef if B<a> is negative.
803              
804             Formula: C<c = sqrt(a)>
805              
806             Error Propagation: C<err-c = sqrt( err-a^2 / (2*sqrt(a))^2 ) = abs( err-a / (2*sqrt(a)) )>
807              
808             =cut
809              
810             sub sqrt {
811 200     200 1 1174 my $o1 = shift;
812              
813 200         343 my $e1 = $o1->{errors};
814 200         279 my $n1 = $o1->{num};
815              
816 200 100       549 return undef if $n1 < 0;
817              
818 111         140 my $errs = [];
819 111         273 my $res = {errors => $errs};
820              
821 111         203 $res->{num} = CORE::sqrt($n1);
822              
823 111         131 my $l1 = $#$e1;
824              
825 111         118 my $len = $#$e1;
826 111         144 my $sh1 = 2*sqrt($n1);
827              
828 111         168 foreach (0..$len) {
829 1044   100     2027 my $le1 = $e1->[$_] || 0;
830 1044         1426 my $ary1 = _ARRAY0 $le1;
831              
832 1044 100       1403 if (!$ary1) {
833 607         1124 push @$errs, CORE::abs($le1 / $sh1);
834             }
835             else {
836 437         1287 push @$errs, [ CORE::abs($le1->[0] / $sh1), CORE::abs($le1->[1] / $sh1) ];
837             }
838             }
839              
840 111         237 bless $res => ref($o1);
841 111         261 return $res;
842             }
843              
844             ######################################
845              
846             =head2 log
847              
848             Calculates the natural logarithm of an object B<a>. Returns a new object B<c>.
849             If B<a> is negative, the function returns undef.
850              
851             Formula: C<c = log(a)>
852              
853             Error Propagation: C<err-c = sqrt( err-a^2 / a^2 ) = abs( err-a / a )>
854              
855             =cut
856              
857             sub log {
858 200     200 1 1211 my $o1 = shift;
859              
860 200         334 my $e1 = $o1->{errors};
861 200         265 my $n1 = $o1->{num};
862 200 100       532 return undef if $n1 < 0;
863              
864 103         127 my $errs = [];
865 103         202 my $res = {errors => $errs};
866              
867 103         239 $res->{num} = CORE::log($n1);
868              
869 103         137 my $l1 = $#$e1;
870              
871 103         109 my $len = $#$e1;
872              
873 103         198 foreach (0..$len) {
874 1064   100     2163 my $le1 = $e1->[$_] || 0;
875 1064         1417 my $ary1 = _ARRAY0 $le1;
876              
877 1064 100       1564 if (!$ary1) {
878 651         1216 push @$errs, CORE::abs($le1 / $n1);
879             }
880             else {
881 413         1231 push @$errs, [ CORE::abs($le1->[0] / $n1), CORE::abs($le1->[1] / $n1) ];
882             }
883             }
884              
885 103         224 bless $res => ref($o1);
886 103         249 return $res;
887             }
888              
889             ###################################
890              
891             =head2 sin
892              
893             Calculates the sine of the object B<a> and returns the result as a new object B<c>.
894              
895             Formula: C<c = sin(a)>
896              
897             Error Propagation: C<err-c = sqrt( cos(a)^2 * err-a^2 ) = abs( cos(a) * err-a )>
898              
899             =cut
900              
901             sub sin {
902 200     200 1 1347 my $o1 = shift;
903              
904 200         313 my $e1 = $o1->{errors};
905 200         266 my $n1 = $o1->{num};
906              
907 200         241 my $errs = [];
908 200         381 my $res = {errors => $errs};
909              
910 200         467 $res->{num} = CORE::sin($n1);
911              
912 200         261 my $l1 = $#$e1;
913              
914 200         304 my $sh1 = CORE::cos($n1);
915 200         212 my $len = $#$e1;
916              
917 200         335 foreach (0..$len) {
918 1800   100     3560 my $le1 = $e1->[$_] || 0;
919 1800         2362 my $ary1 = _ARRAY0 $le1;
920              
921 1800 100       2559 if (!$ary1) {
922 1136         3318 push @$errs, CORE::abs($sh1 * $le1);
923             }
924             else {
925 664         2130 push @$errs, [ CORE::abs($sh1 * $le1->[0]), CORE::abs($sh1 * $le1->[1]) ];
926             }
927             }
928              
929 200         437 bless $res => ref($o1);
930 200         473 return $res;
931             }
932              
933             ###################################
934              
935             =head2 cos
936              
937             Calculates the cosine of the object B<a> and returns the result as a new object B<c>.
938              
939             Formula: C<c = cos(a)>
940              
941             Error Propagation: C<err-c = sqrt( sin(a)^2 * err-a^2 ) = abs( sin(a) * err-a )>
942              
943             =cut
944              
945             sub cos {
946 200     200 1 1227 my $o1 = shift;
947              
948 200         321 my $e1 = $o1->{errors};
949 200         256 my $n1 = $o1->{num};
950              
951 200         259 my $errs = [];
952 200         372 my $res = {errors => $errs};
953              
954 200         421 $res->{num} = CORE::cos($n1);
955              
956 200         223 my $l1 = $#$e1;
957              
958 200         348 my $sh1 = CORE::sin($n1);
959 200         203 my $len = $#$e1;
960              
961 200         336 foreach (0..$len) {
962 1958   100     3864 my $le1 = $e1->[$_] || 0;
963 1958         2906 my $ary1 = _ARRAY0 $le1;
964              
965 1958 100       2771 if (!$ary1) {
966 1212         2302 push @$errs, CORE::abs($sh1 * $le1);
967             }
968             else {
969 746         2444 push @$errs, [ CORE::abs($sh1 * $le1->[0]), CORE::abs($sh1 * $le1->[1]) ];
970             }
971             }
972              
973 200         435 bless $res => ref($o1);
974 200         468 return $res;
975             }
976              
977             ###################################
978              
979             =head2 tan
980              
981             Calculates the tangent of the object B<a> and returns the result as a new object B<c>.
982              
983             Formula: C<c = tan(a)>
984              
985             Error Propagation: C<err-c = sqrt( err-a^2 / cos(a)^4 ) = abs( err-a / cos(a)^2 )>
986              
987             Since there is no built-in C<tan()> function, this operation is not available via
988             the overloaded interface.
989              
990             =cut
991              
992             sub tan {
993 101     101 1 974 my $o1 = shift;
994              
995 101         146 my $e1 = $o1->{errors};
996 101         176 my $n1 = $o1->{num};
997              
998 101         165 my $errs = [];
999 101         218 my $res = {errors => $errs};
1000              
1001 101         223 $res->{num} = _my_tan($n1);
1002              
1003 101         142 my $l1 = $#$e1;
1004              
1005 101         229 my $sh1 = 1 / CORE::cos($n1)**2;
1006 101         124 my $len = $#$e1;
1007              
1008 101         183 foreach (0..$len) {
1009 1029   100     2055 my $le1 = $e1->[$_] || 0;
1010 1029         1734 my $ary1 = _ARRAY0 $le1;
1011              
1012 1029 100       1516 if (!$ary1) {
1013 634         1744 push @$errs, CORE::abs($le1 * $sh1);
1014             }
1015             else {
1016 395         1221 push @$errs, [ CORE::abs($le1->[0] * $sh1), CORE::abs($le1->[1] * $sh1) ];
1017             }
1018             }
1019              
1020 101         248 bless $res => ref($o1);
1021 101         227 return $res;
1022             }
1023              
1024             =head2 abs
1025              
1026             Calculates the absolute value of an object B<a>. Leaves the errors untouched. Returns a new
1027             object B<c>.
1028              
1029             Formula: C<c = abs(a)>
1030              
1031             Error Propagation: C<err-c = err-a>
1032              
1033             =cut
1034              
1035             sub abs {
1036 200     200 1 1385 my $self = shift;
1037              
1038 200         400 my $new = $self->new();
1039 200         437 $new->{num} = CORE::abs($new->{num});
1040 200         464 return $new;
1041             }
1042              
1043              
1044              
1045              
1046             ###################################
1047              
1048             =head1 ROUNDING, STRINGIFICATION AND OUTPUT METHODS
1049              
1050             This section documents methods dealing with the extraction of data from
1051             the object. The methods implement rounding of numbers, stringification
1052             of the object and extracting meta information like the significant
1053             digit.
1054              
1055             =cut
1056              
1057             =head2 number
1058              
1059             Determines the significant digit using the C<significant_digit()> method,
1060             rounds the number that the object C<number()> is called on represents
1061             to that digit and returns the rounded number.
1062              
1063             Regardless of the internal representation of the number, this returns
1064             an unblessed string / an unblessed floating point number.
1065              
1066             To gain access to the raw number representation
1067             in the object, use the C<raw_number> method.
1068              
1069             Either way, the number will be in scientific notation. That means the first
1070             non-zero digit comes before the decimal point and following the decimal
1071             point and any number of digits is an exponent in C<eXXX> notation.
1072              
1073             =cut
1074              
1075             sub number {
1076 6012     6012 1 38525 my $self = shift;
1077 6012         11196 my $sig = $self->significant_digit();
1078 6012         14695 return round_a_number($self->{num}, $sig);
1079             }
1080              
1081              
1082             =head2 raw_number
1083              
1084             This method returns the internal representation of the number in
1085             the object. It does not round as appropriate. It does not clone
1086             C<Math::BigFloat> objects either. So make sure you do that if
1087             necessary!
1088              
1089             =cut
1090              
1091             sub raw_number {
1092 0     0 1 0 my $self = shift;
1093 0         0 return $self->{num};
1094             }
1095              
1096              
1097             =head2 round
1098              
1099             This method determines the significant digit using the C<significant_digit()>
1100             method. Then, it rounds the number represented by the object and all
1101             associated errors to that digit.
1102              
1103             Then, the method concatenates the number with its errors and returns the
1104             resulting string. In case of symmetric errors, the string C<+/-> will
1105             be prepended to the error. In case of asymmetric errors, a C<+> will
1106             be prepended to the first/upper error component and a C<-> to the
1107             second/lower error component.
1108              
1109             Returns the previously described string.
1110              
1111             =cut
1112              
1113             sub round {
1114 0     0 1 0 my $self = shift;
1115 0         0 my $sig = $self->significant_digit();
1116              
1117 0         0 my $str = round_a_number($self->{num}, $sig);
1118              
1119 0         0 foreach my $err (@{$self->{errors}}) {
  0         0  
1120 0 0 0     0 if (ref($err) eq 'ARRAY' and @$err == 2) {
    0          
1121 0         0 $str .= ' + ' . round_a_number($err->[0], $sig) . ' - ' . round_a_number($err->[1], $sig);
1122             }
1123             elsif (ref($err) eq 'ARRAY') {
1124 0         0 $str .= ' +/- ' . round_a_number($err->[0], $sig);
1125             }
1126             else {
1127 0         0 $str .= ' +/- ' . round_a_number($err, $sig);
1128             }
1129             }
1130 0         0 return $str;
1131             }
1132              
1133              
1134              
1135             =head2 significant_digit
1136              
1137             This method returns the significant digit of the number it is called
1138             on as an integer. If the number has no errors or all errors are
1139             C<undef> or zero, this method returns C<undef>.
1140              
1141             The return value of this method is to be interpreted as follows:
1142             If this method returns C<-5>, the significant digit is C<1 * 10**-5>
1143             or C<0.00001>. If it returns C<3>, the significant digit is
1144             C<1 * 10**3> or C<1000>. If it returns C<0>, the significant digit
1145             is C<1>.
1146              
1147             The return value is computed by the following algorithm:
1148             The individual significant digit of a single error is:
1149             Take the exponent of the first non-zero digit
1150             in the error. The digit after this first non-zero digit is the
1151             significant one.
1152              
1153             This method returns the minimum of the individual significant digits of
1154             all errors.
1155              
1156             That means:
1157              
1158             5 +/- 0.0132 + 0.5 - 1
1159              
1160             Will yield a return value of C<-3> since the first error has the lowest
1161             significant digit.
1162              
1163             This algorithm is also used for determining the significant digit for
1164             rounding. It is extremely important that you realize this isn't
1165             carved in stone. B<The way the significant digit is computed in the
1166             presence of errors is merely a convention.> In this case, it stems
1167             from particle physics. It might well be that
1168             in your particular scientific community, there are other conventions.
1169             One, for example, is to use the second non-zero digit only if the first
1170             is a 1.
1171              
1172             =cut
1173              
1174             # Implementation for significant digit = first non-zero unless first non-zero==1
1175             #sub significant_digit {
1176             # my $self = shift;
1177             #
1178             # my $significant;
1179             # foreach my $err (map {ref($_) eq 'ARRAY' ? @$_ : $_} @{$self->{errors}}) {
1180             # my $sci = sprintf('%e', $err);
1181             # $sci =~ /^(.+)[eE]([+-]?\d+)$/ or die;
1182             # my $pre = $1;
1183             # my $exp = $2;
1184             # if ($pre !~ /[1-9]/) {
1185             # next;
1186             # }
1187             # elsif ($pre =~ /^[^1-9]*1/) {
1188             # $significant = $exp-1 if not defined $significant or $exp-1 < $significant;
1189             # }
1190             # else {
1191             # $significant = $exp if not defined $significant or $exp < $significant;
1192             # }
1193             # }
1194             # return defined($significant) ? 0+$significant : undef;
1195             #}
1196              
1197             sub significant_digit {
1198 6188     6188 1 6325 my $self = shift;
1199              
1200 6188         5720 my $significant;
1201 6188 100       6242 foreach my $err (map {ref($_) eq 'ARRAY' ? @$_ : $_} @{$self->{errors}}) {
  55219         114836  
  6188         12853  
1202 78290         253181 my $sci = sprintf('%e', $err);
1203 78290 50       287053 $sci =~ /[eE]([+-]?\d+)$/ or die;
1204 78290         131276 my $exp = $1-1;
1205 78290 100 100     320731 $significant = $exp if not defined $significant or $exp < $significant;
1206             }
1207 6188 100       20333 return defined($significant) ? 0+$significant : undef;
1208             }
1209              
1210              
1211              
1212             =head2 error
1213              
1214             This method returns a reference to an array of errors of the object it is
1215             called on.
1216              
1217             Unlike the C<raw_error()> method, this method takes proper care to copy
1218             all objects and references to defy action at a distance. The structure
1219             of the returned array reference is akin to that returned by
1220             C<raw_error()>.
1221              
1222             Furthermore, this method rounds all errors to the significant digit as
1223             determined by C<significant_digit()>.
1224              
1225             =cut
1226              
1227             sub error{
1228 16     16 1 12214 my $self = shift;
1229 16         53 my $sig = $self->significant_digit();
1230              
1231 16         39 my $errors = [];
1232 16         27 foreach my $err (@{$self->{errors}}) {
  16         62  
1233 25 100 66     113 if (ref($err) eq 'ARRAY' and @$err == 2) {
    50          
1234 4         13 push @$errors, [ round_a_number($err->[0], $sig), round_a_number($err->[1], $sig) ];
1235             }
1236             elsif (ref($err) eq 'ARRAY') {
1237 0         0 push @$errors, round_a_number($err->[0], $sig);
1238             }
1239             else {
1240 21         54 push @$errors, round_a_number($err, $sig);
1241             }
1242             }
1243              
1244 16         58 return $errors;
1245             }
1246              
1247              
1248              
1249             =head2 raw_error
1250              
1251             Returns the internal representation of the errors of the current object.
1252             Note that (just like C<raw_number()>, this does not clone the data for
1253             safe use without action at a distance. Instead, it directly returns the
1254             internal reference to the error structure.
1255             The structure is an array of errors. Each error may either be a
1256             string or floating point number or a C<Math::BigFloat> object or
1257             an array reference. In case of an array reference, it is an
1258             asymmetric error. The inner array contains two
1259             strings/numbers/C<Math::BigFloat>s.
1260              
1261             Note that this practically breaks encapsulation and code relying on it
1262             might break with future releases.
1263              
1264             =cut
1265              
1266             sub raw_error{
1267 16     16 1 10103 my $self = shift;
1268 16         119 return $self->{errors};
1269             }
1270              
1271             =head2 as_array
1272              
1273             This method returns the information stored in the object as an array
1274             (i.e. a list in this context)
1275             which can be passed to the C<new()> method to recreate the object.
1276              
1277             The first element of the return list will be the number itself. If the
1278             object uses C<Math::BigFloat> for the internal representation, this
1279             element will be a copy of the internal object. Otherwise, it will be the
1280             internal representation of the number with full precision.
1281              
1282             Following the number will be all errors either as numbers, C<Math::BigFloat>
1283             objects or arrays containing two asymmetric errors. (Either as numbers or
1284             objects as explained above.) The data returned by this method will be
1285             copied deeply before being returned.
1286              
1287             =cut
1288              
1289             sub as_array {
1290 16     16 1 10616 my $self = shift;
1291 16         44 my $copy = $self->new;
1292 16         32 return( $copy->{num}, @{$copy->{errors}} );
  16         95  
1293             }
1294              
1295              
1296             =head2 round_a_number
1297              
1298             This is a helper B<function> which can round a number
1299             to the specified significant digit (defined as
1300             the return value of the C<significant_digit> method):
1301              
1302             my $rounded = round_a_number(12.01234567, -3);
1303             # $rounded is now 1.2012e01
1304              
1305             =cut
1306              
1307             sub round_a_number {
1308 6331     6331 1 7211 my $number = shift;
1309 6331         6715 my $digit = shift;
1310              
1311 6331 100       11191 my $num = ref($number) ? $number->copy() : $number;
1312              
1313 6331 100       17885 return "$num" if not defined $digit;
1314 6025 50       28152 return "$num" if $num =~ /^nan$/i;
1315              
1316             # if (ref($num)) {
1317             # my $rounded = $num->ffround($digit, 'odd')->bsstr();
1318             # return $rounded;
1319             # }
1320             # else {
1321 6025         33745 my $tmp = sprintf('%e', $num);
1322 6025 50       29399 $tmp =~ /[eE]([+-]?\d+)$/
1323             or die "Error rounding number '$num'. Result '$tmp' was expected to match /[eE][+-]?·\\d+/!";
1324              
1325 6025         10880 my $exp = $1 - $digit;
1326              
1327 6025         6036 my ($bef, $aft);
1328 6025 100       9497 if ($exp >= 0) {
    100          
1329 5997         22512 my $res = sprintf('%.'.$exp.'e', $num);
1330 5997 50       37947 $res =~ /^([+-]?\d+|[+-]?\d*\.\d+)[eE]([+-]?\d+)$/ or die $res;
1331 5997         9276 $bef = $1;
1332 5997         9583 $aft = $2;
1333             }
1334             elsif ($exp <= -2) {
1335 8         12 $bef = 0;
1336 8         12 $aft = $digit;
1337             }
1338             else {
1339             # $exp == -1
1340 20         78 $num =~ /([1-9])/;
1341 20 50       250 if (not defined $1) {
    100          
1342 0         0 $bef = 0;
1343             }
1344             elsif ($1 >= 5) {
1345 19 100       51 $bef = $num < 0 ? -1 : 1;
1346             }
1347             else {
1348 1         2 $bef = 0;
1349             }
1350 20         561 $aft = $digit;
1351             }
1352              
1353 6025         21733 return "${bef}e$aft";
1354             # }
1355             }
1356              
1357              
1358              
1359             ############################################
1360              
1361             =head1 COMPARISON
1362              
1363             This section lists methods that implement different comparisons between
1364             objects.
1365              
1366             =cut
1367              
1368             =head2 numeric_cmp
1369              
1370             This method implements a numeric comparison of two numbers.
1371             It compares the object it is called on to the first argument
1372             of the method. If the first argument is omitted or undefined,
1373             the method returns C<undef>.
1374              
1375             I<Numeric comparison> means in this case that the represented
1376             numbers will be rounded and then compared. If you would like
1377             a comparison that takes care of errors, please have a look at the
1378             C<full_cmp()> method.
1379              
1380             The method returns C<-1> if the rounded number represented by
1381             the object is numerically less than the rounded number represented
1382             by the first argument. It returns C<0> if they are equal and C<1>
1383             if the object's rounded number is more than that of the argument.
1384              
1385             This method implements the overloaded numeric comparison
1386             operations.
1387              
1388             =cut
1389              
1390              
1391             sub numeric_cmp {
1392 96     96 1 120 my $self = shift;
1393 96         108 my $arg = shift;
1394              
1395 96 50       580 $arg = Number::WithError->new($arg) if not _INSTANCE($arg, 'Number::WithError');
1396              
1397 96 50       509 return undef if not defined $arg;
1398              
1399 96         254 my $n1 = $self->number();
1400 96         502 my $n2 = $arg->number();
1401              
1402 96         667 return $n1 <=> $n2;
1403             }
1404              
1405              
1406             =head2 full_cmp
1407              
1408             This method implements a full comparison of two objects. That means,
1409             it takes their numeric values, rounds them and compares them just like
1410             the C<numeric_cmp()> method.
1411              
1412             If, however, the numbers are equal, this method iterates over the errors,
1413             rounds them and then compares them. If all errors are equal, this method
1414             returns C<0>. If an error is found to differ, the method returns C<1> in
1415             case the object's error is larger and C<-1> in case the argument's error is
1416             larger.
1417              
1418             Comparing an asymmetric error to a symmetric error is a special case.
1419             It can never be the same error, hence the method will not return C<0>.
1420             Instead, it guesses which error is larger by using the upper error bound
1421             of the asymmetric error. (Well, yes, not very useful.)
1422              
1423             =cut
1424              
1425             sub full_cmp {
1426 80     80 1 117 my $self = shift;
1427 80         94 my $arg = shift;
1428              
1429 80 50       757 $arg = Number::WithError->new($arg) if not _INSTANCE($arg, 'Number::WithError');
1430              
1431 80 50       464 return undef if not defined $arg;
1432              
1433 80         224 my $numeq = $self->numeric_cmp($arg);
1434              
1435              
1436             # numbers differ or undef
1437 80 50 33     395 if ($numeq or not defined $numeq) {
1438 0         0 return $numeq;
1439             }
1440              
1441 80         174 my $sig1 = $self->significant_digit();
1442 80         160 my $sig2 = $arg->significant_digit();
1443              
1444 80 50       97 my $max = $#{$self->{errors}} > $#{$arg->{errors}} ? $#{$self->{errors}} : $#{$arg->{errors}};
  80         153  
  80         199  
  0         0  
  80         149  
1445 80         209 foreach my $no (0..$max) {
1446 125         232 my $e1 = $self->{errors}[$no];
1447 125         178 my $e2 = $arg->{errors}[$no];
1448              
1449 125 50       379 if (not defined $e1) {
    50          
1450 0 0       0 return -1 if defined $e2;
1451 0 0       0 next if not defined $e2;
1452             }
1453             elsif (not defined $e2) {
1454 0         0 return 1;
1455             }
1456             # else
1457              
1458 125 100       356 if (ref($e1) eq 'ARRAY') {
    50          
1459 20 50       64 if (not ref($e2) eq 'ARRAY') {
1460 0         0 my $res = _full_cmp_err($e1->[0], $sig1, $e2, $sig2);
1461 0 0       0 return $res if $res;
1462 0         0 return 1;
1463             }
1464             else {
1465 20         45 for my $i (0..$#$e1) {
1466 40         92 my $res = _full_cmp_err($e1->[$i], $sig1, $e2->[$i], $sig2);
1467 40 50       121 return $res if $res;
1468             }
1469 20         53 next;
1470             }
1471             }
1472             elsif (ref($e2) eq 'ARRAY') {
1473 0         0 my $res = _full_cmp_err($e1, $sig1, $e2->[1], $sig2);
1474 0 0       0 return $res if $res;
1475 0         0 return 1;
1476             }
1477             else {
1478 105         245 my $res = _full_cmp_err($e1, $sig1, $e2, $sig2);
1479 105 50       244 return $res if $res;
1480 105         221 next;
1481             }
1482             }
1483              
1484 80         825 return 0;
1485             }
1486              
1487             sub _full_cmp_err {
1488 145     145   167 my $e1 = shift;
1489 145         167 my $sig1 = shift;
1490 145         150 my $e2 = shift;
1491 145         169 my $sig2 = shift;
1492              
1493 145         252 my $r1 = round_a_number($e1, $sig1);
1494 145         306 my $r2 = round_a_number($e2, $sig2);
1495              
1496 145         443 return $r1 <=> $r2;
1497             }
1498              
1499             #################################
1500              
1501              
1502             sub _num_eq {
1503 16     16   93 my $self = shift;
1504 16         22 my $arg = shift;
1505 16         19 my $switch = shift;
1506 16 50       77 if ($switch) {
1507 0 0       0 $arg = Number::WithError->new($arg) if not _INSTANCE($arg, 'Number::WithError');
1508 0         0 return $arg->numeric_cmp($self);
1509             }
1510             else {
1511 16         40 return $self->numeric_cmp($arg);
1512             }
1513             }
1514              
1515              
1516             sub _full_eq {
1517 80     80   8463 my $self = shift;
1518 80         128 my $arg = shift;
1519 80         125 my $switch = shift;
1520 80 50       164 if ($switch) {
1521 0 0       0 $arg = Number::WithError->new($arg) if not _INSTANCE($arg, 'Number::WithError');
1522 0         0 return $arg->full_cmp($self);
1523             }
1524             else {
1525 80         253 return $self->full_cmp($arg);
1526             }
1527             }
1528              
1529             use overload
1530 8         144 '+' => \&_addition,
1531             '-' => \&_subtraction,
1532             '*' => \&_multiplication,
1533             '/' => \&_division,
1534             '**' => \&_exponentiation,
1535             '""' => \&round,
1536             '0+' => \&number,
1537             'bool' => \&number,
1538             'sin' => \&sin,
1539             'cos' => \&cos,
1540             'abs' => \&abs,
1541             'sqrt' => \&sqrt,
1542             'log' => \&log,
1543             '<=>' => \&_num_eq,
1544             'cmp' => \&_full_eq,
1545 8     8   106 ;
  8         24  
1546              
1547             1;
1548              
1549             __END__
1550              
1551             =pod
1552              
1553             =head1 SUPPORT
1554              
1555             Bugs should be reported via the CPAN bug tracker at
1556              
1557             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Number-WithError>
1558              
1559             For other issues, contact the author.
1560              
1561             =head1 SEE ALSO
1562              
1563             You may use L<Math::BigFloat> with this module. Also, it should be possible to
1564             use L<Math::Symbolic> to calculate larger formulas. Just assign a
1565             C<Number::WithError> object to the C<Math::Symbolic> variables and it should
1566             work.
1567              
1568             You also possibly want to have a look at the L<prefork> pragma.
1569              
1570             The test suite is implemented using the L<Test::LectroTest> module. In order to
1571             keep the total test time in reasonable bounds, the default number of test attempts
1572             to falsify the test properties is kept at a low number of 100. You can
1573             enable more rigorous testing by setting the environment variable
1574             C<PERL_TEST_ATTEMPTS> to a higher value. A value in the range of C<1500> to
1575             C<3000> is probably a good idea, but takes a long time to test.
1576              
1577             =head1 AUTHOR
1578              
1579             Steffen Mueller E<lt>smueller@cpan.orgE<gt>, L<http://steffen-mueller.net/>
1580              
1581             =head1 COPYRIGHT
1582              
1583             Copyright 2006-2010 Steffen Mueller.
1584              
1585             This program is free software; you can redistribute
1586             it and/or modify it under the same terms as Perl itself.
1587              
1588             =cut