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 |