File Coverage

blib/lib/Number/Uncertainty.pm
Criterion Covered Total %
statement 142 187 75.9
branch 76 126 60.3
condition 19 39 48.7
subroutine 20 20 100.0
pod 11 15 73.3
total 268 387 69.2


line stmt bran cond sub pod time code
1             package Number::Uncertainty;
2              
3             =head1 NAME
4              
5             Number::Uncertainty - An object-orientated uncertainty object
6              
7             =head1 SYNOPSIS
8              
9             $obj = new Number::Uncertainty ( Value => $value );
10              
11             $obj = new Number::Uncertainty ( Value => $value,
12             Error => $error_bar );
13              
14             $obj = new Number::Uncertainty ( Value => $value,
15             Lower => $lower_error_bar,
16             Upper => $upper_error_bar );
17              
18             $obj = new Number::Uncertainty ( Value => $value,
19             Min => $minimum_value,
20             Max => $maximum_value );
21            
22             $obj = new Number::Uncertainty ( Value => $value,
23             Bound => 'lower' );
24              
25             $obj = new Number::Uncertainty ( Value => $value,
26             Bound => 'upper' );
27              
28             =head1 DESCRIPTION
29              
30             Stores information about a value and its error bounds.
31              
32             =cut
33              
34             # L O A D M O D U L E S --------------------------------------------------
35              
36 2     2   11280 use strict;
  2         124  
  2         160  
37 2     2   15 use warnings;
  2         8  
  2         156  
38              
39 2     2   76 use Carp;
  2         5  
  2         411  
40              
41             # Operator overloads
42 2         47 use overload '""' => 'stringify',
43             '==' => 'equal',
44             'eq' => 'equal',
45             '!=' => 'notequal',
46             'ne' => 'notequal',
47             '>' => 'greater_than',
48             '<' => 'less_than',
49 2     2   15 '*' => 'multiply';
  2         4  
50              
51 2     2   454 use vars qw/ $VERSION /;
  2         4  
  2         5015  
