Commit | Line | Data |
---|---|---|
a4e2b1c6 JH |
1 | |
2 | # | |
7d341013 | 3 | # "Tax the rat farms." - Lord Vetinari |
a4e2b1c6 | 4 | # |
184f15d5 JH |
5 | |
6 | # The following hash values are used: | |
7 | # sign : +,-,NaN,+inf,-inf | |
8 | # _d : denominator | |
9 | # _n : numeraotr (value = _n/_d) | |
10 | # _a : accuracy | |
11 | # _p : precision | |
7afd7a91 | 12 | # You should not look at the innards of a BigRat - use the methods for this. |
184f15d5 JH |
13 | |
14 | package Math::BigRat; | |
15 | ||
b8884ce4 | 16 | # anythig older is untested, and unlikely to work |
08a3f4a9 | 17 | use 5.006; |
184f15d5 JH |
18 | use strict; |
19 | ||
184f15d5 | 20 | use Math::BigFloat; |
12fc2493 | 21 | use vars qw($VERSION @ISA $upgrade $downgrade |
990fb837 | 22 | $accuracy $precision $round_mode $div_scale $_trap_nan $_trap_inf); |
184f15d5 | 23 | |
233f7bc0 | 24 | @ISA = qw(Math::BigFloat); |
184f15d5 | 25 | |
07d14be5 | 26 | $VERSION = '0.25'; |
c6c613ed | 27 | $VERSION = eval $VERSION; |
184f15d5 | 28 | |
12fc2493 | 29 | use overload; # inherit overload from Math::BigFloat |
184f15d5 | 30 | |
12fc2493 AMS |
31 | BEGIN |
32 | { | |
33 | *objectify = \&Math::BigInt::objectify; # inherit this from BigInt | |
34 | *AUTOLOAD = \&Math::BigFloat::AUTOLOAD; # can't inherit AUTOLOAD | |
35 | # we inherit these from BigFloat because currently it is not possible | |
36 | # that MBF has a different $MBI variable than we, because MBF also uses | |
37 | # Math::BigInt::config->('lib'); (there is always only one library loaded) | |
38 | *_e_add = \&Math::BigFloat::_e_add; | |
39 | *_e_sub = \&Math::BigFloat::_e_sub; | |
b68b7ab1 T |
40 | *as_int = \&as_number; |
41 | *is_pos = \&is_positive; | |
42 | *is_neg = \&is_negative; | |
12fc2493 | 43 | } |
9b924220 | 44 | |
184f15d5 | 45 | ############################################################################## |
12fc2493 | 46 | # Global constants and flags. Access these only via the accessor methods! |
184f15d5 | 47 | |
184f15d5 JH |
48 | $accuracy = $precision = undef; |
49 | $round_mode = 'even'; | |
50 | $div_scale = 40; | |
51 | $upgrade = undef; | |
52 | $downgrade = undef; | |
53 | ||
12fc2493 | 54 | # These are internally, and not to be used from the outside at all! |
990fb837 RGS |
55 | |
56 | $_trap_nan = 0; # are NaNs ok? set w/ config() | |
57 | $_trap_inf = 0; # are infs ok? set w/ config() | |
58 | ||
12fc2493 AMS |
59 | # the package we are using for our private parts, defaults to: |
60 | # Math::BigInt->config()->{lib} | |
61 | my $MBI = 'Math::BigInt::Calc'; | |
62 | ||
184f15d5 | 63 | my $nan = 'NaN'; |
9b924220 | 64 | my $class = 'Math::BigRat'; |
184f15d5 | 65 | |
8f675a64 JH |
66 | sub isa |
67 | { | |
68 | return 0 if $_[1] =~ /^Math::Big(Int|Float)/; # we aren't | |
69 | UNIVERSAL::isa(@_); | |
70 | } | |
71 | ||
12fc2493 | 72 | ############################################################################## |
9b924220 | 73 | |
184f15d5 JH |
74 | sub _new_from_float |
75 | { | |
7afd7a91 | 76 | # turn a single float input into a rational number (like '0.1') |
184f15d5 JH |
77 | my ($self,$f) = @_; |
78 | ||
79 | return $self->bnan() if $f->is_nan(); | |
9b924220 | 80 | return $self->binf($f->{sign}) if $f->{sign} =~ /^[+-]inf$/; |
184f15d5 | 81 | |
12fc2493 AMS |
82 | $self->{_n} = $MBI->_copy( $f->{_m} ); # mantissa |
83 | $self->{_d} = $MBI->_one(); | |
9b924220 RGS |
84 | $self->{sign} = $f->{sign} || '+'; |
85 | if ($f->{_es} eq '-') | |
184f15d5 JH |
86 | { |
87 | # something like Math::BigRat->new('0.1'); | |
9b924220 | 88 | # 1 / 1 => 1/10 |
12fc2493 | 89 | $MBI->_lsft ( $self->{_d}, $f->{_e} ,10); |
184f15d5 JH |
90 | } |
91 | else | |
92 | { | |
93 | # something like Math::BigRat->new('10'); | |
94 | # 1 / 1 => 10/1 | |
12fc2493 AMS |
95 | $MBI->_lsft ( $self->{_n}, $f->{_e} ,10) unless |
96 | $MBI->_is_zero($f->{_e}); | |
184f15d5 | 97 | } |
184f15d5 JH |
98 | $self; |
99 | } | |
100 | ||
101 | sub new | |
102 | { | |
103 | # create a Math::BigRat | |
104 | my $class = shift; | |
105 | ||
b68b7ab1 | 106 | my ($n,$d) = @_; |
184f15d5 JH |
107 | |
108 | my $self = { }; bless $self,$class; | |
109 | ||
b68b7ab1 | 110 | # input like (BigInt) or (BigFloat): |
6de7f0cc | 111 | if ((!defined $d) && (ref $n) && (!$n->isa('Math::BigRat'))) |
184f15d5 | 112 | { |
184f15d5 JH |
113 | if ($n->isa('Math::BigFloat')) |
114 | { | |
7afd7a91 | 115 | $self->_new_from_float($n); |
184f15d5 JH |
116 | } |
117 | if ($n->isa('Math::BigInt')) | |
118 | { | |
990fb837 | 119 | # TODO: trap NaN, inf |
b68b7ab1 | 120 | $self->{_n} = $MBI->_copy($n->{value}); # "mantissa" = N |
12fc2493 AMS |
121 | $self->{_d} = $MBI->_one(); # d => 1 |
122 | $self->{sign} = $n->{sign}; | |
8f675a64 JH |
123 | } |
124 | if ($n->isa('Math::BigInt::Lite')) | |
125 | { | |
990fb837 RGS |
126 | # TODO: trap NaN, inf |
127 | $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0; | |
b68b7ab1 | 128 | $self->{_n} = $MBI->_new(abs($$n)); # "mantissa" = N |
12fc2493 | 129 | $self->{_d} = $MBI->_one(); # d => 1 |
184f15d5 | 130 | } |
12fc2493 | 131 | return $self->bnorm(); # normalize (120/1 => 12/10) |
184f15d5 | 132 | } |
b68b7ab1 T |
133 | |
134 | # input like (BigInt,BigInt) or (BigLite,BigLite): | |
135 | if (ref($d) && ref($n)) | |
136 | { | |
137 | # do N first (for $self->{sign}): | |
138 | if ($n->isa('Math::BigInt')) | |
139 | { | |
140 | # TODO: trap NaN, inf | |
141 | $self->{_n} = $MBI->_copy($n->{value}); # "mantissa" = N | |
142 | $self->{sign} = $n->{sign}; | |
143 | } | |
144 | elsif ($n->isa('Math::BigInt::Lite')) | |
145 | { | |
146 | # TODO: trap NaN, inf | |
147 | $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0; | |
148 | $self->{_n} = $MBI->_new(abs($$n)); # "mantissa" = $n | |
149 | } | |
150 | else | |
151 | { | |
152 | require Carp; | |
153 | Carp::croak(ref($n) . " is not a recognized object format for Math::BigRat->new"); | |
154 | } | |
155 | # now D: | |
156 | if ($d->isa('Math::BigInt')) | |
157 | { | |
158 | # TODO: trap NaN, inf | |
159 | $self->{_d} = $MBI->_copy($d->{value}); # "mantissa" = D | |
160 | # +/+ or -/- => +, +/- or -/+ => - | |
161 | $self->{sign} = $d->{sign} ne $self->{sign} ? '-' : '+'; | |
162 | } | |
163 | elsif ($d->isa('Math::BigInt::Lite')) | |
164 | { | |
165 | # TODO: trap NaN, inf | |
166 | $self->{_d} = $MBI->_new(abs($$d)); # "mantissa" = D | |
167 | my $ds = '+'; $ds = '-' if $$d < 0; | |
168 | # +/+ or -/- => +, +/- or -/+ => - | |
169 | $self->{sign} = $ds ne $self->{sign} ? '-' : '+'; | |
170 | } | |
171 | else | |
172 | { | |
173 | require Carp; | |
174 | Carp::croak(ref($d) . " is not a recognized object format for Math::BigRat->new"); | |
175 | } | |
176 | return $self->bnorm(); # normalize (120/1 => 12/10) | |
177 | } | |
12fc2493 | 178 | return $n->copy() if ref $n; # already a BigRat |
184f15d5 JH |
179 | |
180 | if (!defined $n) | |
181 | { | |
12fc2493 AMS |
182 | $self->{_n} = $MBI->_zero(); # undef => 0 |
183 | $self->{_d} = $MBI->_one(); | |
184f15d5 | 184 | $self->{sign} = '+'; |
12fc2493 | 185 | return $self; |
184f15d5 | 186 | } |
12fc2493 | 187 | |
184f15d5 JH |
188 | # string input with / delimiter |
189 | if ($n =~ /\s*\/\s*/) | |
190 | { | |
990fb837 RGS |
191 | return $class->bnan() if $n =~ /\/.*\//; # 1/2/3 isn't valid |
192 | return $class->bnan() if $n =~ /\/\s*$/; # 1/ isn't valid | |
184f15d5 JH |
193 | ($n,$d) = split (/\//,$n); |
194 | # try as BigFloats first | |
195 | if (($n =~ /[\.eE]/) || ($d =~ /[\.eE]/)) | |
196 | { | |
7d341013 T |
197 | local $Math::BigFloat::accuracy = undef; |
198 | local $Math::BigFloat::precision = undef; | |
9b924220 | 199 | |
12fc2493 | 200 | # one of them looks like a float |
9b924220 | 201 | my $nf = Math::BigFloat->new($n,undef,undef); |
990fb837 RGS |
202 | $self->{sign} = '+'; |
203 | return $self->bnan() if $nf->is_nan(); | |
233f7bc0 | 204 | |
12fc2493 | 205 | $self->{_n} = $MBI->_copy( $nf->{_m} ); # get mantissa |
9b924220 | 206 | |
184f15d5 | 207 | # now correct $self->{_n} due to $n |
7d341013 | 208 | my $f = Math::BigFloat->new($d,undef,undef); |
990fb837 | 209 | return $self->bnan() if $f->is_nan(); |
12fc2493 | 210 | $self->{_d} = $MBI->_copy( $f->{_m} ); |
9b924220 | 211 | |
990fb837 | 212 | # calculate the difference between nE and dE |
bd49aa09 | 213 | my $diff_e = $nf->exponent()->bsub( $f->exponent); |
990fb837 RGS |
214 | if ($diff_e->is_negative()) |
215 | { | |
216 | # < 0: mul d with it | |
12fc2493 | 217 | $MBI->_lsft( $self->{_d}, $MBI->_new( $diff_e->babs()), 10); |
990fb837 RGS |
218 | } |
219 | elsif (!$diff_e->is_zero()) | |
184f15d5 | 220 | { |
990fb837 | 221 | # > 0: mul n with it |
12fc2493 | 222 | $MBI->_lsft( $self->{_n}, $MBI->_new( $diff_e), 10); |
184f15d5 | 223 | } |
184f15d5 JH |
224 | } |
225 | else | |
226 | { | |
12fc2493 AMS |
227 | # both d and n look like (big)ints |
228 | ||
229 | $self->{sign} = '+'; # no sign => '+' | |
230 | $self->{_n} = undef; | |
231 | $self->{_d} = undef; | |
b8884ce4 | 232 | if ($n =~ /^([+-]?)0*([0-9]+)\z/) # first part ok? |
12fc2493 AMS |
233 | { |
234 | $self->{sign} = $1 || '+'; # no sign => '+' | |
235 | $self->{_n} = $MBI->_new($2 || 0); | |
236 | } | |
237 | ||
b8884ce4 | 238 | if ($d =~ /^([+-]?)0*([0-9]+)\z/) # second part ok? |
12fc2493 AMS |
239 | { |
240 | $self->{sign} =~ tr/+-/-+/ if ($1 || '') eq '-'; # negate if second part neg. | |
241 | $self->{_d} = $MBI->_new($2 || 0); | |
242 | } | |
243 | ||
244 | if (!defined $self->{_n} || !defined $self->{_d}) | |
245 | { | |
246 | $d = Math::BigInt->new($d,undef,undef) unless ref $d; | |
247 | $n = Math::BigInt->new($n,undef,undef) unless ref $n; | |
233f7bc0 | 248 | |
12fc2493 AMS |
249 | if ($n->{sign} =~ /^[+-]$/ && $d->{sign} =~ /^[+-]$/) |
250 | { | |
251 | # both parts are ok as integers (wierd things like ' 1e0' | |
252 | $self->{_n} = $MBI->_copy($n->{value}); | |
253 | $self->{_d} = $MBI->_copy($d->{value}); | |
254 | $self->{sign} = $n->{sign}; | |
255 | $self->{sign} =~ tr/+-/-+/ if $d->{sign} eq '-'; # -1/-2 => 1/2 | |
256 | return $self->bnorm(); | |
257 | } | |
258 | ||
259 | $self->{sign} = '+'; # a default sign | |
260 | return $self->bnan() if $n->is_nan() || $d->is_nan(); | |
261 | ||
262 | # handle inf cases: | |
263 | if ($n->is_inf() || $d->is_inf()) | |
7afd7a91 | 264 | { |
12fc2493 AMS |
265 | if ($n->is_inf()) |
266 | { | |
267 | return $self->bnan() if $d->is_inf(); # both are inf => NaN | |
268 | my $s = '+'; # '+inf/+123' or '-inf/-123' | |
269 | $s = '-' if substr($n->{sign},0,1) ne $d->{sign}; | |
270 | # +-inf/123 => +-inf | |
271 | return $self->binf($s); | |
272 | } | |
273 | # 123/inf => 0 | |
274 | return $self->bzero(); | |
7afd7a91 | 275 | } |
12fc2493 | 276 | } |
184f15d5 | 277 | } |
990fb837 | 278 | |
184f15d5 JH |
279 | return $self->bnorm(); |
280 | } | |
281 | ||
282 | # simple string input | |
c6c613ed | 283 | if (($n =~ /[\.eE]/) && $n !~ /^0x/) |
184f15d5 | 284 | { |
7d341013 | 285 | # looks like a float, quacks like a float, so probably is a float |
12fc2493 | 286 | $self->{sign} = 'NaN'; |
7d341013 T |
287 | local $Math::BigFloat::accuracy = undef; |
288 | local $Math::BigFloat::precision = undef; | |
7d341013 | 289 | $self->_new_from_float(Math::BigFloat->new($n,undef,undef)); |
184f15d5 JH |
290 | } |
291 | else | |
292 | { | |
12fc2493 | 293 | # for simple forms, use $MBI directly |
b8884ce4 | 294 | if ($n =~ /^([+-]?)0*([0-9]+)\z/) |
12fc2493 AMS |
295 | { |
296 | $self->{sign} = $1 || '+'; | |
297 | $self->{_n} = $MBI->_new($2 || 0); | |
298 | $self->{_d} = $MBI->_one(); | |
299 | } | |
300 | else | |
301 | { | |
302 | my $n = Math::BigInt->new($n,undef,undef); | |
303 | $self->{_n} = $MBI->_copy($n->{value}); | |
304 | $self->{_d} = $MBI->_one(); | |
305 | $self->{sign} = $n->{sign}; | |
306 | return $self->bnan() if $self->{sign} eq 'NaN'; | |
307 | return $self->binf($self->{sign}) if $self->{sign} =~ /^[+-]inf$/; | |
308 | } | |
184f15d5 JH |
309 | } |
310 | $self->bnorm(); | |
311 | } | |
312 | ||
9b924220 RGS |
313 | sub copy |
314 | { | |
b68b7ab1 T |
315 | # if two arguments, the first one is the class to "swallow" subclasses |
316 | my ($c,$x) = @_; | |
317 | ||
318 | if (scalar @_ == 1) | |
9b924220 | 319 | { |
b68b7ab1 | 320 | $x = $_[0]; |
9b924220 RGS |
321 | $c = ref($x); |
322 | } | |
323 | return unless ref($x); # only for objects | |
324 | ||
12fc2493 | 325 | my $self = bless {}, $c; |
9b924220 RGS |
326 | |
327 | $self->{sign} = $x->{sign}; | |
12fc2493 AMS |
328 | $self->{_d} = $MBI->_copy($x->{_d}); |
329 | $self->{_n} = $MBI->_copy($x->{_n}); | |
9b924220 RGS |
330 | $self->{_a} = $x->{_a} if defined $x->{_a}; |
331 | $self->{_p} = $x->{_p} if defined $x->{_p}; | |
332 | $self; | |
333 | } | |
334 | ||
990fb837 RGS |
335 | ############################################################################## |
336 | ||
337 | sub config | |
338 | { | |
339 | # return (later set?) configuration data as hash ref | |
b68b7ab1 | 340 | my $class = shift || 'Math::BigRat'; |
990fb837 | 341 | |
116a1b2f SP |
342 | if (@_ == 1 && ref($_[0]) ne 'HASH') |
343 | { | |
344 | my $cfg = $class->SUPER::config(); | |
345 | return $cfg->{$_[0]}; | |
346 | } | |
347 | ||
990fb837 RGS |
348 | my $cfg = $class->SUPER::config(@_); |
349 | ||
350 | # now we need only to override the ones that are different from our parent | |
351 | $cfg->{class} = $class; | |
352 | $cfg->{with} = $MBI; | |
353 | $cfg; | |
354 | } | |
355 | ||
356 | ############################################################################## | |
8f675a64 | 357 | |
184f15d5 JH |
358 | sub bstr |
359 | { | |
7afd7a91 | 360 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
184f15d5 JH |
361 | |
362 | if ($x->{sign} !~ /^[+-]$/) # inf, NaN etc | |
363 | { | |
364 | my $s = $x->{sign}; $s =~ s/^\+//; # +inf => inf | |
365 | return $s; | |
366 | } | |
367 | ||
7afd7a91 | 368 | my $s = ''; $s = $x->{sign} if $x->{sign} ne '+'; # '+3/2' => '3/2' |
184f15d5 | 369 | |
12fc2493 AMS |
370 | return $s . $MBI->_str($x->{_n}) if $MBI->_is_one($x->{_d}); |
371 | $s . $MBI->_str($x->{_n}) . '/' . $MBI->_str($x->{_d}); | |
184f15d5 JH |
372 | } |
373 | ||
374 | sub bsstr | |
375 | { | |
b68b7ab1 | 376 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
184f15d5 JH |
377 | |
378 | if ($x->{sign} !~ /^[+-]$/) # inf, NaN etc | |
379 | { | |
380 | my $s = $x->{sign}; $s =~ s/^\+//; # +inf => inf | |
381 | return $s; | |
382 | } | |
383 | ||
384 | my $s = ''; $s = $x->{sign} if $x->{sign} ne '+'; # +3 vs 3 | |
12fc2493 | 385 | $s . $MBI->_str($x->{_n}) . '/' . $MBI->_str($x->{_d}); |
184f15d5 JH |
386 | } |
387 | ||
388 | sub bnorm | |
389 | { | |
12fc2493 | 390 | # reduce the number to the shortest form |
b68b7ab1 | 391 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
184f15d5 | 392 | |
12fc2493 | 393 | # Both parts must be objects of whatever we are using today. |
bd49aa09 | 394 | if ( my $c = $MBI->_check($x->{_n}) ) |
990fb837 | 395 | { |
bd49aa09 | 396 | require Carp; Carp::croak ("n did not pass the self-check ($c) in bnorm()"); |
990fb837 | 397 | } |
bd49aa09 | 398 | if ( my $c = $MBI->_check($x->{_d}) ) |
990fb837 | 399 | { |
bd49aa09 | 400 | require Carp; Carp::croak ("d did not pass the self-check ($c) in bnorm()"); |
990fb837 | 401 | } |
6de7f0cc | 402 | |
6de7f0cc JH |
403 | # no normalize for NaN, inf etc. |
404 | return $x if $x->{sign} !~ /^[+-]$/; | |
405 | ||
184f15d5 | 406 | # normalize zeros to 0/1 |
12fc2493 | 407 | if ($MBI->_is_zero($x->{_n})) |
184f15d5 | 408 | { |
12fc2493 AMS |
409 | $x->{sign} = '+'; # never leave a -0 |
410 | $x->{_d} = $MBI->_one() unless $MBI->_is_one($x->{_d}); | |
184f15d5 JH |
411 | return $x; |
412 | } | |
413 | ||
12fc2493 | 414 | return $x if $MBI->_is_one($x->{_d}); # no need to reduce |
6de7f0cc | 415 | |
184f15d5 | 416 | # reduce other numbers |
12fc2493 AMS |
417 | my $gcd = $MBI->_copy($x->{_n}); |
418 | $gcd = $MBI->_gcd($gcd,$x->{_d}); | |
419 | ||
420 | if (!$MBI->_is_one($gcd)) | |
184f15d5 | 421 | { |
12fc2493 AMS |
422 | $x->{_n} = $MBI->_div($x->{_n},$gcd); |
423 | $x->{_d} = $MBI->_div($x->{_d},$gcd); | |
184f15d5 | 424 | } |
184f15d5 JH |
425 | $x; |
426 | } | |
427 | ||
428 | ############################################################################## | |
b68b7ab1 T |
429 | # sign manipulation |
430 | ||
431 | sub bneg | |
432 | { | |
433 | # (BRAT or num_str) return BRAT | |
434 | # negate number or make a negated number from string | |
435 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); | |
436 | ||
437 | return $x if $x->modify('bneg'); | |
438 | ||
439 | # for +0 dont negate (to have always normalized +0). Does nothing for 'NaN' | |
440 | $x->{sign} =~ tr/+-/-+/ unless ($x->{sign} eq '+' && $MBI->_is_zero($x->{_n})); | |
441 | $x; | |
442 | } | |
443 | ||
444 | ############################################################################## | |
184f15d5 JH |
445 | # special values |
446 | ||
447 | sub _bnan | |
448 | { | |
990fb837 | 449 | # used by parent class bnan() to initialize number to NaN |
184f15d5 | 450 | my $self = shift; |
990fb837 RGS |
451 | |
452 | if ($_trap_nan) | |
453 | { | |
454 | require Carp; | |
455 | my $class = ref($self); | |
233f7bc0 T |
456 | # "$self" below will stringify the object, this blows up if $self is a |
457 | # partial object (happens under trap_nan), so fix it beforehand | |
458 | $self->{_d} = $MBI->_zero() unless defined $self->{_d}; | |
459 | $self->{_n} = $MBI->_zero() unless defined $self->{_n}; | |
990fb837 RGS |
460 | Carp::croak ("Tried to set $self to NaN in $class\::_bnan()"); |
461 | } | |
12fc2493 AMS |
462 | $self->{_n} = $MBI->_zero(); |
463 | $self->{_d} = $MBI->_zero(); | |
184f15d5 JH |
464 | } |
465 | ||
466 | sub _binf | |
467 | { | |
7d341013 | 468 | # used by parent class bone() to initialize number to +inf/-inf |
184f15d5 | 469 | my $self = shift; |
990fb837 RGS |
470 | |
471 | if ($_trap_inf) | |
472 | { | |
473 | require Carp; | |
474 | my $class = ref($self); | |
233f7bc0 T |
475 | # "$self" below will stringify the object, this blows up if $self is a |
476 | # partial object (happens under trap_nan), so fix it beforehand | |
477 | $self->{_d} = $MBI->_zero() unless defined $self->{_d}; | |
478 | $self->{_n} = $MBI->_zero() unless defined $self->{_n}; | |
990fb837 RGS |
479 | Carp::croak ("Tried to set $self to inf in $class\::_binf()"); |
480 | } | |
12fc2493 AMS |
481 | $self->{_n} = $MBI->_zero(); |
482 | $self->{_d} = $MBI->_zero(); | |
184f15d5 JH |
483 | } |
484 | ||
485 | sub _bone | |
486 | { | |
7d341013 | 487 | # used by parent class bone() to initialize number to +1/-1 |
184f15d5 | 488 | my $self = shift; |
12fc2493 AMS |
489 | $self->{_n} = $MBI->_one(); |
490 | $self->{_d} = $MBI->_one(); | |
184f15d5 JH |
491 | } |
492 | ||
493 | sub _bzero | |
494 | { | |
990fb837 | 495 | # used by parent class bzero() to initialize number to 0 |
184f15d5 | 496 | my $self = shift; |
12fc2493 AMS |
497 | $self->{_n} = $MBI->_zero(); |
498 | $self->{_d} = $MBI->_one(); | |
184f15d5 JH |
499 | } |
500 | ||
501 | ############################################################################## | |
502 | # mul/add/div etc | |
503 | ||
504 | sub badd | |
505 | { | |
7afd7a91 | 506 | # add two rational numbers |
7d341013 T |
507 | |
508 | # set up parameters | |
509 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
510 | # objectify is costly, so avoid it | |
511 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
512 | { | |
513 | ($self,$x,$y,@r) = objectify(2,@_); | |
514 | } | |
184f15d5 | 515 | |
12fc2493 AMS |
516 | # +inf + +inf => +inf, -inf + -inf => -inf |
517 | return $x->binf(substr($x->{sign},0,1)) | |
518 | if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/; | |
184f15d5 | 519 | |
12fc2493 AMS |
520 | # +inf + -inf or -inf + +inf => NaN |
521 | return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/); | |
184f15d5 JH |
522 | |
523 | # 1 1 gcd(3,4) = 1 1*3 + 1*4 7 | |
524 | # - + - = --------- = -- | |
525 | # 4 3 4*3 12 | |
526 | ||
7d341013 | 527 | # we do not compute the gcd() here, but simple do: |
233f7bc0 | 528 | # 5 7 5*3 + 7*4 43 |
7d341013 T |
529 | # - + - = --------- = -- |
530 | # 4 3 4*3 12 | |
531 | ||
12fc2493 | 532 | # and bnorm() will then take care of the rest |
184f15d5 | 533 | |
233f7bc0 | 534 | # 5 * 3 |
12fc2493 | 535 | $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_d}); |
7d341013 | 536 | |
233f7bc0 | 537 | # 7 * 4 |
12fc2493 | 538 | my $m = $MBI->_mul( $MBI->_copy( $y->{_n} ), $x->{_d} ); |
184f15d5 | 539 | |
233f7bc0 | 540 | # 5 * 3 + 7 * 4 |
12fc2493 | 541 | ($x->{_n}, $x->{sign}) = _e_add( $x->{_n}, $m, $x->{sign}, $y->{sign}); |
184f15d5 | 542 | |
233f7bc0 | 543 | # 4 * 3 |
12fc2493 | 544 | $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_d}); |
184f15d5 | 545 | |
233f7bc0 | 546 | # normalize result, and possible round |
7d341013 | 547 | $x->bnorm()->round(@r); |
184f15d5 JH |
548 | } |
549 | ||
550 | sub bsub | |
551 | { | |
7afd7a91 | 552 | # subtract two rational numbers |
7d341013 T |
553 | |
554 | # set up parameters | |
555 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
556 | # objectify is costly, so avoid it | |
557 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
558 | { | |
559 | ($self,$x,$y,@r) = objectify(2,@_); | |
560 | } | |
184f15d5 | 561 | |
7afd7a91 T |
562 | # flip sign of $x, call badd(), then flip sign of result |
563 | $x->{sign} =~ tr/+-/-+/ | |
12fc2493 AMS |
564 | unless $x->{sign} eq '+' && $MBI->_is_zero($x->{_n}); # not -0 |
565 | $x->badd($y,@r); # does norm and round | |
7afd7a91 | 566 | $x->{sign} =~ tr/+-/-+/ |
12fc2493 | 567 | unless $x->{sign} eq '+' && $MBI->_is_zero($x->{_n}); # not -0 |
7afd7a91 | 568 | $x; |
184f15d5 JH |
569 | } |
570 | ||
571 | sub bmul | |
572 | { | |
7afd7a91 | 573 | # multiply two rational numbers |
7d341013 T |
574 | |
575 | # set up parameters | |
576 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
577 | # objectify is costly, so avoid it | |
578 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
579 | { | |
580 | ($self,$x,$y,@r) = objectify(2,@_); | |
581 | } | |
184f15d5 JH |
582 | |
583 | return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN'); | |
584 | ||
585 | # inf handling | |
586 | if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/)) | |
587 | { | |
588 | return $x->bnan() if $x->is_zero() || $y->is_zero(); | |
589 | # result will always be +-inf: | |
590 | # +inf * +/+inf => +inf, -inf * -/-inf => +inf | |
591 | # +inf * -/-inf => -inf, -inf * +/+inf => -inf | |
592 | return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/); | |
593 | return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/); | |
594 | return $x->binf('-'); | |
595 | } | |
596 | ||
597 | # x== 0 # also: or y == 1 or y == -1 | |
598 | return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero(); | |
599 | ||
12fc2493 AMS |
600 | # XXX TODO: |
601 | # According to Knuth, this can be optimized by doing gcd twice (for d and n) | |
602 | # and reducing in one step. This would save us the bnorm() at the end. | |
184f15d5 | 603 | |
12fc2493 AMS |
604 | # 1 2 1 * 2 2 1 |
605 | # - * - = ----- = - = - | |
606 | # 4 3 4 * 3 12 6 | |
7d341013 | 607 | |
12fc2493 AMS |
608 | $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_n}); |
609 | $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_d}); | |
184f15d5 JH |
610 | |
611 | # compute new sign | |
612 | $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-'; | |
613 | ||
7d341013 | 614 | $x->bnorm()->round(@r); |
184f15d5 JH |
615 | } |
616 | ||
617 | sub bdiv | |
618 | { | |
619 | # (dividend: BRAT or num_str, divisor: BRAT or num_str) return | |
620 | # (BRAT,BRAT) (quo,rem) or BRAT (only rem) | |
7d341013 T |
621 | |
622 | # set up parameters | |
623 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
624 | # objectify is costly, so avoid it | |
625 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
626 | { | |
627 | ($self,$x,$y,@r) = objectify(2,@_); | |
628 | } | |
184f15d5 JH |
629 | |
630 | return $self->_div_inf($x,$y) | |
631 | if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero()); | |
632 | ||
633 | # x== 0 # also: or y == 1 or y == -1 | |
634 | return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero(); | |
635 | ||
12fc2493 AMS |
636 | # XXX TODO: list context, upgrade |
637 | # According to Knuth, this can be optimized by doing gcd twice (for d and n) | |
638 | # and reducing in one step. This would save us the bnorm() at the end. | |
184f15d5 | 639 | |
184f15d5 JH |
640 | # 1 1 1 3 |
641 | # - / - == - * - | |
642 | # 4 3 4 1 | |
7d341013 | 643 | |
12fc2493 AMS |
644 | $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_d}); |
645 | $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_n}); | |
184f15d5 JH |
646 | |
647 | # compute new sign | |
648 | $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-'; | |
649 | ||
7d341013 | 650 | $x->bnorm()->round(@r); |
6de7f0cc | 651 | $x; |
184f15d5 JH |
652 | } |
653 | ||
990fb837 RGS |
654 | sub bmod |
655 | { | |
656 | # compute "remainder" (in Perl way) of $x / $y | |
657 | ||
658 | # set up parameters | |
659 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
660 | # objectify is costly, so avoid it | |
661 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
662 | { | |
663 | ($self,$x,$y,@r) = objectify(2,@_); | |
664 | } | |
665 | ||
990fb837 RGS |
666 | return $self->_div_inf($x,$y) |
667 | if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero()); | |
668 | ||
669 | return $x if $x->is_zero(); # 0 / 7 = 0, mod 0 | |
670 | ||
671 | # compute $x - $y * floor($x/$y), keeping the sign of $x | |
672 | ||
12fc2493 AMS |
673 | # copy x to u, make it positive and then do a normal division ($u/$y) |
674 | my $u = bless { sign => '+' }, $self; | |
675 | $u->{_n} = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d} ); | |
676 | $u->{_d} = $MBI->_mul( $MBI->_copy($x->{_d}), $y->{_n} ); | |
677 | ||
678 | # compute floor(u) | |
679 | if (! $MBI->_is_one($u->{_d})) | |
990fb837 | 680 | { |
12fc2493 AMS |
681 | $u->{_n} = $MBI->_div($u->{_n},$u->{_d}); # 22/7 => 3/1 w/ truncate |
682 | # no need to set $u->{_d} to 1, since below we set it to $y->{_d} anyway | |
990fb837 RGS |
683 | } |
684 | ||
12fc2493 AMS |
685 | # now compute $y * $u |
686 | $u->{_d} = $MBI->_copy($y->{_d}); # 1 * $y->{_d}, see floor above | |
687 | $u->{_n} = $MBI->_mul($u->{_n},$y->{_n}); | |
990fb837 | 688 | |
12fc2493 | 689 | my $xsign = $x->{sign}; $x->{sign} = '+'; # remember sign and make x positive |
990fb837 RGS |
690 | # compute $x - $u |
691 | $x->bsub($u); | |
692 | $x->{sign} = $xsign; # put sign back | |
693 | ||
694 | $x->bnorm()->round(@r); | |
990fb837 RGS |
695 | } |
696 | ||
184f15d5 | 697 | ############################################################################## |
a4e2b1c6 JH |
698 | # bdec/binc |
699 | ||
700 | sub bdec | |
701 | { | |
702 | # decrement value (subtract 1) | |
703 | my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_); | |
704 | ||
705 | return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf | |
706 | ||
707 | if ($x->{sign} eq '-') | |
708 | { | |
12fc2493 | 709 | $x->{_n} = $MBI->_add( $x->{_n}, $x->{_d}); # -5/2 => -7/2 |
a4e2b1c6 JH |
710 | } |
711 | else | |
712 | { | |
12fc2493 | 713 | if ($MBI->_acmp($x->{_n},$x->{_d}) < 0) # n < d? |
a4e2b1c6 JH |
714 | { |
715 | # 1/3 -- => -2/3 | |
12fc2493 | 716 | $x->{_n} = $MBI->_sub( $MBI->_copy($x->{_d}), $x->{_n}); |
a4e2b1c6 JH |
717 | $x->{sign} = '-'; |
718 | } | |
719 | else | |
720 | { | |
12fc2493 | 721 | $x->{_n} = $MBI->_sub($x->{_n}, $x->{_d}); # 5/2 => 3/2 |
a4e2b1c6 JH |
722 | } |
723 | } | |
724 | $x->bnorm()->round(@r); | |
a4e2b1c6 JH |
725 | } |
726 | ||
727 | sub binc | |
728 | { | |
729 | # increment value (add 1) | |
730 | my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_); | |
731 | ||
732 | return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf | |
733 | ||
734 | if ($x->{sign} eq '-') | |
735 | { | |
12fc2493 | 736 | if ($MBI->_acmp($x->{_n},$x->{_d}) < 0) |
a4e2b1c6 JH |
737 | { |
738 | # -1/3 ++ => 2/3 (overflow at 0) | |
12fc2493 | 739 | $x->{_n} = $MBI->_sub( $MBI->_copy($x->{_d}), $x->{_n}); |
a4e2b1c6 JH |
740 | $x->{sign} = '+'; |
741 | } | |
742 | else | |
743 | { | |
12fc2493 | 744 | $x->{_n} = $MBI->_sub($x->{_n}, $x->{_d}); # -5/2 => -3/2 |
a4e2b1c6 JH |
745 | } |
746 | } | |
747 | else | |
748 | { | |
12fc2493 | 749 | $x->{_n} = $MBI->_add($x->{_n},$x->{_d}); # 5/2 => 7/2 |
a4e2b1c6 JH |
750 | } |
751 | $x->bnorm()->round(@r); | |
a4e2b1c6 JH |
752 | } |
753 | ||
754 | ############################################################################## | |
184f15d5 JH |
755 | # is_foo methods (the rest is inherited) |
756 | ||
757 | sub is_int | |
758 | { | |
759 | # return true if arg (BRAT or num_str) is an integer | |
9b924220 | 760 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
184f15d5 JH |
761 | |
762 | return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN and +-inf aren't | |
12fc2493 | 763 | $MBI->_is_one($x->{_d}); # x/y && y != 1 => no integer |
184f15d5 JH |
764 | 0; |
765 | } | |
766 | ||
767 | sub is_zero | |
768 | { | |
769 | # return true if arg (BRAT or num_str) is zero | |
9b924220 | 770 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
184f15d5 | 771 | |
12fc2493 | 772 | return 1 if $x->{sign} eq '+' && $MBI->_is_zero($x->{_n}); |
184f15d5 JH |
773 | 0; |
774 | } | |
775 | ||
776 | sub is_one | |
777 | { | |
778 | # return true if arg (BRAT or num_str) is +1 or -1 if signis given | |
9b924220 | 779 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
184f15d5 | 780 | |
9b924220 | 781 | my $sign = $_[2] || ''; $sign = '+' if $sign ne '-'; |
184f15d5 | 782 | return 1 |
12fc2493 | 783 | if ($x->{sign} eq $sign && $MBI->_is_one($x->{_n}) && $MBI->_is_one($x->{_d})); |
184f15d5 JH |
784 | 0; |
785 | } | |
786 | ||
787 | sub is_odd | |
788 | { | |
789 | # return true if arg (BFLOAT or num_str) is odd or false if even | |
9b924220 | 790 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
184f15d5 JH |
791 | |
792 | return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN & +-inf aren't | |
12fc2493 | 793 | ($MBI->_is_one($x->{_d}) && $MBI->_is_odd($x->{_n})); # x/2 is not, but 3/1 |
184f15d5 JH |
794 | 0; |
795 | } | |
796 | ||
797 | sub is_even | |
798 | { | |
799 | # return true if arg (BINT or num_str) is even or false if odd | |
9b924220 | 800 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
184f15d5 JH |
801 | |
802 | return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't | |
12fc2493 AMS |
803 | return 1 if ($MBI->_is_one($x->{_d}) # x/3 is never |
804 | && $MBI->_is_even($x->{_n})); # but 4/1 is | |
184f15d5 JH |
805 | 0; |
806 | } | |
807 | ||
184f15d5 JH |
808 | ############################################################################## |
809 | # parts() and friends | |
810 | ||
811 | sub numerator | |
812 | { | |
813 | my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_); | |
a4e2b1c6 | 814 | |
12fc2493 AMS |
815 | # NaN, inf, -inf |
816 | return Math::BigInt->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/); | |
a4e2b1c6 | 817 | |
12fc2493 | 818 | my $n = Math::BigInt->new($MBI->_str($x->{_n})); $n->{sign} = $x->{sign}; |
184f15d5 JH |
819 | $n; |
820 | } | |
821 | ||
822 | sub denominator | |
823 | { | |
824 | my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_); | |
825 | ||
12fc2493 AMS |
826 | # NaN |
827 | return Math::BigInt->new($x->{sign}) if $x->{sign} eq 'NaN'; | |
828 | # inf, -inf | |
829 | return Math::BigInt->bone() if $x->{sign} !~ /^[+-]$/; | |
830 | ||
831 | Math::BigInt->new($MBI->_str($x->{_d})); | |
184f15d5 JH |
832 | } |
833 | ||
834 | sub parts | |
835 | { | |
836 | my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_); | |
837 | ||
12fc2493 AMS |
838 | my $c = 'Math::BigInt'; |
839 | ||
840 | return ($c->bnan(),$c->bnan()) if $x->{sign} eq 'NaN'; | |
841 | return ($c->binf(),$c->binf()) if $x->{sign} eq '+inf'; | |
842 | return ($c->binf('-'),$c->binf()) if $x->{sign} eq '-inf'; | |
a4e2b1c6 | 843 | |
12fc2493 | 844 | my $n = $c->new( $MBI->_str($x->{_n})); |
184f15d5 | 845 | $n->{sign} = $x->{sign}; |
12fc2493 AMS |
846 | my $d = $c->new( $MBI->_str($x->{_d})); |
847 | ($n,$d); | |
184f15d5 JH |
848 | } |
849 | ||
850 | sub length | |
851 | { | |
9b924220 RGS |
852 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
853 | ||
854 | return $nan unless $x->is_int(); | |
12fc2493 | 855 | $MBI->_len($x->{_n}); # length(-123/1) => length(123) |
184f15d5 JH |
856 | } |
857 | ||
858 | sub digit | |
859 | { | |
12fc2493 | 860 | my ($self,$x,$n) = ref($_[0]) ? (undef,$_[0],$_[1]) : objectify(1,@_); |
9b924220 RGS |
861 | |
862 | return $nan unless $x->is_int(); | |
12fc2493 | 863 | $MBI->_digit($x->{_n},$n || 0); # digit(-123/1,2) => digit(123,2) |
184f15d5 JH |
864 | } |
865 | ||
866 | ############################################################################## | |
867 | # special calc routines | |
868 | ||
869 | sub bceil | |
870 | { | |
871 | my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_); | |
872 | ||
12fc2493 AMS |
873 | return $x if $x->{sign} !~ /^[+-]$/ || # not for NaN, inf |
874 | $MBI->_is_one($x->{_d}); # 22/1 => 22, 0/1 => 0 | |
184f15d5 | 875 | |
12fc2493 AMS |
876 | $x->{_n} = $MBI->_div($x->{_n},$x->{_d}); # 22/7 => 3/1 w/ truncate |
877 | $x->{_d} = $MBI->_one(); # d => 1 | |
878 | $x->{_n} = $MBI->_inc($x->{_n}) | |
879 | if $x->{sign} eq '+'; # +22/7 => 4/1 | |
880 | $x->{sign} = '+' if $MBI->_is_zero($x->{_n}); # -0 => 0 | |
184f15d5 JH |
881 | $x; |
882 | } | |
883 | ||
884 | sub bfloor | |
885 | { | |
886 | my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_); | |
887 | ||
12fc2493 AMS |
888 | return $x if $x->{sign} !~ /^[+-]$/ || # not for NaN, inf |
889 | $MBI->_is_one($x->{_d}); # 22/1 => 22, 0/1 => 0 | |
184f15d5 | 890 | |
12fc2493 AMS |
891 | $x->{_n} = $MBI->_div($x->{_n},$x->{_d}); # 22/7 => 3/1 w/ truncate |
892 | $x->{_d} = $MBI->_one(); # d => 1 | |
893 | $x->{_n} = $MBI->_inc($x->{_n}) | |
894 | if $x->{sign} eq '-'; # -22/7 => -4/1 | |
184f15d5 JH |
895 | $x; |
896 | } | |
897 | ||
898 | sub bfac | |
899 | { | |
a4e2b1c6 JH |
900 | my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_); |
901 | ||
12fc2493 AMS |
902 | # if $x is not an integer |
903 | if (($x->{sign} ne '+') || (!$MBI->_is_one($x->{_d}))) | |
a4e2b1c6 | 904 | { |
12fc2493 | 905 | return $x->bnan(); |
a4e2b1c6 | 906 | } |
12fc2493 AMS |
907 | |
908 | $x->{_n} = $MBI->_fac($x->{_n}); | |
909 | # since _d is 1, we don't need to reduce/norm the result | |
910 | $x->round(@r); | |
184f15d5 JH |
911 | } |
912 | ||
913 | sub bpow | |
914 | { | |
7d341013 T |
915 | # power ($x ** $y) |
916 | ||
917 | # set up parameters | |
918 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
919 | # objectify is costly, so avoid it | |
920 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
921 | { | |
922 | ($self,$x,$y,@r) = objectify(2,@_); | |
923 | } | |
184f15d5 JH |
924 | |
925 | return $x if $x->{sign} =~ /^[+-]inf$/; # -inf/+inf ** x | |
926 | return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan; | |
927 | return $x->bone(@r) if $y->is_zero(); | |
928 | return $x->round(@r) if $x->is_one() || $y->is_one(); | |
12fc2493 AMS |
929 | |
930 | if ($x->{sign} eq '-' && $MBI->_is_one($x->{_n}) && $MBI->_is_one($x->{_d})) | |
184f15d5 JH |
931 | { |
932 | # if $x == -1 and odd/even y => +1/-1 | |
933 | return $y->is_odd() ? $x->round(@r) : $x->babs()->round(@r); | |
934 | # my Casio FX-5500L has a bug here: -1 ** 2 is -1, but -1 * -1 is 1; | |
935 | } | |
936 | # 1 ** -y => 1 / (1 ** |y|) | |
937 | # so do test for negative $y after above's clause | |
12fc2493 | 938 | |
184f15d5 JH |
939 | return $x->round(@r) if $x->is_zero(); # 0**y => 0 (if not y <= 0) |
940 | ||
4de3d162 T |
941 | # shortcut if y == 1/N (is then sqrt() respective broot()) |
942 | if ($MBI->_is_one($y->{_n})) | |
943 | { | |
944 | return $x->bsqrt(@r) if $MBI->_is_two($y->{_d}); # 1/2 => sqrt | |
945 | return $x->broot($MBI->_str($y->{_d}),@r); # 1/N => root(N) | |
946 | } | |
947 | ||
a4e2b1c6 | 948 | # shortcut y/1 (and/or x/1) |
12fc2493 | 949 | if ($MBI->_is_one($y->{_d})) |
a4e2b1c6 JH |
950 | { |
951 | # shortcut for x/1 and y/1 | |
12fc2493 | 952 | if ($MBI->_is_one($x->{_d})) |
a4e2b1c6 | 953 | { |
12fc2493 | 954 | $x->{_n} = $MBI->_pow($x->{_n},$y->{_n}); # x/1 ** y/1 => (x ** y)/1 |
a4e2b1c6 JH |
955 | if ($y->{sign} eq '-') |
956 | { | |
957 | # 0.2 ** -3 => 1/(0.2 ** 3) | |
958 | ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n}); # swap | |
959 | } | |
960 | # correct sign; + ** + => + | |
961 | if ($x->{sign} eq '-') | |
962 | { | |
963 | # - * - => +, - * - * - => - | |
12fc2493 | 964 | $x->{sign} = '+' if $MBI->_is_even($y->{_n}); |
a4e2b1c6 JH |
965 | } |
966 | return $x->round(@r); | |
967 | } | |
968 | # x/z ** y/1 | |
12fc2493 AMS |
969 | $x->{_n} = $MBI->_pow($x->{_n},$y->{_n}); # 5/2 ** y/1 => 5 ** y / 2 ** y |
970 | $x->{_d} = $MBI->_pow($x->{_d},$y->{_n}); | |
a4e2b1c6 JH |
971 | if ($y->{sign} eq '-') |
972 | { | |
973 | # 0.2 ** -3 => 1/(0.2 ** 3) | |
974 | ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n}); # swap | |
975 | } | |
976 | # correct sign; + ** + => + | |
977 | if ($x->{sign} eq '-') | |
978 | { | |
979 | # - * - => +, - * - * - => - | |
12fc2493 | 980 | $x->{sign} = '+' if $MBI->_is_even($y->{_n}); |
a4e2b1c6 JH |
981 | } |
982 | return $x->round(@r); | |
983 | } | |
984 | ||
4de3d162 | 985 | # print STDERR "# $x $y\n"; |
12fc2493 | 986 | |
4de3d162 T |
987 | # otherwise: |
988 | ||
989 | # n/d n ______________ | |
990 | # a/b = -\/ (a/b) ** d | |
991 | ||
992 | # (a/b) ** n == (a ** n) / (b ** n) | |
993 | $MBI->_pow($x->{_n}, $y->{_n} ); | |
994 | $MBI->_pow($x->{_d}, $y->{_n} ); | |
995 | ||
996 | return $x->broot($MBI->_str($y->{_d}),@r); # n/d => root(n) | |
184f15d5 JH |
997 | } |
998 | ||
999 | sub blog | |
1000 | { | |
7afd7a91 T |
1001 | # set up parameters |
1002 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
1003 | ||
1004 | # objectify is costly, so avoid it | |
1005 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1006 | { | |
9b924220 | 1007 | ($self,$x,$y,@r) = objectify(2,$class,@_); |
7afd7a91 T |
1008 | } |
1009 | ||
9b924220 RGS |
1010 | # blog(1,Y) => 0 |
1011 | return $x->bzero() if $x->is_one() && $y->{sign} eq '+'; | |
1012 | ||
7afd7a91 T |
1013 | # $x <= 0 => NaN |
1014 | return $x->bnan() if $x->is_zero() || $x->{sign} ne '+' || $y->{sign} ne '+'; | |
1015 | ||
1016 | if ($x->is_int() && $y->is_int()) | |
1017 | { | |
1018 | return $self->new($x->as_number()->blog($y->as_number(),@r)); | |
1019 | } | |
1020 | ||
9b924220 RGS |
1021 | # do it with floats |
1022 | $x->_new_from_float( $x->_as_float()->blog(Math::BigFloat->new("$y"),@r) ); | |
1023 | } | |
1024 | ||
116a1b2f SP |
1025 | sub bexp |
1026 | { | |
1027 | # set up parameters | |
4de3d162 | 1028 | my ($self,$x,$y,@r) = (ref($_[0]),@_); |
116a1b2f SP |
1029 | |
1030 | # objectify is costly, so avoid it | |
1031 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1032 | { | |
4de3d162 | 1033 | ($self,$x,$y,@r) = objectify(2,$class,@_); |
116a1b2f SP |
1034 | } |
1035 | ||
4de3d162 T |
1036 | return $x->binf(@r) if $x->{sign} eq '+inf'; |
1037 | return $x->bzero(@r) if $x->{sign} eq '-inf'; | |
116a1b2f SP |
1038 | |
1039 | # we need to limit the accuracy to protect against overflow | |
1040 | my $fallback = 0; | |
1041 | my ($scale,@params); | |
4de3d162 | 1042 | ($x,@params) = $x->_find_round_parameters(@r); |
116a1b2f SP |
1043 | |
1044 | # also takes care of the "error in _find_round_parameters?" case | |
1045 | return $x if $x->{sign} eq 'NaN'; | |
1046 | ||
1047 | # no rounding at all, so must use fallback | |
1048 | if (scalar @params == 0) | |
1049 | { | |
1050 | # simulate old behaviour | |
4de3d162 T |
1051 | $params[0] = $self->div_scale(); # and round to it as accuracy |
1052 | $params[1] = undef; # P = undef | |
1053 | $scale = $params[0]+4; # at least four more for proper round | |
1054 | $params[2] = $r[2]; # round mode by caller or undef | |
1055 | $fallback = 1; # to clear a/p afterwards | |
116a1b2f SP |
1056 | } |
1057 | else | |
1058 | { | |
1059 | # the 4 below is empirical, and there might be cases where it's not enough... | |
1060 | $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined | |
1061 | } | |
1062 | ||
1063 | return $x->bone(@params) if $x->is_zero(); | |
1064 | ||
1065 | # See the comments in Math::BigFloat on how this algorithm works. | |
1066 | # Basically we calculate A and B (where B is faculty(N)) so that A/B = e | |
1067 | ||
1068 | my $x_org = $x->copy(); | |
1069 | if ($scale <= 75) | |
1070 | { | |
1071 | # set $x directly from a cached string form | |
1072 | $x->{_n} = $MBI->_new("90933395208605785401971970164779391644753259799242"); | |
1073 | $x->{_d} = $MBI->_new("33452526613163807108170062053440751665152000000000"); | |
1074 | $x->{sign} = '+'; | |
1075 | } | |
1076 | else | |
1077 | { | |
1078 | # compute A and B so that e = A / B. | |
1079 | ||
1080 | # After some terms we end up with this, so we use it as a starting point: | |
1081 | my $A = $MBI->_new("90933395208605785401971970164779391644753259799242"); | |
1082 | my $F = $MBI->_new(42); my $step = 42; | |
1083 | ||
1084 | # Compute how many steps we need to take to get $A and $B sufficiently big | |
1085 | my $steps = Math::BigFloat::_len_to_steps($scale - 4); | |
1086 | # print STDERR "# Doing $steps steps for ", $scale-4, " digits\n"; | |
1087 | while ($step++ <= $steps) | |
1088 | { | |
1089 | # calculate $a * $f + 1 | |
1090 | $A = $MBI->_mul($A, $F); | |
1091 | $A = $MBI->_inc($A); | |
1092 | # increment f | |
1093 | $F = $MBI->_inc($F); | |
1094 | } | |
1095 | # compute $B as factorial of $steps (this is faster than doing it manually) | |
1096 | my $B = $MBI->_fac($MBI->_new($steps)); | |
1097 | ||
1098 | # print "A ", $MBI->_str($A), "\nB ", $MBI->_str($B), "\n"; | |
1099 | ||
1100 | $x->{_n} = $A; | |
1101 | $x->{_d} = $B; | |
1102 | $x->{sign} = '+'; | |
1103 | } | |
1104 | ||
1105 | # $x contains now an estimate of e, with some surplus digits, so we can round | |
1106 | if (!$x_org->is_one()) | |
1107 | { | |
1108 | # raise $x to the wanted power and round it in one step: | |
1109 | $x->bpow($x_org, @params); | |
1110 | } | |
1111 | else | |
1112 | { | |
1113 | # else just round the already computed result | |
1114 | delete $x->{_a}; delete $x->{_p}; | |
1115 | # shortcut to not run through _find_round_parameters again | |
1116 | if (defined $params[0]) | |
1117 | { | |
1118 | $x->bround($params[0],$params[2]); # then round accordingly | |
1119 | } | |
1120 | else | |
1121 | { | |
1122 | $x->bfround($params[1],$params[2]); # then round accordingly | |
1123 | } | |
1124 | } | |
1125 | if ($fallback) | |
1126 | { | |
1127 | # clear a/p after round, since user did not request it | |
1128 | delete $x->{_a}; delete $x->{_p}; | |
1129 | } | |
1130 | ||
1131 | $x; | |
1132 | } | |
1133 | ||
1134 | sub bnok | |
1135 | { | |
1136 | # set up parameters | |
1137 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
1138 | ||
1139 | # objectify is costly, so avoid it | |
1140 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1141 | { | |
1142 | ($self,$x,$y,@r) = objectify(2,$class,@_); | |
1143 | } | |
1144 | ||
1145 | # do it with floats | |
1146 | $x->_new_from_float( $x->_as_float()->bnok(Math::BigFloat->new("$y"),@r) ); | |
1147 | } | |
1148 | ||
12fc2493 AMS |
1149 | sub _float_from_part |
1150 | { | |
1151 | my $x = shift; | |
1152 | ||
1153 | my $f = Math::BigFloat->bzero(); | |
1154 | $f->{_m} = $MBI->_copy($x); | |
1155 | $f->{_e} = $MBI->_zero(); | |
1156 | ||
1157 | $f; | |
1158 | } | |
1159 | ||
9b924220 RGS |
1160 | sub _as_float |
1161 | { | |
1162 | my $x = shift; | |
1163 | ||
1164 | local $Math::BigFloat::upgrade = undef; | |
1165 | local $Math::BigFloat::accuracy = undef; | |
1166 | local $Math::BigFloat::precision = undef; | |
1167 | # 22/7 => 3.142857143.. | |
12fc2493 AMS |
1168 | |
1169 | my $a = $x->accuracy() || 0; | |
1170 | if ($a != 0 || !$MBI->_is_one($x->{_d})) | |
1171 | { | |
1172 | # n/d | |
4de3d162 | 1173 | return scalar Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}))->bdiv( $MBI->_str($x->{_d}), $x->accuracy()); |
12fc2493 AMS |
1174 | } |
1175 | # just n | |
1176 | Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n})); | |
7afd7a91 T |
1177 | } |
1178 | ||
1179 | sub broot | |
1180 | { | |
1181 | # set up parameters | |
1182 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
1183 | # objectify is costly, so avoid it | |
1184 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1185 | { | |
1186 | ($self,$x,$y,@r) = objectify(2,@_); | |
1187 | } | |
1188 | ||
1189 | if ($x->is_int() && $y->is_int()) | |
1190 | { | |
1191 | return $self->new($x->as_number()->broot($y->as_number(),@r)); | |
1192 | } | |
9b924220 RGS |
1193 | |
1194 | # do it with floats | |
4de3d162 | 1195 | $x->_new_from_float( $x->_as_float()->broot($y->_as_float(),@r) )->bnorm()->bround(@r); |
7afd7a91 T |
1196 | } |
1197 | ||
1198 | sub bmodpow | |
1199 | { | |
1200 | # set up parameters | |
1201 | my ($self,$x,$y,$m,@r) = (ref($_[0]),@_); | |
1202 | # objectify is costly, so avoid it | |
1203 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1204 | { | |
1205 | ($self,$x,$y,$m,@r) = objectify(3,@_); | |
1206 | } | |
1207 | ||
1208 | # $x or $y or $m are NaN or +-inf => NaN | |
1209 | return $x->bnan() | |
1210 | if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/ || | |
1211 | $m->{sign} !~ /^[+-]$/; | |
1212 | ||
1213 | if ($x->is_int() && $y->is_int() && $m->is_int()) | |
1214 | { | |
1215 | return $self->new($x->as_number()->bmodpow($y->as_number(),$m,@r)); | |
1216 | } | |
1217 | ||
1218 | warn ("bmodpow() not fully implemented"); | |
1219 | $x->bnan(); | |
1220 | } | |
1221 | ||
1222 | sub bmodinv | |
1223 | { | |
1224 | # set up parameters | |
1225 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
1226 | # objectify is costly, so avoid it | |
1227 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1228 | { | |
1229 | ($self,$x,$y,@r) = objectify(2,@_); | |
1230 | } | |
1231 | ||
1232 | # $x or $y are NaN or +-inf => NaN | |
1233 | return $x->bnan() | |
1234 | if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/; | |
1235 | ||
1236 | if ($x->is_int() && $y->is_int()) | |
1237 | { | |
1238 | return $self->new($x->as_number()->bmodinv($y->as_number(),@r)); | |
1239 | } | |
1240 | ||
1241 | warn ("bmodinv() not fully implemented"); | |
1242 | $x->bnan(); | |
184f15d5 JH |
1243 | } |
1244 | ||
1245 | sub bsqrt | |
1246 | { | |
990fb837 RGS |
1247 | my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_); |
1248 | ||
1249 | return $x->bnan() if $x->{sign} !~ /^[+]/; # NaN, -inf or < 0 | |
1250 | return $x if $x->{sign} eq '+inf'; # sqrt(inf) == inf | |
1251 | return $x->round(@r) if $x->is_zero() || $x->is_one(); | |
1252 | ||
1253 | local $Math::BigFloat::upgrade = undef; | |
1254 | local $Math::BigFloat::downgrade = undef; | |
1255 | local $Math::BigFloat::precision = undef; | |
1256 | local $Math::BigFloat::accuracy = undef; | |
1257 | local $Math::BigInt::upgrade = undef; | |
1258 | local $Math::BigInt::precision = undef; | |
1259 | local $Math::BigInt::accuracy = undef; | |
9b924220 | 1260 | |
12fc2493 AMS |
1261 | $x->{_n} = _float_from_part( $x->{_n} )->bsqrt(); |
1262 | $x->{_d} = _float_from_part( $x->{_d} )->bsqrt(); | |
1263 | ||
1264 | # XXX TODO: we probably can optimze this: | |
184f15d5 | 1265 | |
990fb837 | 1266 | # if sqrt(D) was not integer |
9b924220 | 1267 | if ($x->{_d}->{_es} ne '+') |
990fb837 | 1268 | { |
9b924220 | 1269 | $x->{_n}->blsft($x->{_d}->exponent()->babs(),10); # 7.1/4.51 => 7.1/45.1 |
12fc2493 | 1270 | $x->{_d} = $MBI->_copy( $x->{_d}->{_m} ); # 7.1/45.1 => 71/45.1 |
990fb837 RGS |
1271 | } |
1272 | # if sqrt(N) was not integer | |
9b924220 | 1273 | if ($x->{_n}->{_es} ne '+') |
990fb837 | 1274 | { |
9b924220 | 1275 | $x->{_d}->blsft($x->{_n}->exponent()->babs(),10); # 71/45.1 => 710/45.1 |
12fc2493 | 1276 | $x->{_n} = $MBI->_copy( $x->{_n}->{_m} ); # 710/45.1 => 710/451 |
990fb837 | 1277 | } |
12fc2493 | 1278 | |
990fb837 | 1279 | # convert parts to $MBI again |
12fc2493 AMS |
1280 | $x->{_n} = $MBI->_lsft( $MBI->_copy( $x->{_n}->{_m} ), $x->{_n}->{_e}, 10) |
1281 | if ref($x->{_n}) ne $MBI && ref($x->{_n}) ne 'ARRAY'; | |
1282 | $x->{_d} = $MBI->_lsft( $MBI->_copy( $x->{_d}->{_m} ), $x->{_d}->{_e}, 10) | |
1283 | if ref($x->{_d}) ne $MBI && ref($x->{_d}) ne 'ARRAY'; | |
1284 | ||
990fb837 | 1285 | $x->bnorm()->round(@r); |
184f15d5 JH |
1286 | } |
1287 | ||
1288 | sub blsft | |
1289 | { | |
9b924220 | 1290 | my ($self,$x,$y,$b,@r) = objectify(3,@_); |
184f15d5 | 1291 | |
9b924220 RGS |
1292 | $b = 2 unless defined $b; |
1293 | $b = $self->new($b) unless ref ($b); | |
1294 | $x->bmul( $b->copy()->bpow($y), @r); | |
184f15d5 JH |
1295 | $x; |
1296 | } | |
1297 | ||
1298 | sub brsft | |
1299 | { | |
12fc2493 | 1300 | my ($self,$x,$y,$b,@r) = objectify(3,@_); |
184f15d5 | 1301 | |
9b924220 RGS |
1302 | $b = 2 unless defined $b; |
1303 | $b = $self->new($b) unless ref ($b); | |
1304 | $x->bdiv( $b->copy()->bpow($y), @r); | |
184f15d5 JH |
1305 | $x; |
1306 | } | |
1307 | ||
1308 | ############################################################################## | |
1309 | # round | |
1310 | ||
1311 | sub round | |
1312 | { | |
1313 | $_[0]; | |
1314 | } | |
1315 | ||
1316 | sub bround | |
1317 | { | |
1318 | $_[0]; | |
1319 | } | |
1320 | ||
1321 | sub bfround | |
1322 | { | |
1323 | $_[0]; | |
1324 | } | |
1325 | ||
1326 | ############################################################################## | |
1327 | # comparing | |
1328 | ||
1329 | sub bcmp | |
1330 | { | |
7afd7a91 T |
1331 | # compare two signed numbers |
1332 | ||
1333 | # set up parameters | |
1334 | my ($self,$x,$y) = (ref($_[0]),@_); | |
1335 | # objectify is costly, so avoid it | |
1336 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1337 | { | |
1338 | ($self,$x,$y) = objectify(2,@_); | |
1339 | } | |
184f15d5 JH |
1340 | |
1341 | if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) | |
1342 | { | |
1343 | # handle +-inf and NaN | |
1344 | return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan)); | |
1345 | return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/; | |
1346 | return +1 if $x->{sign} eq '+inf'; | |
1347 | return -1 if $x->{sign} eq '-inf'; | |
1348 | return -1 if $y->{sign} eq '+inf'; | |
1349 | return +1; | |
1350 | } | |
1351 | # check sign for speed first | |
1352 | return 1 if $x->{sign} eq '+' && $y->{sign} eq '-'; # does also 0 <=> -y | |
1353 | return -1 if $x->{sign} eq '-' && $y->{sign} eq '+'; # does also -x <=> 0 | |
1354 | ||
1355 | # shortcut | |
12fc2493 AMS |
1356 | my $xz = $MBI->_is_zero($x->{_n}); |
1357 | my $yz = $MBI->_is_zero($y->{_n}); | |
184f15d5 JH |
1358 | return 0 if $xz && $yz; # 0 <=> 0 |
1359 | return -1 if $xz && $y->{sign} eq '+'; # 0 <=> +y | |
1360 | return 1 if $yz && $x->{sign} eq '+'; # +x <=> 0 | |
1361 | ||
12fc2493 AMS |
1362 | my $t = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d}); |
1363 | my $u = $MBI->_mul( $MBI->_copy($y->{_n}), $x->{_d}); | |
1364 | ||
1365 | my $cmp = $MBI->_acmp($t,$u); # signs are equal | |
1366 | $cmp = -$cmp if $x->{sign} eq '-'; # both are '-' => reverse | |
1367 | $cmp; | |
184f15d5 JH |
1368 | } |
1369 | ||
1370 | sub bacmp | |
1371 | { | |
7afd7a91 | 1372 | # compare two numbers (as unsigned) |
9b924220 | 1373 | |
7afd7a91 T |
1374 | # set up parameters |
1375 | my ($self,$x,$y) = (ref($_[0]),@_); | |
1376 | # objectify is costly, so avoid it | |
1377 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1378 | { | |
9b924220 | 1379 | ($self,$x,$y) = objectify(2,$class,@_); |
7afd7a91 | 1380 | } |
184f15d5 JH |
1381 | |
1382 | if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) | |
1383 | { | |
1384 | # handle +-inf and NaN | |
1385 | return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan)); | |
1386 | return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/; | |
7afd7a91 T |
1387 | return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/; |
1388 | return -1; | |
184f15d5 JH |
1389 | } |
1390 | ||
12fc2493 AMS |
1391 | my $t = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d}); |
1392 | my $u = $MBI->_mul( $MBI->_copy($y->{_n}), $x->{_d}); | |
1393 | $MBI->_acmp($t,$u); # ignore signs | |
184f15d5 JH |
1394 | } |
1395 | ||
1396 | ############################################################################## | |
1397 | # output conversation | |
1398 | ||
7d341013 T |
1399 | sub numify |
1400 | { | |
1401 | # convert 17/8 => float (aka 2.125) | |
b68b7ab1 | 1402 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
7d341013 T |
1403 | |
1404 | return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, NaN, etc | |
1405 | ||
93c87d9d | 1406 | # N/1 => N |
b68b7ab1 T |
1407 | my $neg = ''; $neg = '-' if $x->{sign} eq '-'; |
1408 | return $neg . $MBI->_num($x->{_n}) if $MBI->_is_one($x->{_d}); | |
93c87d9d | 1409 | |
b68b7ab1 | 1410 | $x->_as_float()->numify() + 0.0; |
7d341013 T |
1411 | } |
1412 | ||
184f15d5 JH |
1413 | sub as_number |
1414 | { | |
9b924220 | 1415 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
184f15d5 | 1416 | |
08a3f4a9 T |
1417 | # NaN, inf etc |
1418 | return Math::BigInt->new($x->{sign}) if $x->{sign} !~ /^[+-]$/; | |
990fb837 | 1419 | |
12fc2493 AMS |
1420 | my $u = Math::BigInt->bzero(); |
1421 | $u->{sign} = $x->{sign}; | |
1422 | $u->{value} = $MBI->_div( $MBI->_copy($x->{_n}), $x->{_d}); # 22/7 => 3 | |
1423 | $u; | |
184f15d5 JH |
1424 | } |
1425 | ||
4de3d162 T |
1426 | sub as_float |
1427 | { | |
1428 | # return N/D as Math::BigFloat | |
1429 | ||
1430 | # set up parameters | |
1431 | my ($self,$x,@r) = (ref($_[0]),@_); | |
1432 | # objectify is costly, so avoid it | |
1433 | ($self,$x,@r) = objectify(1,$class,@_) unless ref $_[0]; | |
1434 | ||
1435 | # NaN, inf etc | |
1436 | return Math::BigFloat->new($x->{sign}) if $x->{sign} !~ /^[+-]$/; | |
1437 | ||
1438 | my $u = Math::BigFloat->bzero(); | |
1439 | $u->{sign} = $x->{sign}; | |
1440 | # n | |
1441 | $u->{_m} = $MBI->_copy($x->{_n}); | |
1442 | $u->{_e} = $MBI->_zero(); | |
1443 | $u->bdiv( $MBI->_str($x->{_d}), @r); | |
1444 | # return $u | |
1445 | $u; | |
1446 | } | |
1447 | ||
9b924220 RGS |
1448 | sub as_bin |
1449 | { | |
1450 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); | |
1451 | ||
1452 | return $x unless $x->is_int(); | |
1453 | ||
1454 | my $s = $x->{sign}; $s = '' if $s eq '+'; | |
12fc2493 | 1455 | $s . $MBI->_as_bin($x->{_n}); |
9b924220 RGS |
1456 | } |
1457 | ||
1458 | sub as_hex | |
1459 | { | |
1460 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); | |
1461 | ||
1462 | return $x unless $x->is_int(); | |
1463 | ||
1464 | my $s = $x->{sign}; $s = '' if $s eq '+'; | |
12fc2493 | 1465 | $s . $MBI->_as_hex($x->{_n}); |
9b924220 RGS |
1466 | } |
1467 | ||
b8884ce4 T |
1468 | sub as_oct |
1469 | { | |
1470 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); | |
1471 | ||
1472 | return $x unless $x->is_int(); | |
1473 | ||
1474 | my $s = $x->{sign}; $s = '' if $s eq '+'; | |
1475 | $s . $MBI->_as_oct($x->{_n}); | |
1476 | } | |
1477 | ||
1478 | ############################################################################## | |
1479 | ||
1480 | sub from_hex | |
1481 | { | |
1482 | my $class = shift; | |
1483 | ||
1484 | $class->new(@_); | |
1485 | } | |
1486 | ||
1487 | sub from_bin | |
1488 | { | |
1489 | my $class = shift; | |
1490 | ||
1491 | $class->new(@_); | |
1492 | } | |
1493 | ||
1494 | sub from_oct | |
1495 | { | |
1496 | my $class = shift; | |
1497 | ||
1498 | my @parts; | |
1499 | for my $c (@_) | |
1500 | { | |
1501 | push @parts, Math::BigInt->from_oct($c); | |
1502 | } | |
1503 | $class->new ( @parts ); | |
1504 | } | |
1505 | ||
b68b7ab1 T |
1506 | ############################################################################## |
1507 | # import | |
1508 | ||
6de7f0cc JH |
1509 | sub import |
1510 | { | |
1511 | my $self = shift; | |
1512 | my $l = scalar @_; | |
1513 | my $lib = ''; my @a; | |
b8884ce4 | 1514 | my $try = 'try'; |
9b924220 | 1515 | |
6de7f0cc JH |
1516 | for ( my $i = 0; $i < $l ; $i++) |
1517 | { | |
6de7f0cc JH |
1518 | if ( $_[$i] eq ':constant' ) |
1519 | { | |
1520 | # this rest causes overlord er load to step in | |
6de7f0cc JH |
1521 | overload::constant float => sub { $self->new(shift); }; |
1522 | } | |
1523 | # elsif ($_[$i] eq 'upgrade') | |
1524 | # { | |
1525 | # # this causes upgrading | |
b68b7ab1 | 1526 | # $upgrade = $_[$i+1]; # or undef to disable |
6de7f0cc JH |
1527 | # $i++; |
1528 | # } | |
1529 | elsif ($_[$i] eq 'downgrade') | |
1530 | { | |
1531 | # this causes downgrading | |
b68b7ab1 | 1532 | $downgrade = $_[$i+1]; # or undef to disable |
6de7f0cc JH |
1533 | $i++; |
1534 | } | |
b8884ce4 | 1535 | elsif ($_[$i] =~ /^(lib|try|only)\z/) |
6de7f0cc | 1536 | { |
b68b7ab1 | 1537 | $lib = $_[$i+1] || ''; # default Calc |
b8884ce4 | 1538 | $try = $1; # lib, try or only |
6de7f0cc JH |
1539 | $i++; |
1540 | } | |
1541 | elsif ($_[$i] eq 'with') | |
1542 | { | |
233f7bc0 T |
1543 | # this argument is no longer used |
1544 | #$MBI = $_[$i+1] || 'Math::BigInt::Calc'; # default Math::BigInt::Calc | |
6de7f0cc JH |
1545 | $i++; |
1546 | } | |
1547 | else | |
1548 | { | |
1549 | push @a, $_[$i]; | |
1550 | } | |
1551 | } | |
b68b7ab1 | 1552 | require Math::BigInt; |
6de7f0cc | 1553 | |
b68b7ab1 T |
1554 | # let use Math::BigInt lib => 'GMP'; use Math::BigRat; still have GMP |
1555 | if ($lib ne '') | |
1556 | { | |
1557 | my @c = split /\s*,\s*/, $lib; | |
1558 | foreach (@c) | |
6de7f0cc | 1559 | { |
b68b7ab1 | 1560 | $_ =~ tr/a-zA-Z0-9://cd; # limit to sane characters |
6de7f0cc | 1561 | } |
233f7bc0 | 1562 | $lib = join(",", @c); |
93c87d9d | 1563 | } |
233f7bc0 | 1564 | my @import = ('objectify'); |
b8884ce4 | 1565 | push @import, $try => $lib if $lib ne ''; |
233f7bc0 T |
1566 | |
1567 | # MBI already loaded, so feed it our lib arguments | |
1568 | Math::BigInt->import( @import ); | |
6de7f0cc | 1569 | |
12fc2493 | 1570 | $MBI = Math::BigFloat->config()->{lib}; |
b68b7ab1 T |
1571 | |
1572 | # register us with MBI to get notified of future lib changes | |
1573 | Math::BigInt::_register_callback( $self, sub { $MBI = $_[0]; } ); | |
9b924220 | 1574 | |
233f7bc0 T |
1575 | # any non :constant stuff is handled by our parent, Exporter (loaded |
1576 | # by Math::BigFloat, even if @_ is empty, to give it a chance | |
6de7f0cc JH |
1577 | $self->SUPER::import(@a); # for subclasses |
1578 | $self->export_to_level(1,$self,@a); # need this, too | |
1579 | } | |
184f15d5 JH |
1580 | |
1581 | 1; | |
1582 | ||
1583 | __END__ | |
1584 | ||
1585 | =head1 NAME | |
1586 | ||
b68b7ab1 | 1587 | Math::BigRat - Arbitrary big rational numbers |
184f15d5 JH |
1588 | |
1589 | =head1 SYNOPSIS | |
1590 | ||
7d341013 | 1591 | use Math::BigRat; |
184f15d5 | 1592 | |
7afd7a91 | 1593 | my $x = Math::BigRat->new('3/7'); $x += '5/9'; |
184f15d5 | 1594 | |
7d341013 T |
1595 | print $x->bstr(),"\n"; |
1596 | print $x ** 2,"\n"; | |
184f15d5 | 1597 | |
7afd7a91 T |
1598 | my $y = Math::BigRat->new('inf'); |
1599 | print "$y ", ($y->is_inf ? 'is' : 'is not') , " infinity\n"; | |
1600 | ||
1601 | my $z = Math::BigRat->new(144); $z->bsqrt(); | |
1602 | ||
184f15d5 JH |
1603 | =head1 DESCRIPTION |
1604 | ||
7d341013 | 1605 | Math::BigRat complements Math::BigInt and Math::BigFloat by providing support |
b68b7ab1 | 1606 | for arbitrary big rational numbers. |
184f15d5 JH |
1607 | |
1608 | =head2 MATH LIBRARY | |
1609 | ||
b8884ce4 T |
1610 | You can change the underlying module that does the low-level |
1611 | math operations by using: | |
184f15d5 | 1612 | |
b8884ce4 | 1613 | use Math::BigRat try => 'GMP'; |
184f15d5 | 1614 | |
b8884ce4 | 1615 | Note: This needs Math::BigInt::GMP installed. |
184f15d5 JH |
1616 | |
1617 | The following would first try to find Math::BigInt::Foo, then | |
1618 | Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc: | |
1619 | ||
b8884ce4 | 1620 | use Math::BigRat try => 'Foo,Math::BigInt::Bar'; |
184f15d5 | 1621 | |
b8884ce4 T |
1622 | If you want to get warned when the fallback occurs, replace "try" with |
1623 | "lib": | |
184f15d5 | 1624 | |
b8884ce4 | 1625 | use Math::BigRat lib => 'Foo,Math::BigInt::Bar'; |
7d341013 | 1626 | |
b8884ce4 T |
1627 | If you want the code to die instead, replace "try" with |
1628 | "only": | |
1629 | ||
1630 | use Math::BigRat only => 'Foo,Math::BigInt::Bar'; | |
7d341013 | 1631 | |
184f15d5 JH |
1632 | =head1 METHODS |
1633 | ||
3c4b39be | 1634 | Any methods not listed here are derived from Math::BigFloat (or |
6de7f0cc JH |
1635 | Math::BigInt), so make sure you check these two modules for further |
1636 | information. | |
1637 | ||
1638 | =head2 new() | |
184f15d5 JH |
1639 | |
1640 | $x = Math::BigRat->new('1/3'); | |
1641 | ||
1642 | Create a new Math::BigRat object. Input can come in various forms: | |
1643 | ||
7d341013 | 1644 | $x = Math::BigRat->new(123); # scalars |
7afd7a91 | 1645 | $x = Math::BigRat->new('inf'); # infinity |
7d341013 | 1646 | $x = Math::BigRat->new('123.3'); # float |
184f15d5 JH |
1647 | $x = Math::BigRat->new('1/3'); # simple string |
1648 | $x = Math::BigRat->new('1 / 3'); # spaced | |
1649 | $x = Math::BigRat->new('1 / 0.1'); # w/ floats | |
1650 | $x = Math::BigRat->new(Math::BigInt->new(3)); # BigInt | |
1651 | $x = Math::BigRat->new(Math::BigFloat->new('3.1')); # BigFloat | |
6de7f0cc | 1652 | $x = Math::BigRat->new(Math::BigInt::Lite->new('2')); # BigLite |
184f15d5 | 1653 | |
b68b7ab1 T |
1654 | # You can also give D and N as different objects: |
1655 | $x = Math::BigRat->new( | |
1656 | Math::BigInt->new(-123), | |
1657 | Math::BigInt->new(7), | |
1658 | ); # => -123/7 | |
1659 | ||
6de7f0cc | 1660 | =head2 numerator() |
184f15d5 JH |
1661 | |
1662 | $n = $x->numerator(); | |
1663 | ||
1664 | Returns a copy of the numerator (the part above the line) as signed BigInt. | |
1665 | ||
6de7f0cc | 1666 | =head2 denominator() |
184f15d5 JH |
1667 | |
1668 | $d = $x->denominator(); | |
1669 | ||
1670 | Returns a copy of the denominator (the part under the line) as positive BigInt. | |
1671 | ||
6de7f0cc | 1672 | =head2 parts() |
184f15d5 JH |
1673 | |
1674 | ($n,$d) = $x->parts(); | |
1675 | ||
1676 | Return a list consisting of (signed) numerator and (unsigned) denominator as | |
1677 | BigInts. | |
1678 | ||
b8884ce4 T |
1679 | =head2 numify() |
1680 | ||
1681 | my $y = $x->numify(); | |
1682 | ||
1683 | Returns the object as a scalar. This will lose some data if the object | |
1684 | cannot be represented by a normal Perl scalar (integer or float), so | |
4de3d162 | 1685 | use L<as_int()> or L<as_float()> instead. |
b8884ce4 T |
1686 | |
1687 | This routine is automatically used whenever a scalar is required: | |
1688 | ||
1689 | my $x = Math::BigRat->new('3/1'); | |
c6c613ed | 1690 | @array = (0,1,2,3); |
b8884ce4 T |
1691 | $y = $array[$x]; # set $y to 3 |
1692 | ||
1693 | =head2 as_int()/as_number() | |
6de7f0cc | 1694 | |
7d341013 | 1695 | $x = Math::BigRat->new('13/7'); |
b68b7ab1 T |
1696 | print $x->as_int(),"\n"; # '1' |
1697 | ||
1698 | Returns a copy of the object as BigInt, truncated to an integer. | |
7d341013 | 1699 | |
b68b7ab1 T |
1700 | C<as_number()> is an alias for C<as_int()>. |
1701 | ||
4de3d162 T |
1702 | =head2 as_float() |
1703 | ||
1704 | $x = Math::BigRat->new('13/7'); | |
1705 | print $x->as_float(),"\n"; # '1' | |
1706 | ||
1707 | $x = Math::BigRat->new('2/3'); | |
1708 | print $x->as_float(5),"\n"; # '0.66667' | |
1709 | ||
1710 | Returns a copy of the object as BigFloat, preserving the | |
1711 | accuracy as wanted, or the default of 40 digits. | |
1712 | ||
1713 | This method was added in v0.22 of Math::BigRat (April 2008). | |
1714 | ||
b68b7ab1 T |
1715 | =head2 as_hex() |
1716 | ||
1717 | $x = Math::BigRat->new('13'); | |
1718 | print $x->as_hex(),"\n"; # '0xd' | |
1719 | ||
1720 | Returns the BigRat as hexadecimal string. Works only for integers. | |
1721 | ||
1722 | =head2 as_bin() | |
1723 | ||
1724 | $x = Math::BigRat->new('13'); | |
1725 | print $x->as_bin(),"\n"; # '0x1101' | |
1726 | ||
1727 | Returns the BigRat as binary string. Works only for integers. | |
6de7f0cc | 1728 | |
b8884ce4 T |
1729 | =head2 as_oct() |
1730 | ||
1731 | $x = Math::BigRat->new('13'); | |
1732 | print $x->as_oct(),"\n"; # '015' | |
1733 | ||
1734 | Returns the BigRat as octal string. Works only for integers. | |
1735 | ||
1736 | =head2 from_hex()/from_bin()/from_oct() | |
1737 | ||
1738 | my $h = Math::BigRat->from_hex('0x10'); | |
1739 | my $b = Math::BigRat->from_bin('0b10000000'); | |
1740 | my $o = Math::BigRat->from_oct('020'); | |
1741 | ||
1742 | Create a BigRat from an hexadecimal, binary or octal number | |
1743 | in string form. | |
1744 | ||
1745 | =head2 length() | |
1746 | ||
1747 | $len = $x->length(); | |
1748 | ||
1749 | Return the length of $x in digitis for integer values. | |
1750 | ||
1751 | =head2 digit() | |
1752 | ||
1753 | print Math::BigRat->new('123/1')->digit(1); # 1 | |
1754 | print Math::BigRat->new('123/1')->digit(-1); # 3 | |
1755 | ||
1756 | Return the N'ths digit from X when X is an integer value. | |
1757 | ||
1758 | =head2 bnorm() | |
1759 | ||
1760 | $x->bnorm(); | |
1761 | ||
1762 | Reduce the number to the shortest form. This routine is called | |
1763 | automatically whenever it is needed. | |
1764 | ||
a4e2b1c6 | 1765 | =head2 bfac() |
6de7f0cc | 1766 | |
a4e2b1c6 | 1767 | $x->bfac(); |
6de7f0cc | 1768 | |
a4e2b1c6 | 1769 | Calculates the factorial of $x. For instance: |
6de7f0cc | 1770 | |
a4e2b1c6 JH |
1771 | print Math::BigRat->new('3/1')->bfac(),"\n"; # 1*2*3 |
1772 | print Math::BigRat->new('5/1')->bfac(),"\n"; # 1*2*3*4*5 | |
184f15d5 | 1773 | |
7d341013 | 1774 | Works currently only for integers. |
6de7f0cc | 1775 | |
a4e2b1c6 | 1776 | =head2 bround()/round()/bfround() |
6de7f0cc | 1777 | |
a4e2b1c6 | 1778 | Are not yet implemented. |
6de7f0cc | 1779 | |
990fb837 RGS |
1780 | =head2 bmod() |
1781 | ||
1782 | use Math::BigRat; | |
1783 | my $x = Math::BigRat->new('7/4'); | |
1784 | my $y = Math::BigRat->new('4/3'); | |
1785 | print $x->bmod($y); | |
1786 | ||
1787 | Set $x to the remainder of the division of $x by $y. | |
1788 | ||
b8884ce4 T |
1789 | =head2 bneg() |
1790 | ||
1791 | $x->bneg(); | |
1792 | ||
1793 | Used to negate the object in-place. | |
1794 | ||
7d341013 T |
1795 | =head2 is_one() |
1796 | ||
1797 | print "$x is 1\n" if $x->is_one(); | |
1798 | ||
1799 | Return true if $x is exactly one, otherwise false. | |
1800 | ||
1801 | =head2 is_zero() | |
1802 | ||
1803 | print "$x is 0\n" if $x->is_zero(); | |
1804 | ||
1805 | Return true if $x is exactly zero, otherwise false. | |
1806 | ||
b8884ce4 | 1807 | =head2 is_pos()/is_positive() |
7d341013 T |
1808 | |
1809 | print "$x is >= 0\n" if $x->is_positive(); | |
1810 | ||
1811 | Return true if $x is positive (greater than or equal to zero), otherwise | |
1812 | false. Please note that '+inf' is also positive, while 'NaN' and '-inf' aren't. | |
1813 | ||
b68b7ab1 T |
1814 | C<is_positive()> is an alias for C<is_pos()>. |
1815 | ||
b8884ce4 | 1816 | =head2 is_neg()/is_negative() |
7d341013 T |
1817 | |
1818 | print "$x is < 0\n" if $x->is_negative(); | |
1819 | ||
1820 | Return true if $x is negative (smaller than zero), otherwise false. Please | |
1821 | note that '-inf' is also negative, while 'NaN' and '+inf' aren't. | |
1822 | ||
b68b7ab1 T |
1823 | C<is_negative()> is an alias for C<is_neg()>. |
1824 | ||
7d341013 T |
1825 | =head2 is_int() |
1826 | ||
1827 | print "$x is an integer\n" if $x->is_int(); | |
1828 | ||
1829 | Return true if $x has a denominator of 1 (e.g. no fraction parts), otherwise | |
1830 | false. Please note that '-inf', 'inf' and 'NaN' aren't integer. | |
1831 | ||
1832 | =head2 is_odd() | |
1833 | ||
1834 | print "$x is odd\n" if $x->is_odd(); | |
1835 | ||
1836 | Return true if $x is odd, otherwise false. | |
1837 | ||
1838 | =head2 is_even() | |
1839 | ||
1840 | print "$x is even\n" if $x->is_even(); | |
1841 | ||
1842 | Return true if $x is even, otherwise false. | |
1843 | ||
1844 | =head2 bceil() | |
1845 | ||
1846 | $x->bceil(); | |
1847 | ||
1848 | Set $x to the next bigger integer value (e.g. truncate the number to integer | |
1849 | and then increment it by one). | |
1850 | ||
1851 | =head2 bfloor() | |
1852 | ||
1853 | $x->bfloor(); | |
1854 | ||
1855 | Truncate $x to an integer value. | |
6de7f0cc | 1856 | |
7afd7a91 T |
1857 | =head2 bsqrt() |
1858 | ||
1859 | $x->bsqrt(); | |
1860 | ||
1861 | Calculate the square root of $x. | |
1862 | ||
b8884ce4 T |
1863 | =head2 broot() |
1864 | ||
1865 | $x->broot($n); | |
1866 | ||
1867 | Calculate the N'th root of $x. | |
1868 | ||
1869 | =head2 badd()/bmul()/bsub()/bdiv()/bdec()/binc() | |
1870 | ||
1871 | Please see the documentation in L<Math::BigInt>. | |
1872 | ||
1873 | =head2 copy() | |
1874 | ||
1875 | my $z = $x->copy(); | |
1876 | ||
1877 | Makes a deep copy of the object. | |
1878 | ||
1879 | Please see the documentation in L<Math::BigInt> for further details. | |
1880 | ||
1881 | =head2 bstr()/bsstr() | |
1882 | ||
1883 | my $x = Math::BigInt->new('8/4'); | |
1884 | print $x->bstr(),"\n"; # prints 1/2 | |
1885 | print $x->bsstr(),"\n"; # prints 1/2 | |
1886 | ||
1887 | Return a string representating this object. | |
1888 | ||
1889 | =head2 bacmp()/bcmp() | |
1890 | ||
1891 | Used to compare numbers. | |
1892 | ||
1893 | Please see the documentation in L<Math::BigInt> for further details. | |
1894 | ||
1895 | =head2 blsft()/brsft() | |
1896 | ||
1897 | Used to shift numbers left/right. | |
1898 | ||
1899 | Please see the documentation in L<Math::BigInt> for further details. | |
1900 | ||
1901 | =head2 bpow() | |
1902 | ||
1903 | $x->bpow($y); | |
1904 | ||
1905 | Compute $x ** $y. | |
1906 | ||
1907 | Please see the documentation in L<Math::BigInt> for further details. | |
1908 | ||
116a1b2f SP |
1909 | =head2 bexp() |
1910 | ||
1911 | $x->bexp($accuracy); # calculate e ** X | |
1912 | ||
1913 | Calculates two integers A and B so that A/B is equal to C<e ** $x>, where C<e> is | |
1914 | Euler's number. | |
1915 | ||
1916 | This method was added in v0.20 of Math::BigRat (May 2007). | |
1917 | ||
1918 | See also L<blog()>. | |
1919 | ||
1920 | =head2 bnok() | |
1921 | ||
1922 | $x->bnok($y); # x over y (binomial coefficient n over k) | |
1923 | ||
1924 | Calculates the binomial coefficient n over k, also called the "choose" | |
1925 | function. The result is equivalent to: | |
1926 | ||
1927 | ( n ) n! | |
1928 | | - | = ------- | |
1929 | ( k ) k!(n-k)! | |
1930 | ||
1931 | This method was added in v0.20 of Math::BigRat (May 2007). | |
1932 | ||
b8884ce4 | 1933 | =head2 config() |
990fb837 RGS |
1934 | |
1935 | use Data::Dumper; | |
1936 | ||
1937 | print Dumper ( Math::BigRat->config() ); | |
1938 | print Math::BigRat->config()->{lib},"\n"; | |
1939 | ||
1940 | Returns a hash containing the configuration, e.g. the version number, lib | |
1941 | loaded etc. The following hash keys are currently filled in with the | |
1942 | appropriate information. | |
1943 | ||
1944 | key RO/RW Description | |
1945 | Example | |
1946 | ============================================================ | |
1947 | lib RO Name of the Math library | |
1948 | Math::BigInt::Calc | |
1949 | lib_version RO Version of 'lib' | |
1950 | 0.30 | |
1951 | class RO The class of config you just called | |
1952 | Math::BigRat | |
1953 | version RO version number of the class you used | |
1954 | 0.10 | |
1955 | upgrade RW To which class numbers are upgraded | |
1956 | undef | |
1957 | downgrade RW To which class numbers are downgraded | |
1958 | undef | |
1959 | precision RW Global precision | |
1960 | undef | |
1961 | accuracy RW Global accuracy | |
1962 | undef | |
1963 | round_mode RW Global round mode | |
1964 | even | |
3c4b39be | 1965 | div_scale RW Fallback accuracy for div |
990fb837 RGS |
1966 | 40 |
1967 | trap_nan RW Trap creation of NaN (undef = no) | |
1968 | undef | |
1969 | trap_inf RW Trap creation of +inf/-inf (undef = no) | |
1970 | undef | |
1971 | ||
1972 | By passing a reference to a hash you may set the configuration values. This | |
1973 | works only for values that a marked with a C<RW> above, anything else is | |
1974 | read-only. | |
1975 | ||
4de3d162 T |
1976 | =head2 objectify() |
1977 | ||
1978 | This is an internal routine that turns scalars into objects. | |
1979 | ||
a4e2b1c6 | 1980 | =head1 BUGS |
6de7f0cc | 1981 | |
7d341013 T |
1982 | Some things are not yet implemented, or only implemented half-way: |
1983 | ||
1984 | =over 2 | |
1985 | ||
1986 | =item inf handling (partial) | |
1987 | ||
1988 | =item NaN handling (partial) | |
1989 | ||
1990 | =item rounding (not implemented except for bceil/bfloor) | |
1991 | ||
1992 | =item $x ** $y where $y is not an integer | |
1993 | ||
7afd7a91 T |
1994 | =item bmod(), blog(), bmodinv() and bmodpow() (partial) |
1995 | ||
7d341013 | 1996 | =back |
184f15d5 JH |
1997 | |
1998 | =head1 LICENSE | |
1999 | ||
2000 | This program is free software; you may redistribute it and/or modify it under | |
2001 | the same terms as Perl itself. | |
2002 | ||
2003 | =head1 SEE ALSO | |
2004 | ||
2005 | L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>, | |
2006 | L<Math::BigInt::Pari> and L<Math::BigInt::GMP>. | |
2007 | ||
7d341013 T |
2008 | See L<http://search.cpan.org/search?dist=bignum> for a way to use |
2009 | Math::BigRat. | |
2010 | ||
2011 | The package at L<http://search.cpan.org/search?dist=Math%3A%3ABigRat> | |
2012 | may contain more documentation and examples as well as testcases. | |
184f15d5 JH |
2013 | |
2014 | =head1 AUTHORS | |
2015 | ||
c6c613ed CBW |
2016 | (C) by Tels L<http://bloodgate.com/> 2001 - 2009. |
2017 | ||
2018 | Currently maintained by Jonathan "Duke" Leto <jonathan@leto.net> L<http://leto.net> | |
184f15d5 JH |
2019 | |
2020 | =cut |