52             '$Revision: 1.4 $ ' =~ /.*:\s(.*)\s\$/ && ($VERSION = $1);
53              
54             # C O N S T R U C T O R ----------------------------------------------------
55              
56             =head1 REVISION
57              
58             $Id: Uncertainty.pm,v 1.4 2005/10/26 20:13:57 cavanagh Exp $
59              
60             =head1 METHODS
61              
62             =head2 Constructor
63              
64             =over 4
65              
66             =item B
67              
68             Create a new instance from a hash of options
69              
70             $object = new Number::Uncertainty( %hash );
71              
72             returns a reference a C object. 'Value' is the sole
73             mandatory agruement.
74              
75             =cut
76              
77             sub new {
78 11     11 1 664 my $proto = shift;
79 11   33     50 my $class = ref($proto) || $proto;
80              
81             # bless the query hash into the class
82 11         51 my $block = bless { VALUE => undef,
83             UPPER => undef,
84             LOWER => undef,
85             BOUND => undef }, $class;
86              
87             # Configure the object
88 11         29 $block->configure( @_ );
89              
90 11         32 return $block;
91              
92             }
93              
94             # M E T H O D S -------------------------------------------------------------
95              
96             =back
97              
98             =head2 Accessor Methods
99              
100             =over 4
101              
102             =item B
103              
104             Sets or gets the value of the number
105              
106             $obj->value( $val );
107             $val = $obj->value();
108              
109             =cut
110              
111             sub value {
112 227     227 1 400 my $self = shift;
113              
114 227 100       434 if (@_) {
115 11         57 $self->{VALUE} = shift;
116             }
117 227         587 return $self->{VALUE};
118            
119             }
120              
121             =item B
122              
123             Sets or gets the value of the error
124              
125             $obj->error( $err );
126             $err = $obj->error();
127              
128             =cut
129              
130             sub error {
131 26     26 1 12691 my $self = shift;
132              
133 26 100       60 if (@_) {
134 6         8 my $error = shift;
135 6         12 $self->{LOWER} = 0.5*$error;
136 6         11 $self->{UPPER} = 0.5*$error;
137             }
138            
139 26 100       43 if( defined $self->bound() ) {
140 2         8 return undef;
141             }
142            
143 24         23 my $errorbar;
144 24 100 66     41 if ( defined $self->lower() && defined $self->upper() ) {
145 23         33 $errorbar = abs ( $self->lower() + $self->upper() );
146             } else {
147 1         2 $errorbar = 0;
148             }
149            
150 24         91 return $errorbar;
151            
152             }
153              
154             =item B
155              
156             Sets or gets the value of the lower error value
157              
158             $obj->lower( $lower );
159             $lower = $obj->lower();
160              
161             =cut
162              
163             sub lower {
164 48     48 1 56 my $self = shift;
165              
166 48 100       82 if (@_) {
167 1         2 $self->{LOWER} = shift;
168             }
169            
170 48 50       73 if( defined $self->bound() ) {
171 0         0 return undef;
172             }
173            
174 48         162 return $self->{LOWER};
175             }
176              
177              
178             =item B
179              
180             Sets or gets the value of the upper error value
181              
182             $obj->upper( $upper );
183             $upper = $obj->upper();
184              
185             =cut
186              
187             sub upper {
188 47     47 1 51 my $self = shift;
189              
190 47 100       79 if (@_) {
191 1         2 $self->{UPPER} = shift;
192             }
193            
194 47 50       71 if( defined $self->bound() ) {
195 0         0 return undef;
196             }
197            
198 47         127 return $self->{UPPER};
199             }
200              
201             =item B
202              
203             Sets or gets the value of the minimum value
204              
205             $obj->lower( $min );
206             $min = $obj->min();
207              
208             =cut
209              
210             sub min {
211 75     75 1 94 my $self = shift;
212              
213 75 100       145 if (@_) {
214 1         22 my $min = shift;
215 1         3 $self->{LOWER} = abs ( $self->value() - $min );
216             }
217            
218 75 100       130 if( defined $self->bound() ) {
219 18 100       37 if( $self->bound() eq 'upper' ) {
    50          
220 1         3 return undef;
221             } elsif ( $self->bound() eq 'lower' ) {
222 17         39 return $self->value();
223             }
224             }
225            
226 57         56 my $min;
227 57 100       110 if( defined $self->{LOWER} ) {
228 46         86 $min = $self->value() - $self->{LOWER};
229             } else {
230 11         22 $min = $self->value();
231             }
232 57         206 return $min;
233             }
234              
235              
236             =item B
237              
238             Sets or gets the value of the maximum value
239              
240             $obj->max( $max );
241             $max = $obj->max();
242              
243             =cut
244              
245             sub max {
246 83     83 1 98 my $self = shift;
247              
248 83 100       311 if (@_) {
249 1         1 my $max = shift;
250 1         2 $self->{UPPER} = $max - $self->value();
251             }
252            
253 83 100       143 if( defined $self->bound() ) {
254 18 100       31 if( $self->bound() eq 'upper' ) {
    50          
255 17         47 return $self->value();
256             } elsif ( $self->bound() eq 'lower' ) {
257 1         5 return undef;
258             }
259             }
260            
261 65         85 my $max;
262 65 100       121 if( defined $self->{UPPER} ) {
263 54         98 $max = $self->value() + $self->{UPPER};
264             } else {
265 11         25 $max = $self->value();
266             }
267 65         234 return $max;
268             }
269              
270              
271             =item B
272              
273             Flag to say whether the value() is an upper or lower bound
274              
275             $obj->bound( 'upper' );
276             $obj->bound( 'lower' );
277             $obj->bound( undef );
278             $flag = $obj->bound();
279              
280             =cut
281              
282             sub bound {
283 582     582 1 652 my $self = shift;
284              
285 582 100       1283 if (@_) {
286 2         2 my $flag = shift;
287 2 100       9 if( lc ( $flag ) eq 'upper' ) {
    50          
288 1         2 $self->{BOUND} = 'upper';
289             } elsif ( lc ( $flag ) eq 'lower' ) {
290 1         3 $self->{BOUND} = 'lower';
291             } else {
292 0         0 $self->{BOUND} = undef;
293             }
294             }
295 582         2862 return $self->{BOUND};
296             }
297              
298             # C O N F I G U R E -------------------------------------------------------
299              
300             =back
301              
302             =head2 General Methods
303              
304             =over 4
305              
306             =item B
307              
308             Configures the object, takes an options hash as an argument
309              
310             $obj->configure( %options );
311              
312             Does nothing if the array is not supplied.
313              
314             =cut
315              
316             sub configure {
317 11     11 1 13 my $self = shift;
318              
319             # return unless we have arguments
320 11 50       26 return undef unless @_;
321              
322             # grab the argument list
323 11         47 my %args = @_;
324              
325 11 50 33     30 unless ( defined $args{"Value"} || defined $args{"value"} ) {
326 0         0 croak( "Error - Number::Uncertainty: No value defined..." );
327             }
328            
329             # Loop over the allowed keys and modify the default query options
330 11         21 for my $key (qw / Value Error Lower Upper Bound Min Max / ) {
331 77         87 my $method = lc($key);
332 77 100       192 $self->$method( $args{$key} ) if exists $args{$key};
333             }
334              
335             }
336              
337             # P R I V A T E M E T H O D S ------------------------------------------
338              
339             =back
340              
341             =head2 Operator Overloading
342              
343             These operators are overloaded:
344              
345             =over 4
346              
347             =item B<"">
348              
349             When the object is used in a string context it is stringify'ed.
350              
351             =cut
352              
353             sub stringify {
354 2     2 0 18 my $self = shift;
355            
356 2         4 my $string;
357 2 50       4 if( defined $self->bound() ) {
358 0 0       0 if ( $self->bound() eq 'lower' ) {
    0          
359 0         0 $string = "lower bound of " . $self->value();
360             } elsif ( $self->bound() eq 'upper' ) {
361 0         0 $string = "upper bound of " . $self->value();
362             }
363             } else {
364 2 50       8 if( $self->{UPPER} == $self->{LOWER} ) {
365 2         5 $string = $self->value . " +- " . $self->{UPPER};
366             } else {
367 0         0 $string = $self->value . " + " . $self->{UPPER} .
368             ", - " . $self->{LOWER};
369             }
370            
371             }
372 2         10 return $string;
373             }
374              
375              
376             =item B<==>
377              
378             When the object is equated then we do a comparison and find whether
379             the two values are within the error bounds.
380              
381             =cut
382              
383             sub equal {
384 63     63 0 87 my $self = shift;
385 63         70 my $other = shift;
386            
387 63 50       144 return 0 unless defined $other;
388 63 50       189 return 0 unless UNIVERSAL::isa($other, "Number::Uncertainty" );
389              
390             # both objects are boundary value, bugger...
391 63 100 100     119 if( defined $self->bound() && defined $other->bound() ) {
392             #print "Both objects are boundary objects\n";
393            
394 4 50 66     10 if( ( $self->bound() eq 'upper' && $self->bound() eq 'upper' ) ||
      33        
      66        
395             ( $self->bound() eq 'lower' && $self->bound() eq 'lower' ) ) {
396 4         32 return 1;
397             }
398            
399 0         0 my ($lower, $upper);
400 0 0       0 if ( $self->bound() eq 'lower' ) {
    0          
401 0         0 $lower = $self->min();
402 0         0 $upper = $other->max();
403             } elsif ( $self->bound() eq 'upper' ) {
404 0         0 $upper = $self-> max();
405 0         0 $lower = $other->lower();
406             }
407            
408 0 0       0 if( $lower <= $upper ) {
409 0         0 return 1;
410             } else {
411 0         0 return 0;
412             }
413              
414             }
415            
416             # The self object is a boundary value
417 59 100       110 if( defined $self->bound() ) {
418             #print "The \$self object is a boundary objects\n";
419            
420             # the value is an upper bound
421 16 100       26 if( $self->bound() eq 'upper' ) {
422 8 50       197 if ($other->max() >= $self->max() ) {
423 8         204 return 1;
424             } else {
425 0         0 return 0;
426             }
427             }
428            
429             # the value is an lower bound
430 8 50       18 if( $self->bound() eq 'lower' ) {
431 8 50       17 if ( $other->min() <= $self->min() ) {
432 8         39 return 1;
433             } else {
434 0         0 return 0;
435             }
436             }
437             }
438              
439             # The other object is a boundary value
440 43 100       84 if( defined $other->bound() ) {
441             #print "The \$other object is a boundary objects\n";
442            
443             # the value is an upper bound
444 16 100       31 if( $other->bound() eq 'upper' ) {
445 8 50       21 if ($self->max() >= $other->max() ) {
446 8         39 return 1;
447             } else {
448 0         0 return 0;
449             }
450             }
451            
452             # the value is an lower bound
453 8 50       28 if( $other->bound() eq 'lower' ) {
454 8 50       18 if ( $self->min() <= $other->min() ) {
455 8         36 return 1;
456             } else {
457 0         0 return 0;
458             }
459             }
460             }
461              
462             # Case 1) The upper and lower bound of the $other object
463             # falls within the bounds of the $self object
464 27 100 66     58 if ( ( $other->value() <= $self->max() ) &&
465             ( $other->value() >= $self->min() ) ) {
466 25         128 return 1;
467             }
468            
469             # Case 2) The lower bound of the $other object falls within
470             # the bound of the self object, but the upper bound is outside
471 2 50 33     7 if( ( $other->min() <= $self->max() ) &&
472             ( $other->max() >= $self->max() ) ) {
473 0         0 return 1;
474             }
475              
476             # Case 3) The upper bound of the $other object falls within
477             # the bound of the self object, but the lower bound is outside
478 2 50 33     6 if( ( $other->max() >= $self->min() ) &&
479             ( $other->min() <= $self->min() ) ) {
480 0         0 return 1;
481             }
482            
483             # Case 4) The self object lies within the bounds of the other
484 2 50 33     5 if( ( $other->max() >= $self->max() ) &&
485             ( $other->min() <= $self->min() ) ) {
486 0         0 return 1;
487             }
488            
489             # We don't have any overlap
490 2         11 return 0;
491              
492             }
493              
494             =item B
495              
496             When the object is equated then we do a comparison and find whether
497             the two values are within the error bounds.
498              
499             =cut
500              
501             sub notequal {
502 31     31 0 211 my $self = shift;
503 31         35 my $other = shift;
504            
505 31         60 return !($self->equal( $other ));
506              
507             }
508              
509             =item B
510              
511             =cut
512              
513             sub greater_than {
514 2     2 1 7 my $self = shift;
515 2         3 my $other = shift;
516              
517 2 50       9 if( ! UNIVERSAL::isa( $other, "Number::Uncertainty" ) ) {
518 0 0       0 if( defined( $self->error ) ) {
519 0         0 return ( ( $self->max ) > $other );
520             } else {
521 0         0 return ( $self->value > $other );
522             }
523             } else {
524 2 50       5 if( defined( $self->error ) ) {
525 2 50       4 if( defined( $other->error ) ) {
526 2         6 return ( $self->max > $other->min );
527             } else {
528 0         0 return ( $self->max > $other->value );
529             }
530             } else {
531 0 0       0 if( defined( $other->error ) ) {
532 0         0 return ( $self->value > $other->min );
533             } else {
534 0         0 return ( $self->value > $other->value );
535             }
536             }
537             }
538             }
539              
540             =item B
541              
542             =cut
543              
544             sub less_than {
545 2     2 1 4 my $self = shift;
546 2         3 my $other = shift;
547              
548 2 50       10 if( ! UNIVERSAL::isa( $other, "Number::Uncertainty" ) ) {
549 0 0       0 if( defined( $self->error ) ) {
550 0         0 return ( ( $self->min ) < $other );
551             } else {
552 0         0 return ( $self->value < $other );
553             }
554             } else {
555 2 50       5 if( defined( $self->error ) ) {
556 2 50       5 if( defined( $other->error ) ) {
557 2         5 return ( $self->min < $other->max );
558             } else {
559 0         0 return ( $self->min < $other->value );
560             }
561             } else {
562 0 0       0 if( defined( $other->error ) ) {
563 0         0 return ( $self->value < $other->max );
564             } else {
565 0         0 return ( $self->value < $other->value );
566             }
567             }
568             }
569             }
570              
571             =item B<*>
572              
573             When the object is multiplied.
574              
575             =cut
576              
577             sub multiply {
578 1     1 0 2 my $self = shift;
579 1         2 my $other = shift;
580            
581 1 50       5 if ( !UNIVERSAL::isa( $other, "Number::Uncertainty" ) ) {
582 0 0       0 if( defined $self->error() ) {
583 0         0 my $value = $self->value()*$other;
584 0         0 my $error = $self->error();
585 0         0 return new Number::Uncertainty( Value => $value, Error => $error );
586             } else {
587 0         0 my $value = $self->value()*$other;
588 0         0 return new Number::Uncertainty( Value => $value );
589             }
590             }
591            
592 1         4 my $value = $self->value() * $other->value();
593 1 50 33     3 if( defined $self->bound() || defined $other->bound() ) {
594 0         0 return new Number::Uncertainty( Value => $value );
595             }
596            
597 1 50 33     3 if( defined $self->error() && defined $other->error() ) {
598 1         3 my $error = sqrt ( $self->error()*$self->error() +
599             $other->error()*$other->error() );
600 1         4 return new Number::Uncertainty( Value => $value, Error => $error );
601             }
602              
603             }
604              
605             =back
606              
607             =head1 COPYRIGHT
608              
609             Copyright (C) 2005 University of Exeter. All Rights Reserved.
610              
611             This program was written as part of the eSTAR project and is free software;
612             you can redistribute it and/or modify it under the terms of the GNU Public
613             License.
614              
615             =head1 AUTHORS
616              
617             Alasdair Allan Eaa@astro.ex.ac.ukE,
618              
619             =cut
620              
621             # L A S T O R D E R S ------------------------------------------------------
622              
623             1;