File Coverage

blib/lib/Math/BigFloat.pm
Criterion Covered Total %
statement 2145 3056 70.1
branch 1307 2288 57.1
condition 615 1056 58.2
subroutine 131 177 74.0
pod 103 104 99.0
total 4301 6681 64.3


line stmt bran cond sub pod time code
1             package Math::BigFloat;
2              
3             #
4             # Mike grinned. 'Two down, infinity to go' - Mike Nostrus in 'Before and After'
5             #
6              
7             # The following hash values are used internally:
8             #
9             # sign : "+", "-", "+inf", "-inf", or "NaN"
10             # _m : absolute value of mantissa ($LIB thingy)
11             # _es : sign of exponent ("+" or "-")
12             # _e : absolute value of exponent ($LIB thingy)
13             # accuracy : accuracy (scalar)
14             # precision : precision (scalar)
15              
16 43     43   1474307 use 5.006001;
  43         179  
17 43     43   291 use strict;
  43         145  
  43         1349  
18 43     43   260 use warnings;
  43         94  
  43         3092  
19              
20 43     43   263 use Carp qw< carp croak >;
  43         89  
  43         4007  
21 43     43   276 use Scalar::Util qw< blessed >;
  43         100  
  43         2522  
22 43     43   36572 use Math::BigInt qw< >;
  43         153  
  43         67960  
23              
24             our $VERSION = '2.005003';
25             $VERSION =~ tr/_//d;
26              
27             require Exporter;
28             our @ISA = qw< Math::BigInt >;
29             our @EXPORT_OK = qw< bpi >;
30              
31             use overload
32              
33             # overload key: with_assign
34              
35 33     33   304 '+' => sub { $_[0] -> copy() -> badd($_[1]); },
36              
37 22     22   1371 '-' => sub { my $c = $_[0] -> copy();
38 22 50       151 $_[2] ? $c -> bneg() -> badd($_[1])
39             : $c -> bsub($_[1]); },
40              
41 143     143   9304 '*' => sub { $_[0] -> copy() -> bmul($_[1]); },
42              
43 22 50   22   5230 '/' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bdiv($_[0])
44             : $_[0] -> copy() -> bdiv($_[1]); },
45              
46 0 0   0   0 '%' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bmod($_[0])
47             : $_[0] -> copy() -> bmod($_[1]); },
48              
49 7 50   7   1419 '**' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bpow($_[0])
50             : $_[0] -> copy() -> bpow($_[1]); },
51              
52 0 0   0   0 '<<' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bblsft($_[0])
53             : $_[0] -> copy() -> bblsft($_[1]); },
54              
55 0 0   0   0 '>>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bbrsft($_[0])
56             : $_[0] -> copy() -> bbrsft($_[1]); },
57              
58             # overload key: assign
59              
60 29     29   338 '+=' => sub { $_[0] -> badd($_[1]); },
61              
62 28     28   443 '-=' => sub { $_[0] -> bsub($_[1]); },
63              
64 6472     6472   22192 '*=' => sub { $_[0] -> bmul($_[1]); },
65              
66 8     8   120 '/=' => sub { scalar $_[0] -> bdiv($_[1]); },
67              
68 8     8   113 '%=' => sub { $_[0] -> bmod($_[1]); },
69              
70 4     4   71 '**=' => sub { $_[0] -> bpow($_[1]); },
71              
72 8     8   157 '<<=' => sub { $_[0] -> bblsft($_[1]); },
73              
74 8     8   1518 '>>=' => sub { $_[0] -> bbrsft($_[1]); },
75              
76             # 'x=' => sub { },
77              
78             # '.=' => sub { },
79              
80             # overload key: num_comparison
81              
82 671 50   671   4245 '<' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> blt($_[0])
83             : $_[0] -> blt($_[1]); },
84              
85 845 50   845   4121 '<=' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> ble($_[0])
86             : $_[0] -> ble($_[1]); },
87              
88 875 50   875   5128 '>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bgt($_[0])
89             : $_[0] -> bgt($_[1]); },
90              
91 216 100   216   1320 '>=' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bge($_[0])
92             : $_[0] -> bge($_[1]); },
93              
94 216     216   10040 '==' => sub { $_[0] -> beq($_[1]); },
95              
96 9     9   491 '!=' => sub { $_[0] -> bne($_[1]); },
97              
98             # overload key: 3way_comparison
99              
100 0     0   0 '<=>' => sub { my $cmp = $_[0] -> bcmp($_[1]);
101 0 0 0     0 defined($cmp) && $_[2] ? -$cmp : $cmp; },
102              
103 5885 50   5885   2928827 'cmp' => sub { $_[2] ? "$_[1]" cmp $_[0] -> bstr()
104             : $_[0] -> bstr() cmp "$_[1]"; },
105              
106             # overload key: str_comparison
107              
108             # 'lt' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrlt($_[0])
109             # : $_[0] -> bstrlt($_[1]); },
110             #
111             # 'le' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrle($_[0])
112             # : $_[0] -> bstrle($_[1]); },
113             #
114             # 'gt' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrgt($_[0])
115             # : $_[0] -> bstrgt($_[1]); },
116             #
117             # 'ge' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrge($_[0])
118             # : $_[0] -> bstrge($_[1]); },
119             #
120             # 'eq' => sub { $_[0] -> bstreq($_[1]); },
121             #
122             # 'ne' => sub { $_[0] -> bstrne($_[1]); },
123              
124             # overload key: binary
125              
126 0 0   0   0 '&' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> band($_[0])
127             : $_[0] -> copy() -> band($_[1]); },
128              
129 0     0   0 '&=' => sub { $_[0] -> band($_[1]); },
130              
131 0 0   0   0 '|' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bior($_[0])
132             : $_[0] -> copy() -> bior($_[1]); },
133              
134 0     0   0 '|=' => sub { $_[0] -> bior($_[1]); },
135              
136 0 0   0   0 '^' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bxor($_[0])
137             : $_[0] -> copy() -> bxor($_[1]); },
138              
139 0     0   0 '^=' => sub { $_[0] -> bxor($_[1]); },
140              
141             # '&.' => sub { },
142              
143             # '&.=' => sub { },
144              
145             # '|.' => sub { },
146              
147             # '|.=' => sub { },
148              
149             # '^.' => sub { },
150              
151             # '^.=' => sub { },
152              
153             # overload key: unary
154              
155 344     344   1578 'neg' => sub { $_[0] -> copy() -> bneg(); },
156              
157             # '!' => sub { },
158              
159 0     0   0 '~' => sub { $_[0] -> copy() -> bnot(); },
160              
161             # '~.' => sub { },
162              
163             # overload key: mutators
164              
165 7     7   92 '++' => sub { $_[0] -> binc() },
166              
167 0     0   0 '--' => sub { $_[0] -> bdec() },
168              
169             # overload key: func
170              
171 0 0   0   0 'atan2' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> batan2($_[0])
172             : $_[0] -> copy() -> batan2($_[1]); },
173              
174 0     0   0 'cos' => sub { $_[0] -> copy() -> bcos(); },
175              
176 0     0   0 'sin' => sub { $_[0] -> copy() -> bsin(); },
177              
178 0     0   0 'exp' => sub { $_[0] -> copy() -> bexp($_[1]); },
179              
180 10     10   48 'abs' => sub { $_[0] -> copy() -> babs(); },
181              
182 40     40   633 'log' => sub { $_[0] -> copy() -> blog(); },
183              
184 0     0   0 'sqrt' => sub { $_[0] -> copy() -> bsqrt(); },
185              
186 178     178   795 'int' => sub { $_[0] -> copy() -> bint(); },
187              
188             # overload key: conversion
189              
190 336 50   336   859 'bool' => sub { $_[0] -> is_zero() ? '' : 1; },
191              
192 738     738   120083 '""' => sub { $_[0] -> bstr(); },
193              
194 8     8   35 '0+' => sub { $_[0] -> numify(); },
195              
196 0     0   0 '=' => sub { $_[0] -> copy(); },
197              
198 43     43   412 ;
  43         88  
  43         3682  
199              
200             ##############################################################################
201             # global constants, flags and assorted stuff
202              
203             # the following are public, but their usage is not recommended. Use the
204             # accessor methods instead.
205              
206             # class constants, use Class->constant_name() to access
207             # one of 'even', 'odd', '+inf', '-inf', 'zero', 'trunc' or 'common'
208              
209             our $accuracy = undef;
210             our $precision = undef;
211             our $round_mode = 'even';
212             our $div_scale = 40;
213              
214             our $upgrade = undef;
215             our $downgrade = undef;
216              
217             our $_trap_nan = 0; # croak on NaNs?
218             our $_trap_inf = 0; # croak on Infs?
219              
220             my $nan = 'NaN'; # constant for easier life
221              
222             my $LIB = Math::BigInt -> config('lib'); # math backend library
223              
224             # Has import() been called yet? This variable is needed to make "require" work.
225              
226             my $IMPORT = 0;
227              
228             # some digits of accuracy for blog(undef, 10); which we use in blog() for speed
229             my $LOG_10 =
230             '2.3025850929940456840179914546843642076011014886287729760333279009675726097';
231             my $LOG_10_A = length($LOG_10)-1;
232             # ditto for log(2)
233             my $LOG_2 =
234             '0.6931471805599453094172321214581765680755001343602552541206800094933936220';
235             my $LOG_2_A = length($LOG_2)-1;
236             my $HALF = '0.5'; # made into an object if nec.
237              
238             ##############################################################################
239             # the old code had $rnd_mode, so we need to support it, too
240              
241             our $rnd_mode;
242             our $AUTOLOAD;
243              
244             sub TIESCALAR {
245 43     43   147 my ($class) = @_;
246 43         210 bless \$round_mode, $class;
247             }
248              
249             sub FETCH {
250 1     1   671 return $round_mode;
251             }
252              
253             sub STORE {
254 1     1   729 $rnd_mode = (ref $_[0]) -> round_mode($_[1]);
255             }
256              
257             BEGIN {
258 43     43   35517 *objectify = \&Math::BigInt::objectify;
259              
260             # when someone sets $rnd_mode, we catch this and check the value to see
261             # whether it is valid or not.
262 43         110 $rnd_mode = 'even';
263 43         218 tie $rnd_mode, 'Math::BigFloat';
264              
265 43         8331 *as_number = \&as_int;
266             }
267              
268       0     sub DESTROY {
269             # going through AUTOLOAD for every DESTROY is costly, avoid it by empty sub
270             }
271              
272             sub AUTOLOAD {
273              
274             # Make fxxx() work by mapping fxxx() to Math::BigFloat::bxxx().
275              
276 1820     1820   6234 my $name = $AUTOLOAD;
277 1820         8841 $name =~ s/^(.*):://; # strip package name
278 1820   50     6681 my $class = $1 || __PACKAGE__;
279              
280 1820 50       4180 $class -> import() if $IMPORT == 0;
281              
282             # E.g., "fabs" -> "babs", but "is_neg" -> "is_neg"
283              
284 1820         3300 my $bname = $name;
285 1820         3322 $bname =~ s/^f/b/;
286              
287             # Map, e.g., Math::BigFloat::fabs() to Math::BigFloat::babs()
288              
289 1820 50 33     11392 if ($bname ne $name && Math::BigFloat -> can($bname)) {
    50          
290 43     43   368 no strict 'refs';
  43         121  
  43         4343  
291 0         0 return &{"Math::BigFloat::$bname"}(@_);
  0         0  
292             }
293              
294             # Map, e.g., Math::BigFloat::babs() to Math::BigInt::babs()
295              
296             elsif (Math::BigInt -> can($bname)) {
297 43     43   244 no strict 'refs';
  43         77  
  43         240406  
298 1820         3525 return &{"Math::BigInt::$bname"}(@_);
  1820         8681  
299             }
300              
301             else {
302 0         0 croak("Can't call $class->$name(), not a valid method");
303             }
304             }
305              
306             ##############################################################################
307              
308             # Compare the following function with @ISA above. This inheritance mess needs a
309             # clean up. When doing so, also consider the BEGIN block and the AUTOLOAD code.
310             # Fixme!
311              
312             sub isa {
313 28987     28987 0 68462 my ($self, $class) = @_;
314 28987 100       82043 return if $class =~ /^Math::BigInt/; # we aren't one of these
315 27868         134379 UNIVERSAL::isa($self, $class);
316             }
317              
318             sub config {
319 435     435 1 1097048 my $self = shift;
320 435   50     1802 my $class = ref($self) || $self || __PACKAGE__;
321              
322             # Getter/accessor.
323              
324 435 100 100     1801 if (@_ == 1 && ref($_[0]) ne 'HASH') {
325 316         496 my $param = shift;
326 316 100       678 return $class if $param eq 'class';
327 314 100       705 return $LIB if $param eq 'with';
328 311         1035 return $self -> SUPER::config($param);
329             }
330              
331             # Setter.
332              
333 119         549 my $cfg = $self -> SUPER::config(@_);
334              
335             # We need only to override the ones that are different from our parent.
336              
337 115 100       370 unless (ref($self)) {
338 91         1059 $cfg->{class} = $class;
339 91         233 $cfg->{with} = $LIB;
340             }
341              
342 115         388 $cfg;
343             }
344              
345             ###############################################################################
346             # Constructor methods
347             ###############################################################################
348              
349             sub new {
350             # Create a new Math::BigFloat object from a string or another Math::BigInt,
351             # Math::BigFloat, or Math::BigRat object. See hash keys documented at top.
352              
353 20371     20371 1 3113771 my $self = shift;
354 20371         38936 my $selfref = ref $self;
355 20371   33     88161 my $class = $selfref || $self;
356              
357             # Make "require" work.
358              
359 20371 100       54147 $class -> import() if $IMPORT == 0;
360              
361             # Calling new() with no input arguments has been discouraged for more than
362             # 10 years, but people apparently still use it, so we still support it.
363              
364 20371 100       50957 return $class -> bzero() unless @_;
365              
366 20363         50243 my ($wanted, @r) = @_;
367              
368 20363 50       51887 if (!defined($wanted)) {
369             #if (warnings::enabled("uninitialized")) {
370             # warnings::warn("uninitialized",
371             # "Use of uninitialized value in new()");
372             #}
373 0         0 return $class -> bzero(@r);
374             }
375              
376 20363 50 66     90806 if (!ref($wanted) && $wanted eq "") {
377             #if (warnings::enabled("numeric")) {
378             # warnings::warn("numeric",
379             # q|Argument "" isn't numeric in new()|);
380             #}
381             #return $class -> bzero(@r);
382 0         0 return $class -> bnan(@r);
383             }
384              
385             # Initialize a new object.
386              
387 20363         55330 $self = bless {}, $class;
388              
389             # See if $wanted is an object that is a Math::BigFloat or can convert
390             # itself to a Math::BigFloat.
391              
392 20363 100 100     64920 if (defined(blessed($wanted)) && $wanted -> can('as_float')) {
393 167         554 my $tmp = $wanted -> as_float(@r);
394 167         487 for my $attr ('sign', '_m', '_es', '_e') {
395 668         1739 $self -> {$attr} = $tmp -> {$attr};
396             }
397 167         496 return $self -> round(@r);
398             }
399              
400             # From now on we only work on the stringified version of $wanted, so
401             # stringify it once and for all.
402              
403 20196         37892 $wanted = "$wanted";
404              
405             # Shortcut for simple forms like '123' that have no trailing zeros.
406             # Trailing zeros would require a non-zero exponent.
407              
408 20196 100       136514 if ($wanted =~
409             / ^
410             \s* # optional leading whitespace
411             ( [+-]? ) # optional sign
412             0* # optional leading zeros
413             ( [1-9] (?: [0-9]* [1-9] )? ) # significand
414             \s* # optional trailing whitespace
415             $
416             /x)
417             {
418 8794         36680 my $dng = $class -> downgrade();
419 8794 100 66     25948 return $dng -> new($1 . $2) if $dng && $dng ne $class;
420 8786   100     52162 $self->{sign} = $1 || '+';
421 8786         40040 $self->{_m} = $LIB -> _new($2);
422 8786         23527 $self->{_es} = '+';
423 8786         26689 $self->{_e} = $LIB -> _zero();
424 8786 100 100     68516 $self -> round(@r)
      100        
425             unless @r >= 2 && !defined $r[0] && !defined $r[1];
426 8786         101930 return $self;
427             }
428              
429             # Handle Infs.
430              
431 11402 100       48636 if ($wanted =~ / ^
432             \s*
433             ( [+-]? )
434             inf (?: inity )?
435             \s*
436             \z
437             /ix)
438             {
439 2605   100     12564 my $sgn = $1 || '+';
440 2605         12554 return $class -> binf($sgn, @r);
441             }
442              
443             # Handle explicit NaNs (not the ones returned due to invalid input).
444              
445 8797 100       34024 if ($wanted =~ / ^
446             \s*
447             ( [+-]? )
448             nan
449             \s*
450             \z
451             /ix)
452             {
453 795         3851 return $class -> bnan(@r);
454             }
455              
456 8002         14709 my @parts;
457              
458 8002 100 66     126139 if (
      33        
      66        
      100        
      66        
      100        
      33        
      66        
459             # Handle hexadecimal numbers. We auto-detect hexadecimal numbers if
460             # they have a "0x", "0X", "x", or "X" prefix, cf. CORE::oct().
461              
462             $wanted =~ /^\s*[+-]?0?[Xx]/ and
463             @parts = $class -> _hex_str_to_flt_lib_parts($wanted)
464              
465             or
466              
467             # Handle octal numbers. We auto-detect octal numbers if they have a
468             # "0o", "0O", "o", "O" prefix, cf. CORE::oct().
469              
470             $wanted =~ /^\s*[+-]?0?[Oo]/ and
471             @parts = $class -> _oct_str_to_flt_lib_parts($wanted)
472              
473             or
474              
475             # Handle binary numbers. We auto-detect binary numbers if they have a
476             # "0b", "0B", "b", or "B" prefix, cf. CORE::oct().
477              
478             $wanted =~ /^\s*[+-]?0?[Bb]/ and
479             @parts = $class -> _bin_str_to_flt_lib_parts($wanted)
480              
481             or
482              
483             # At this point, what is left are decimal numbers that aren't handled
484             # above and octal floating point numbers that don't have any of the
485             # "0o", "0O", "o", or "O" prefixes. First see if it is a decimal
486             # number.
487              
488             @parts = $class -> _dec_str_to_flt_lib_parts($wanted)
489             or
490              
491             # See if it is an octal floating point number. The extra check is
492             # included because _oct_str_to_flt_lib_parts() accepts octal numbers
493             # that don't have a prefix (this is needed to make it work with, e.g.,
494             # from_oct() that don't require a prefix). However, Perl requires a
495             # prefix for octal floating point literals. For example, "1p+0" is not
496             # valid, but "01p+0" and "0__1p+0" are.
497              
498             $wanted =~ /^\s*[+-]?0_*\d/ and
499             @parts = $class -> _oct_str_to_flt_lib_parts($wanted))
500             {
501 7214         43738 ($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
502              
503 7214 50 66     42470 $self -> round(@r)
      66        
504             unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
505              
506 7214 50 66     24233 $self -> _dng() if ($self -> is_int() ||
      66        
507             $self -> is_inf() ||
508             $self -> is_nan());
509              
510 7214         103901 return $self;
511             }
512              
513             # If we get here, the value is neither a valid decimal, binary, octal, or
514             # hexadecimal number. It is not an explicit Inf or a NaN either.
515              
516 788         3326 return $class -> bnan(@r);
517             }
518              
519             sub from_dec {
520 1     1 1 4649 my $self = shift;
521 1         3 my $selfref = ref $self;
522 1   33     9 my $class = $selfref || $self;
523              
524             # Make "require" work.
525              
526 1 50       4 $class -> import() if $IMPORT == 0;
527              
528             # Don't modify constant (read-only) objects.
529              
530 1 50 33     6 return $self if $selfref && $self -> modify('from_dec');
531              
532 1         4 my $str = shift;
533 1         3 my @r = @_;
534              
535 1 50       8 if (my @parts = $class -> _dec_str_to_flt_lib_parts($str)) {
536              
537             # If called as a class method, initialize a new object.
538              
539 1 50       5 unless ($selfref) {
540 1         4 $self = bless {}, $class;
541             #$self -> _init();
542             }
543              
544 1         7 ($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
545              
546 1 0 33     11 $self -> round(@r)
      33        
547             unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
548              
549 1 0 33     6 $self -> _dng() if ($self -> is_int() ||
      33        
550             $self -> is_inf() ||
551             $self -> is_nan());
552              
553 1         6 return $self;
554             }
555              
556 0         0 return $self -> bnan(@r);
557             }
558              
559             sub from_hex {
560 1     1 1 5432 my $self = shift;
561 1         2 my $selfref = ref $self;
562 1   33     9 my $class = $selfref || $self;
563              
564             # Make "require" work.
565              
566 1 50       5 $class -> import() if $IMPORT == 0;
567              
568             # Don't modify constant (read-only) objects.
569              
570 1 50 33     5 return $self if $selfref && $self -> modify('from_hex');
571              
572 1         3 my $str = shift;
573 1         3 my @r = @_;
574              
575 1 50       13 if (my @parts = $class -> _hex_str_to_flt_lib_parts($str)) {
576              
577             # If called as a class method, initialize a new object.
578              
579 1 50       3 unless ($selfref) {
580 1         4 $self = bless {}, $class;
581             #$self -> _init();
582             }
583              
584 1         6 ($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
585              
586 1 0 33     10 $self -> round(@r)
      33        
587             unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
588              
589 1 0 33     6 $self -> _dng() if ($self -> is_int() ||
      33        
590             $self -> is_inf() ||
591             $self -> is_nan());
592 1         6 return $self;
593             }
594              
595 0         0 return $self -> bnan(@r);
596             }
597              
598             sub from_oct {
599 1     1 1 4670 my $self = shift;
600 1         4 my $selfref = ref $self;
601 1   33     9 my $class = $selfref || $self;
602              
603             # Make "require" work.
604              
605 1 50       5 $class -> import() if $IMPORT == 0;
606              
607             # Don't modify constant (read-only) objects.
608              
609 1 50 33     5 return $self if $selfref && $self -> modify('from_oct');
610              
611 1         3 my $str = shift;
612 1         5 my @r = @_;
613              
614 1 50       14 if (my @parts = $class -> _oct_str_to_flt_lib_parts($str)) {
615              
616             # If called as a class method, initialize a new object.
617              
618 1 50       4 unless ($selfref) {
619 1         4 $self = bless {}, $class;
620             #$self -> _init();
621             }
622              
623 1         6 ($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
624              
625 1 0 33     10 $self -> round(@r)
      33        
626             unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
627              
628 1 0 33     5 $self -> _dng() if ($self -> is_int() ||
      33        
629             $self -> is_inf() ||
630             $self -> is_nan());
631 1         6 return $self;
632             }
633              
634 0         0 return $self -> bnan(@r);
635             }
636              
637             sub from_bin {
638 3     3 1 4044 my $self = shift;
639 3         9 my $selfref = ref $self;
640 3   33     74 my $class = $selfref || $self;
641              
642             # Make "require" work.
643              
644 3 50       11 $class -> import() if $IMPORT == 0;
645              
646             # Don't modify constant (read-only) objects.
647              
648 3 50 33     15 return $self if $selfref && $self -> modify('from_bin');
649              
650 3         9 my $str = shift;
651 3         8 my @r = @_;
652              
653 3 50       22 if (my @parts = $class -> _bin_str_to_flt_lib_parts($str)) {
654              
655             # If called as a class method, initialize a new object.
656              
657 3 50       10 unless ($selfref) {
658 3         12 $self = bless {}, $class;
659             #$self -> _init();
660             }
661              
662 3         17 ($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
663              
664 3 0 33     23 $self -> round(@r)
      33        
665             unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
666              
667 3 0 33     13 $self -> _dng() if ($self -> is_int() ||
      33        
668             $self -> is_inf() ||
669             $self -> is_nan());
670 3         16 return $self;
671             }
672              
673 0         0 return $self -> bnan(@r);
674             }
675              
676             sub from_bytes {
677 0     0 1 0 my $self = shift;
678 0         0 my $selfref = ref $self;
679 0   0     0 my $class = $selfref || $self;
680              
681             # Make "require" work.
682              
683 0 0       0 $class -> import() if $IMPORT == 0;
684              
685             # Don't modify constant (read-only) objects.
686              
687 0 0 0     0 return $self if $selfref && $self -> modify('from_bytes');
688              
689 0         0 my $str = shift;
690 0         0 my @r = @_;
691              
692             # If called as a class method, initialize a new object.
693              
694 0 0       0 $self = $class -> bzero(@r) unless $selfref;
695              
696 0         0 $self -> {sign} = "+";
697 0         0 $self -> {_m} = $LIB -> _from_bytes($str);
698 0         0 $self -> {_es} = "+";
699 0         0 $self -> {_e} = $LIB -> _zero();
700 0         0 $self -> bnorm();
701              
702 0         0 $self -> _dng();
703 0         0 return $self;
704             }
705              
706             sub from_ieee754 {
707 1     1 1 4553 my $self = shift;
708 1         4 my $selfref = ref $self;
709 1   33     8 my $class = $selfref || $self;
710              
711             # Make "require" work.
712              
713 1 50       5 $class -> import() if $IMPORT == 0;
714              
715             # Don't modify constant (read-only) objects.
716              
717 1 50 33     6 return $self if $selfref && $self -> modify('from_ieee754');
718              
719 1         3 my $in = shift; # input string (or raw bytes)
720 1         3 my $format = shift; # format ("binary32", "decimal64" etc.)
721 1         4 my $enc; # significand encoding (applies only to decimal)
722             my $k; # storage width in bits
723 1         0 my $b; # base
724 1         3 my @r = @_; # rounding parameters, if any
725              
726 1 50       10 if ($format =~ /^binary(\d+)\z/) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
727 1         4 $k = $1;
728 1         4 $b = 2;
729             } elsif ($format =~ /^decimal(\d+)(dpd|bcd)?\z/) {
730 0         0 $k = $1;
731 0         0 $b = 10;
732 0   0     0 $enc = $2 || 'dpd'; # default is dencely-packed decimals (DPD)
733             } elsif ($format eq 'half') {
734 0         0 $k = 16;
735 0         0 $b = 2;
736             } elsif ($format eq 'single') {
737 0         0 $k = 32;
738 0         0 $b = 2;
739             } elsif ($format eq 'double') {
740 0         0 $k = 64;
741 0         0 $b = 2;
742             } elsif ($format eq 'quadruple') {
743 0         0 $k = 128;
744 0         0 $b = 2;
745             } elsif ($format eq 'octuple') {
746 0         0 $k = 256;
747 0         0 $b = 2;
748             } elsif ($format eq 'sexdecuple') {
749 0         0 $k = 512;
750 0         0 $b = 2;
751             }
752              
753 1 50       3 if ($b == 2) {
754              
755             # Get the parameters for this format.
756              
757 1         4 my $p; # precision (in bits)
758             my $t; # number of bits in significand
759 1         0 my $w; # number of bits in exponent
760              
761 1 50       7 if ($k == 16) { # binary16 (half-precision)
    50          
    0          
762 0         0 $p = 11;
763 0         0 $t = 10;
764 0         0 $w = 5;
765             } elsif ($k == 32) { # binary32 (single-precision)
766 1         3 $p = 24;
767 1         2 $t = 23;
768 1         3 $w = 8;
769             } elsif ($k == 64) { # binary64 (double-precision)
770 0         0 $p = 53;
771 0         0 $t = 52;
772 0         0 $w = 11;
773             } else { # binaryN (quadruple-precision and above)
774 0 0 0     0 if ($k < 128 || $k != 32 * sprintf('%.0f', $k / 32)) {
775 0         0 croak "Number of bits must be 16, 32, 64, or >= 128 and",
776             " a multiple of 32";
777             }
778 0         0 $p = $k - sprintf('%.0f', 4 * log($k) / log(2)) + 13;
779 0         0 $t = $p - 1;
780 0         0 $w = $k - $t - 1;
781             }
782              
783             # The maximum exponent, minimum exponent, and exponent bias.
784              
785 1         7 my $emax = $class -> new(2) -> bpow($w - 1) -> bdec();
786 1         25 my $emin = 1 - $emax;
787 1         3 my $bias = $emax;
788              
789             # Undefined input.
790              
791 1 50       4 unless (defined $in) {
792 0         0 carp("Input is undefined");
793 0         0 return $self -> bzero(@r);
794             }
795              
796             # Make sure input string is a string of zeros and ones.
797              
798 1         3 my $len = CORE::length $in;
799 1 50       5 if (8 * $len == $k) { # bytes
    0          
    0          
800 1         6 $in = unpack "B*", $in;
801             } elsif (4 * $len == $k) { # hexadecimal
802 0 0       0 if ($in =~ /([^\da-f])/i) {
803 0         0 croak "Illegal hexadecimal digit '$1'";
804             }
805 0         0 $in = unpack "B*", pack "H*", $in;
806             } elsif ($len == $k) { # bits
807 0 0       0 if ($in =~ /([^01])/) {
808 0         0 croak "Illegal binary digit '$1'";
809             }
810             } else {
811 0         0 croak "Unknown input -- $in";
812             }
813              
814             # Split bit string into sign, exponent, and mantissa/significand.
815              
816 1 50       6 my $sign = substr($in, 0, 1) eq '1' ? '-' : '+';
817 1         8 my $expo = $class -> from_bin(substr($in, 1, $w));
818 1         9 my $mant = $class -> from_bin(substr($in, $w + 1));
819              
820 1         5 my $x;
821              
822 1         8 $expo -> bsub($bias); # subtract bias
823              
824 1 50       6 if ($expo < $emin) { # zero and subnormals
    50          
825 0 0       0 if ($mant == 0) { # zero
826 0         0 $x = $class -> bzero();
827             } else { # subnormals
828             # compute (1/$b)**(N) rather than ($b)**(-N)
829 0         0 $x = $class -> new("0.5"); # 1/$b
830 0         0 $x -> bpow($bias + $t - 1) -> bmul($mant);
831 0 0       0 $x -> bneg() if $sign eq '-';
832             }
833             }
834              
835             elsif ($expo > $emax) { # inf and nan
836 0 0       0 if ($mant == 0) { # inf
837 0         0 $x = $class -> binf($sign);
838             } else { # nan
839 0         0 $x = $class -> bnan(@r);
840             }
841             }
842              
843             else { # normals
844 1         6 $mant = $class -> new(2) -> bpow($t) -> badd($mant);
845 1 50       8 if ($expo < $t) {
846             # compute (1/$b)**(N) rather than ($b)**(-N)
847 1         6 $x = $class -> new("0.5"); # 1/$b
848 1         7 $x -> bpow($t - $expo) -> bmul($mant);
849             } else {
850 0         0 $x = $class -> new(2);
851 0         0 $x -> bpow($expo - $t) -> bmul($mant);
852             }
853 1 50       9 $x -> bneg() if $sign eq '-';
854             }
855              
856 1 50       6 if ($selfref) {
857 0         0 $self -> {sign} = $x -> {sign};
858 0         0 $self -> {_m} = $x -> {_m};
859 0         0 $self -> {_es} = $x -> {_es};
860 0         0 $self -> {_e} = $x -> {_e};
861             } else {
862 1         3 $self = $x;
863             }
864              
865 1         6 $self -> round(@r);
866 1 0 33     4 $self -> _dng() if ($self -> is_int() ||
      33        
867             $self -> is_inf() ||
868             $self -> is_nan());
869 1         14 return $self;
870             }
871              
872 0         0 croak("The format '$format' is not yet supported.");
873             }
874              
875             sub from_fp80 {
876 0     0 1 0 my $self = shift;
877 0         0 my $selfref = ref $self;
878 0   0     0 my $class = $selfref || $self;
879              
880             # Make "require" work.
881              
882 0 0       0 $class -> import() if $IMPORT == 0;
883              
884             # Don't modify constant (read-only) objects.
885              
886 0 0 0     0 return $self if $selfref && $self -> modify('from_fp80');
887              
888 0         0 my $in = shift; # input string (or raw bytes)
889 0         0 my @r = @_; # rounding parameters, if any
890              
891             # Undefined input.
892              
893 0 0       0 unless (defined $in) {
894 0         0 carp("Input is undefined");
895 0         0 return $self -> bzero(@r);
896             }
897              
898             # The parameters for this format.
899              
900 0         0 my $p = 64; # precision (in bits)
901 0         0 my $w = 15; # number of bits in exponent
902              
903             # The maximum exponent, minimum exponent, and exponent bias.
904              
905 0         0 my $emax = $class -> new(2) -> bpow($w - 1) -> bdec(); # = 16383
906 0         0 my $emin = 1 - $emax; # = -16382
907 0         0 my $bias = $emax; # = -16383
908              
909             # Make sure input string is a string of zeros and ones.
910              
911 0         0 my $len = CORE::length $in;
912 0 0       0 if (8 * $len == 80) { # bytes
    0          
    0          
913 0         0 $in = unpack "B*", $in;
914             } elsif (4 * $len == 80) { # hexadecimal
915 0 0       0 if ($in =~ /([^\da-f])/i) {
916 0         0 croak "Illegal hexadecimal digit '$1'";
917             }
918 0         0 $in = unpack "B*", pack "H*", $in;
919             } elsif ($len == 80) { # bits
920 0 0       0 if ($in =~ /([^01])/) {
921 0         0 croak "Illegal binary digit '$1'";
922             }
923             } else {
924 0         0 croak "Unknown input -- $in";
925             }
926              
927             # Split bit string into sign, exponent, and mantissa/significand.
928              
929 0 0       0 my $sign = substr($in, 0, 1) eq '1' ? '-' : '+';
930 0         0 my $expo = $class -> from_bin(substr($in, 1, $w));
931 0         0 my $mant = $class -> from_bin(substr($in, $w + 1));
932              
933 0         0 my $x;
934              
935 0         0 $expo -> bsub($bias); # subtract bias
936              
937             # zero and subnormal numbers
938              
939 0 0       0 if ($expo < $emin) {
    0          
940 0 0       0 if ($mant == 0) { # zero
941 0         0 $x = $class -> bzero();
942             } else { # subnormals
943             # compute (1/2)**N rather than 2**(-N)
944 0         0 $x = $class -> new("0.5");
945 0         0 $x -> bpow(-$emin - 1 + $p) -> bmul($mant);
946 0 0       0 $x -> bneg() if $sign eq '-';
947             }
948             }
949              
950             # inf and nan
951              
952             elsif ($expo > $emax) {
953              
954             # if fraction of mantissa is zero, i.e., if mantissa is
955             # 0.000... or 1.000...
956              
957 0 0       0 if (substr($in, 16) =~ /^[01]0+$/) {
958 0         0 $x = $class -> binf($sign);
959             } else {
960 0         0 $x = $class -> bnan();
961             }
962             }
963              
964             # normal numbers
965              
966             else {
967              
968             # downscale mantissa
969 0         0 $mant -> blsft($p - 1, "0.5"); # brsft($p - 1, 2) does division
970              
971 0 0       0 if ($expo < 0) {
    0          
972             # compute (1/2)**N rather than 2**(-N)
973 0         0 $x = $mant -> blsft(-$expo, "0.5");
974             } elsif ($expo > 0) {
975 0         0 $x = $mant -> blsft($expo, "2");
976             } else {
977 0         0 $x = $mant;
978             }
979              
980 0 0       0 $x -> bneg() if $sign eq '-';
981             }
982              
983 0 0       0 if ($selfref) {
984 0         0 $self -> {sign} = $x -> {sign};
985 0         0 $self -> {_m} = $x -> {_m};
986 0         0 $self -> {_es} = $x -> {_es};
987 0         0 $self -> {_e} = $x -> {_e};
988             } else {
989 0         0 $self = $x;
990             }
991              
992 0         0 $self -> round(@r);
993 0 0 0     0 $self -> _dng() if ($self -> is_int() ||
      0        
994             $self -> is_inf() ||
995             $self -> is_nan());
996 0         0 return $self;
997             }
998              
999             sub from_base {
1000 0     0 1 0 my $self = shift;
1001 0         0 my $selfref = ref $self;
1002 0   0     0 my $class = $selfref || $self;
1003              
1004             # Make "require" work.
1005              
1006 0 0       0 $class -> import() if $IMPORT == 0;
1007              
1008             # Don't modify constant (read-only) objects.
1009              
1010 0 0 0     0 return $self if $selfref && $self -> modify('from_base');
1011              
1012 0         0 my ($str, $base, $cs, @r) = @_; # $cs is the collation sequence
1013              
1014 0 0       0 $base = $class -> new($base) unless ref($base);
1015              
1016 0 0 0     0 croak("the base must be a finite integer >= 2")
1017             if $base < 2 || ! $base -> is_int();
1018              
1019             # If called as a class method, initialize a new object.
1020              
1021 0 0       0 $self = $class -> bzero() unless $selfref;
1022              
1023             # If no collating sequence is given, pass some of the conversions to
1024             # methods optimized for those cases.
1025              
1026 0 0       0 unless (defined $cs) {
1027 0 0       0 return $self -> from_bin($str, @r) if $base == 2;
1028 0 0       0 return $self -> from_oct($str, @r) if $base == 8;
1029 0 0       0 return $self -> from_hex($str, @r) if $base == 16;
1030 0 0       0 return $self -> from_dec($str, @r) if $base == 10;
1031             }
1032              
1033 0 0       0 croak("from_base() requires a newer version of the $LIB library.")
1034             unless $LIB -> can('_from_base');
1035              
1036 0         0 my $base_lib = $LIB -> _lsft($LIB -> _copy($base->{_m}), $base->{_e}, 10);
1037 0         0 $self -> {sign} = '+';
1038 0 0       0 $self -> {_m} = $LIB->_from_base($str, $base_lib,
1039             defined($cs) ? $cs : ());
1040 0         0 $self -> {_es} = "+";
1041 0         0 $self -> {_e} = $LIB->_zero();
1042 0         0 $self -> bnorm();
1043              
1044 0         0 $self -> bround(@r);
1045 0         0 $self -> _dng();
1046 0         0 return $self;
1047             }
1048              
1049             sub bzero {
1050             # create/assign '+0'
1051              
1052             # Class::method(...) -> Class->method(...)
1053 599 50 66 599 1 32497 unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
      66        
1054             $_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i))
1055             {
1056             #carp "Using ", (caller(0))[3], "() as a function is deprecated;",
1057             # " use is as a method instead";
1058 0         0 unshift @_, __PACKAGE__;
1059             }
1060              
1061 599         1561 my $self = shift;
1062 599         1365 my $selfref = ref $self;
1063 599   66     2107 my $class = $selfref || $self;
1064              
1065             # Make "require" work.
1066              
1067 599 50       1791 $class -> import() if $IMPORT == 0;
1068              
1069             # Don't modify constant (read-only) objects.
1070              
1071 599 50 66     3473 return $self if $selfref && $self -> modify('bzero');
1072              
1073 599         2344 my $dng = $class -> downgrade();
1074 599 100 66     2214 if ($dng && $dng ne $class) {
1075 1 50       6 return $self -> _dng() -> bzero(@_) if $selfref;
1076 1         8 return $dng -> bzero(@_);
1077             }
1078              
1079             # Get the rounding parameters, if any.
1080              
1081 598         1635 my @r = @_;
1082              
1083             # If called as a class method, initialize a new object.
1084              
1085 598 100       1693 $self = bless {}, $class unless $selfref;
1086              
1087 598         1740 $self -> {sign} = '+';
1088 598         2522 $self -> {_m} = $LIB -> _zero();
1089 598         1568 $self -> {_es} = '+';
1090 598         1877 $self -> {_e} = $LIB -> _zero();
1091              
1092             # If rounding parameters are given as arguments, use them. If no rounding
1093             # parameters are given, and if called as a class method initialize the new
1094             # instance with the class variables.
1095              
1096             #return $self -> round(@r); # this should work, but doesnt; fixme!
1097              
1098 598 100       1791 if (@r) {
1099 78 50 100     503 if (@r >= 2 && defined($r[0]) && defined($r[1])) {
      66        
1100 0         0 carp "can't specify both accuracy and precision";
1101 0         0 return $self -> bnan();
1102             }
1103 78         240 $self->{accuracy} = $r[0];
1104 78         285 $self->{precision} = $r[1];
1105             } else {
1106 520 100       1587 unless($selfref) {
1107 98         436 $self->{accuracy} = $class -> accuracy();
1108 98         330 $self->{precision} = $class -> precision();
1109             }
1110             }
1111              
1112 598         5649 return $self;
1113             }
1114              
1115             sub bone {
1116             # Create or assign '+1' (or -1 if given sign '-').
1117              
1118             # Class::method(...) -> Class->method(...)
1119 1720 50 66 1720 1 67031 unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
      66        
1120             $_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i))
1121             {
1122             #carp "Using ", (caller(0))[3], "() as a function is deprecated;",
1123             # " use is as a method instead";
1124 0         0 unshift @_, __PACKAGE__;
1125             }
1126              
1127 1720         4065 my $self = shift;
1128 1720         3606 my $selfref = ref $self;
1129 1720   66     6117 my $class = $selfref || $self;
1130              
1131             # Make "require" work.
1132              
1133 1720 50       4741 $class -> import() if $IMPORT == 0;
1134              
1135             # Don't modify constant (read-only) objects.
1136              
1137 1720 50 66     6641 return $self if $selfref && $self -> modify('bone');
1138              
1139 1720         6182 my $dng = $class -> downgrade();
1140 1720 100 66     5058 if ($dng && $dng ne $class) {
1141 1 50       5 return $self -> _dng() -> bone(@_) if $selfref;
1142 1         7 return $dng -> bone(@_);
1143             }
1144              
1145             # Get the sign.
1146              
1147 1719         4225 my $sign = '+'; # default is to return +1
1148 1719 100 100     6327 if (defined($_[0]) && $_[0] =~ /^\s*([+-])\s*$/) {
1149 170         596 $sign = $1;
1150 170         319 shift;
1151             }
1152              
1153             # Get the rounding parameters, if any.
1154              
1155 1719         3927 my @r = @_;
1156              
1157             # If called as a class method, initialize a new object.
1158              
1159 1719 100       5782 $self = bless {}, $class unless $selfref;
1160              
1161 1719         5287 $self -> {sign} = $sign;
1162 1719         6877 $self -> {_m} = $LIB -> _one();
1163 1719         4100 $self -> {_es} = '+';
1164 1719         5262 $self -> {_e} = $LIB -> _zero();
1165              
1166             # If rounding parameters are given as arguments, use them. If no rounding
1167             # parameters are given, and if called as a class method initialize the new
1168             # instance with the class variables.
1169              
1170             #return $self -> round(@r); # this should work, but doesnt; fixme!
1171              
1172 1719 100       4127 if (@r) {
1173 29 50 100     161 if (@r >= 2 && defined($r[0]) && defined($r[1])) {
      66        
1174 0         0 carp "can't specify both accuracy and precision";
1175 0         0 return $self -> bnan();
1176             }
1177 29         114 $self->{accuracy} = $_[0];
1178 29         97 $self->{precision} = $_[1];
1179             } else {
1180 1690 100       4402 unless($selfref) {
1181 1129         3852 $self->{accuracy} = $class -> accuracy();
1182 1129         3548 $self->{precision} = $class -> precision();
1183             }
1184             }
1185              
1186 1719         8832 return $self;
1187             }
1188              
1189             sub binf {
1190             # create/assign a '+inf' or '-inf'
1191              
1192             # Class::method(...) -> Class->method(...)
1193 3027 50 66 3027 1 40098 unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
      66        
1194             $_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i))
1195             {
1196             #carp "Using ", (caller(0))[3], "() as a function is deprecated;",
1197             # " use is as a method instead";
1198 0         0 unshift @_, __PACKAGE__;
1199             }
1200              
1201 3027         6112 my $self = shift;
1202 3027         5751 my $selfref = ref $self;
1203 3027   66     9771 my $class = $selfref || $self;
1204              
1205             {
1206 43     43   428 no strict 'refs';
  43         84  
  43         29155  
  3027         6462  
1207 3027 100       4792 if (${"${class}::_trap_inf"}) {
  3027         16338  
1208 16         3647 croak("Tried to create +-inf in $class->binf()");
1209             }
1210             }
1211              
1212             # Make "require" work.
1213              
1214 3011 50       7435 $class -> import() if $IMPORT == 0;
1215              
1216             # Don't modify constant (read-only) objects.
1217              
1218 3011 50 66     9840 return $self if $selfref && $self -> modify('binf');
1219              
1220             # Get the sign.
1221              
1222 3011         5927 my $sign = '+'; # default is to return positive infinity
1223 3011 100 100     19728 if (defined($_[0]) && $_[0] =~ /^\s*([+-])(inf|$)/i) {
1224 2927         6854 $sign = $1;
1225 2927         4625 shift;
1226             }
1227              
1228             # Get the rounding parameters, if any.
1229              
1230 3011         7025 my @r = @_;
1231              
1232             # Downgrade?
1233              
1234 3011         12002 my $dng = $class -> downgrade();
1235 3011 100 66     8990 if ($dng && $dng ne $class) {
1236 10 100       41 return $self -> _dng() -> binf($sign, @r) if $selfref;
1237 2         12 return $dng -> binf($sign, @r);
1238             }
1239              
1240             # If called as a class method, initialize a new object.
1241              
1242 3001 100       9657 $self = bless {}, $class unless $selfref;
1243              
1244 3001         10809 $self -> {sign} = $sign . 'inf';
1245 3001         13026 $self -> {_m} = $LIB -> _zero();
1246 3001         7243 $self -> {_es} = '+';
1247 3001         7542 $self -> {_e} = $LIB -> _zero();
1248              
1249             # If rounding parameters are given as arguments, use them. If no rounding
1250             # parameters are given, and if called as a class method initialize the new
1251             # instance with the class variables.
1252              
1253             #return $self -> round(@r); # this should work, but doesnt; fixme!
1254              
1255 3001 100       7196 if (@r) {
1256 919 50 66     4058 if (@r >= 2 && defined($r[0]) && defined($r[1])) {
      33        
1257 0         0 carp "can't specify both accuracy and precision";
1258 0         0 return $self -> bnan();
1259             }
1260 919         2046 $self->{accuracy} = $r[0];
1261 919         2074 $self->{precision} = $r[1];
1262             } else {
1263 2082 100       5097 unless($selfref) {
1264 1755         6127 $self->{accuracy} = $class -> accuracy();
1265 1755         5634 $self->{precision} = $class -> precision();
1266             }
1267             }
1268              
1269 3001         37760 return $self;
1270             }
1271              
1272             sub bnan {
1273             # create/assign a 'NaN'
1274              
1275             # Class::method(...) -> Class->method(...)
1276 2751 50 66 2751 1 35437 unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
      66        
1277             $_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i))
1278             {
1279             #carp "Using ", (caller(0))[3], "() as a function is deprecated;",
1280             # " use is as a method instead";
1281 0         0 unshift @_, __PACKAGE__;
1282             }
1283              
1284 2751         6045 my $self = shift;
1285 2751         5161 my $selfref = ref $self;
1286 2751   66     8785 my $class = $selfref || $self;
1287              
1288             {
1289 43     43   387 no strict 'refs';
  43         87  
  43         1535474  
  2751         4652  
1290 2751 100       4770 if (${"${class}::_trap_nan"}) {
  2751         13594  
1291 7         1670 croak("Tried to create NaN in $class->bnan()");
1292             }
1293             }
1294              
1295             # Make "require" work.
1296              
1297 2744 50       6767 $class -> import() if $IMPORT == 0;
1298              
1299             # Don't modify constant (read-only) objects.
1300              
1301 2744 50 66     10681 return $self if $selfref && $self -> modify('bnan');
1302              
1303 2744         9619 my $dng = $class -> downgrade();
1304 2744 100 66     8204 if ($dng && $dng ne $class) {
1305 11 100       50 return $self -> _dng() -> bnan(@_) if $selfref;
1306 2         11 return $dng -> bnan(@_);
1307             }
1308              
1309             # Get the rounding parameters, if any.
1310              
1311 2733         6306 my @r = @_;
1312              
1313             # If called as a class method, initialize a new object.
1314              
1315 2733 100       7804 $self = bless {}, $class unless $selfref;
1316              
1317 2733         8757 $self -> {sign} = $nan;
1318 2733         10729 $self -> {_m} = $LIB -> _zero();
1319 2733         6197 $self -> {_es} = '+';
1320 2733         6857 $self -> {_e} = $LIB -> _zero();
1321              
1322             # If rounding parameters are given as arguments, use them. If no rounding
1323             # parameters are given, and if called as a class method initialize the new
1324             # instance with the class variables.
1325              
1326             #return $self -> round(@r); # this should work, but doesnt; fixme!
1327              
1328 2733 100       6471 if (@r) {
1329 752 50 66     3574 if (@r >= 2 && defined($r[0]) && defined($r[1])) {
      33        
1330 0         0 carp "can't specify both accuracy and precision";
1331 0         0 return $self -> bnan();
1332             }
1333 752         1847 $self->{accuracy} = $r[0];
1334 752         1748 $self->{precision} = $r[1];
1335             } else {
1336 1981 100       4933 unless($selfref) {
1337 1028         3655 $self->{accuracy} = $class -> accuracy();
1338 1028         3511 $self->{precision} = $class -> precision();
1339             }
1340             }
1341              
1342 2733         31627 return $self;
1343             }
1344              
1345             sub bpi {
1346              
1347             # Class::method(...) -> Class->method(...)
1348 257 100 66 257 1 241606 unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
      66        
1349             $_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i))
1350             {
1351             #carp "Using ", (caller(0))[3], "() as a function is deprecated;",
1352             # " use is as a method instead";
1353 1         5 unshift @_, __PACKAGE__;
1354             }
1355              
1356             # Called as Argument list
1357             # --------- -------------
1358             # Math::BigFloat->bpi() ("Math::BigFloat")
1359             # Math::BigFloat->bpi(10) ("Math::BigFloat", 10)
1360             # $x->bpi() ($x)
1361             # $x->bpi(10) ($x, 10)
1362             # Math::BigFloat::bpi() ()
1363             # Math::BigFloat::bpi(10) (10)
1364             #
1365             # In ambiguous cases, we favour the OO-style, so the following case
1366             #
1367             # $n = Math::BigFloat->new("10");
1368             # $x = Math::BigFloat->bpi($n);
1369             #
1370             # which gives an argument list with the single element $n, is resolved as
1371             #
1372             # $n->bpi();
1373              
1374 257         597 my $self = shift;
1375 257         570 my $selfref = ref $self;
1376 257   66     991 my $class = $selfref || $self;
1377 257         768 my @r = @_; # rounding paramters
1378              
1379             # Make "require" work.
1380              
1381 257 50       745 $class -> import() if $IMPORT == 0;
1382              
1383 257 100       706 if ($selfref) { # bpi() called as an instance method
1384 83 50       379 return $self if $self -> modify('bpi');
1385             } else { # bpi() called as a class method
1386 174         533 $self = bless {}, $class; # initialize new instance
1387             }
1388              
1389 257         1043 ($self, @r) = $self -> _find_round_parameters(@r);
1390              
1391             # The accuracy, i.e., the number of digits. Pi has one digit before the
1392             # dot, so a precision of 4 digits is equivalent to an accuracy of 5 digits.
1393              
1394 257 50       864 my $n = defined $r[0] ? $r[0]
    100          
1395             : defined $r[1] ? 1 - $r[1]
1396             : $self -> div_scale();
1397              
1398 257 100       756 my $rmode = defined $r[2] ? $r[2] : $self -> round_mode();
1399              
1400 257         473 my $pi;
1401              
1402 257 50       714 if ($n <= 1000) {
1403              
1404             # 75 x 14 = 1050 digits
1405              
1406 257         514 my $all_digits = <
1407             314159265358979323846264338327950288419716939937510582097494459230781640628
1408             620899862803482534211706798214808651328230664709384460955058223172535940812
1409             848111745028410270193852110555964462294895493038196442881097566593344612847
1410             564823378678316527120190914564856692346034861045432664821339360726024914127
1411             372458700660631558817488152092096282925409171536436789259036001133053054882
1412             046652138414695194151160943305727036575959195309218611738193261179310511854
1413             807446237996274956735188575272489122793818301194912983367336244065664308602
1414             139494639522473719070217986094370277053921717629317675238467481846766940513
1415             200056812714526356082778577134275778960917363717872146844090122495343014654
1416             958537105079227968925892354201995611212902196086403441815981362977477130996
1417             051870721134999999837297804995105973173281609631859502445945534690830264252
1418             230825334468503526193118817101000313783875288658753320838142061717766914730
1419             359825349042875546873115956286388235378759375195778185778053217122680661300
1420             192787661119590921642019893809525720106548586327886593615338182796823030195
1421             EOF
1422              
1423             # Should we round up?
1424              
1425 257         455 my $round_up;
1426              
1427             # From the string above, we need to extract the number of digits we
1428             # want plus extra characters for the newlines.
1429              
1430 257         828 my $nchrs = $n + int($n / 75);
1431              
1432             # Extract the digits we want.
1433              
1434 257         735 my $digits = substr($all_digits, 0, $nchrs);
1435              
1436             # Find out whether we should round up or down. Rounding is easy, since
1437             # pi is trancendental. With directed rounding, it doesn't matter what
1438             # the following digits are. With rounding to nearest, we only have to
1439             # look at one extra digit.
1440              
1441 257 50       684 if ($rmode eq 'trunc') {
1442 0         0 $round_up = 0;
1443             } else {
1444 257         655 my $next_digit = substr($all_digits, $nchrs, 1);
1445 257 100       871 $round_up = $next_digit lt '5' ? 0 : 1;
1446             }
1447              
1448             # Remove the newlines.
1449              
1450 257         692 $digits =~ tr/0-9//cd;
1451              
1452             # Now do the rounding. We could easily make the regex substitution
1453             # handle all cases, but we avoid using the regex engine when it is
1454             # simple to avoid it.
1455              
1456 257 100       748 if ($round_up) {
1457 159         369 my $last_digit = substr($digits, -1, 1);
1458 159 100       453 if ($last_digit lt '9') {
1459 140         433 substr($digits, -1, 1) = ++$last_digit;
1460             } else {
1461 19         224 $digits =~ s{([0-8])(9+)$}
1462 19         148 { ($1 + 1) . ("0" x CORE::length($2)) }e;
1463             }
1464             }
1465              
1466             # Convert to an object.
1467              
1468 257 50       1324 $pi = bless {
1469             sign => '+',
1470             _m => $LIB -> _new($digits),
1471             _es => CORE::length($digits) > 1 ? '-' : '+',
1472             _e => $LIB -> _new($n - 1),
1473             }, $class;
1474              
1475             } else {
1476              
1477             # For large accuracy, the arctan formulas become very inefficient with
1478             # Math::BigFloat, so use Brent-Salamin (aka AGM or Gauss-Legendre).
1479              
1480             # Use a few more digits in the intermediate computations.
1481 0         0 $n += 8;
1482              
1483 0 0       0 $HALF = $class -> new($HALF) unless ref($HALF);
1484 0         0 my ($an, $bn, $tn, $pn)
1485             = ($class -> bone, $HALF -> copy() -> bsqrt($n),
1486             $HALF -> copy() -> bmul($HALF), $class -> bone);
1487 0         0 while ($pn < $n) {
1488 0         0 my $prev_an = $an -> copy();
1489 0         0 $an -> badd($bn) -> bmul($HALF, $n);
1490 0         0 $bn -> bmul($prev_an) -> bsqrt($n);
1491 0         0 $prev_an -> bsub($an);
1492 0         0 $tn -> bsub($pn * $prev_an * $prev_an);
1493 0         0 $pn -> badd($pn);
1494             }
1495 0         0 $an -> badd($bn);
1496 0         0 $an -> bmul($an, $n) -> bdiv(4 * $tn, $n);
1497              
1498 0         0 $an -> round(@r);
1499 0         0 $pi = $an;
1500             }
1501              
1502 257 100       849 if (defined $r[0]) {
    50          
1503 243         1042 $pi -> accuracy($r[0]);
1504             } elsif (defined $r[1]) {
1505 0         0 $pi -> precision($r[1]);
1506             }
1507              
1508 257 50 33     646 $pi -> _dng() if ($pi -> is_int() ||
      33        
1509             $pi -> is_inf() ||
1510             $pi -> is_nan());
1511              
1512 257         2171 %$self = %$pi;
1513 257         883 bless $self, ref($pi);
1514 257         2045 return $self;
1515             }
1516              
1517             sub copy {
1518 22644     22644 1 286200 my ($x, $class);
1519 22644 50       49102 if (ref($_[0])) { # $y = $x -> copy()
1520 22644         40618 $x = shift;
1521 22644         43004 $class = ref($x);
1522             } else { # $y = Math::BigInt -> copy($y)
1523 0         0 $class = shift;
1524 0         0 $x = shift;
1525             }
1526              
1527 22644 50       51999 carp "Rounding is not supported for ", (caller(0))[3], "()" if @_;
1528              
1529 22644         55154 my $copy = bless {}, $class;
1530              
1531 22644         67695 $copy->{sign} = $x->{sign};
1532 22644         57612 $copy->{_es} = $x->{_es};
1533 22644         80965 $copy->{_m} = $LIB->_copy($x->{_m});
1534 22644         71830 $copy->{_e} = $LIB->_copy($x->{_e});
1535              
1536 22644 100       68657 $copy->{accuracy} = $x->{accuracy} if exists $x->{accuracy};
1537 22644 100       68938 $copy->{precision} = $x->{precision} if exists $x->{precision};
1538              
1539 22644         83821 return $copy;
1540             }
1541              
1542             sub as_int {
1543 781 50   781 1 5116 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1544              
1545             # Temporarily disable upgrading and downgrading.
1546              
1547 781         11264 my $upg = Math::BigInt -> upgrade();
1548 781         2670 my $dng = Math::BigInt -> downgrade();
1549 781         2666 Math::BigInt -> upgrade(undef);
1550 781         2392 Math::BigInt -> downgrade(undef);
1551              
1552 781         1292 my $y;
1553 781 50       2421 if ($x -> isa("Math::BigInt")) {
1554 0         0 $y = $x -> copy();
1555             } else {
1556 781 100       2481 if ($x -> is_inf()) {
    100          
1557 12         79 $y = Math::BigInt -> binf($x -> sign());
1558             } elsif ($x -> is_nan()) {
1559 4         28 $y = Math::BigInt -> bnan();
1560             } else {
1561 765         2784 $y = Math::BigInt -> new($x -> copy() -> bint() -> bdstr());
1562             }
1563              
1564             # Copy the remaining instance variables.
1565              
1566 781         5356 ($y->{accuracy}, $y->{precision}) = ($x->{accuracy}, $x->{precision});
1567             }
1568              
1569 781         2674 $y -> round(@r);
1570              
1571             # Restore upgrading and downgrading.
1572              
1573 781         2693 Math::BigInt -> upgrade($upg);
1574 781         2381 Math::BigInt -> downgrade($dng);
1575              
1576 781         4331 return $y;
1577             }
1578              
1579             sub as_rat {
1580 2655 50   2655 1 9085 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1581              
1582             # Temporarily disable upgrading and downgrading.
1583              
1584 2655         18100 require Math::BigRat;
1585 2655         9135 my $upg = Math::BigRat -> upgrade();
1586 2655         6681 my $dng = Math::BigRat -> downgrade();
1587 2655         7480 Math::BigRat -> upgrade(undef);
1588 2655         7201 Math::BigRat -> downgrade(undef);
1589              
1590 2655         18689 my $y;
1591 2655 50       6796 if ($x -> isa("Math::BigRat")) {
1592 0         0 $y = $x -> copy();
1593             } else {
1594              
1595 2655 100       7533 if ($x -> is_inf()) {
    100          
1596 867         3324 $y = Math::BigRat -> binf($x -> sign());
1597             } elsif ($x -> is_nan()) {
1598 654         2646 $y = Math::BigRat -> bnan();
1599             } else {
1600 1134         3613 $y = Math::BigRat -> new($x -> bfstr());
1601             }
1602              
1603             # Copy the remaining instance variables.
1604              
1605 2655         10174 ($y->{accuracy}, $y->{precision}) = ($x->{accuracy}, $x->{precision});
1606             }
1607              
1608 2655         10038 $y -> round(@r);
1609              
1610             # Restore upgrading and downgrading.
1611              
1612 2655         8242 Math::BigRat -> upgrade($upg);
1613 2655         7209 Math::BigRat -> downgrade($dng);
1614              
1615 2655         8042 return $y;
1616             }
1617              
1618             sub as_float {
1619 46 50   46 1 214 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1620              
1621             # Disable upgrading and downgrading.
1622              
1623 46         585 require Math::BigFloat;
1624 46         221 my $upg = Math::BigFloat -> upgrade();
1625 46         236 my $dng = Math::BigFloat -> downgrade();
1626 46         206 Math::BigFloat -> upgrade(undef);
1627 46         577 Math::BigFloat -> downgrade(undef);
1628              
1629 46         116 my $y;
1630 46 50       151 if ($x -> isa("Math::BigFloat")) {
1631 46         216 $y = $x -> copy();
1632             } else {
1633 0 0       0 if ($x -> is_inf()) {
    0          
1634 0         0 $y = Math::BigFloat -> binf($x -> sign());
1635             } elsif ($x -> is_nan()) {
1636 0         0 $y = Math::BigFloat -> bnan();
1637             } else {
1638 0 0       0 if ($x -> isa("Math::BigRat")) {
1639 0 0       0 if ($x -> is_int()) {
1640 0         0 $y = Math::BigFloat -> new($x -> bdstr());
1641             } else {
1642 0         0 my ($num, $den) = $x -> fparts();
1643 0         0 my $str = $num -> as_float() -> bdiv($den, @r) -> bdstr();
1644 0         0 $y = Math::BigFloat -> new($str);
1645             }
1646             } else {
1647 0         0 $y = Math::BigFloat -> new($x -> bdstr());
1648             }
1649             }
1650              
1651             # Copy the remaining instance variables.
1652              
1653 0         0 ($y->{accuracy}, $y->{precision}) = ($x->{accuracy}, $x->{precision});
1654             }
1655              
1656 46         234 $y -> round(@r);
1657              
1658             # Restore upgrading and downgrading.
1659              
1660 46         177 Math::BigFloat -> upgrade($upg);
1661 46         153 Math::BigFloat -> downgrade($dng);
1662              
1663 46         135 return $y;
1664             }
1665              
1666             ###############################################################################
1667             # Boolean methods
1668             ###############################################################################
1669              
1670             sub is_zero {
1671             # return true if arg (BFLOAT or num_str) is zero
1672 110984 100   110984 1 261036 my (undef, $x) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
1673              
1674 110984 100       279708 return 0 if $x->{sign} ne '+';
1675 102279 100       321913 return 1 if $LIB->_is_zero($x->{_m});
1676 100427         364175 return 0;
1677             }
1678              
1679             sub is_one {
1680             # return true if arg (BFLOAT or num_str) is +1 or -1 if signis given
1681 3055 100   3055 1 11965 my (undef, $x, $sign) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
1682              
1683 3055 100       6352 if (defined($sign)) {
1684 1274 50 66     4759 croak 'is_one(): sign argument must be "+" or "-"'
1685             unless $sign eq '+' || $sign eq '-';
1686             } else {
1687 1781         3327 $sign = '+';
1688             }
1689              
1690 3055 100       9486 return 0 if $x->{sign} ne $sign;
1691 2245 100 100     7608 $LIB->_is_zero($x->{_e}) && $LIB->_is_one($x->{_m}) ? 1 : 0;
1692             }
1693              
1694             sub is_odd {
1695             # return true if arg (BFLOAT or num_str) is odd or false if even
1696 108 50   108 1 996 my (undef, $x) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
1697              
1698 108 100       332 return 0 unless $x -> is_finite();
1699 92 100 100     372 $LIB->_is_zero($x->{_e}) && $LIB->_is_odd($x->{_m}) ? 1 : 0;
1700             }
1701              
1702             sub is_even {
1703             # return true if arg (BINT or num_str) is even or false if odd
1704 72 50   72 1 1110 my (undef, $x) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
1705              
1706 72 100       217 return 0 unless $x -> is_finite();
1707             ($x->{_es} eq '+') && # 123.45 isn't
1708 60 100 100     488 ($LIB->_is_even($x->{_m})) ? 1 : 0; # but 1200 is
1709             }
1710              
1711             sub is_int {
1712             # return true if arg (BFLOAT or num_str) is an integer
1713 157351 50   157351 1 384686 my (undef, $x) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
1714              
1715 157351 100       415828 return 0 unless $x -> is_finite();
1716 157238 100       591032 return $x->{_es} eq '+' ? 1 : 0; # 1e-1 => no integer
1717             }
1718              
1719             ###############################################################################
1720             # Comparison methods
1721             ###############################################################################
1722              
1723             sub bcmp {
1724             # Compares 2 values. Returns one of undef, <0, =0, >0. (suitable for sort)
1725              
1726             # set up parameters
1727 4037 100 66 4037 1 26065 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
1728             ? (ref($_[0]), @_)
1729             : objectify(2, @_);
1730              
1731 4037 50       9186 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
1732              
1733             # Handle all 'nan' cases.
1734              
1735 4037 100 100     11147 return if $x -> is_nan() || $y -> is_nan();
1736              
1737             # Handle all '+inf' and '-inf' cases.
1738              
1739 3979 100 100     10693 return 0 if ($x -> is_inf("+") && $y -> is_inf("+") ||
      100        
      100        
1740             $x -> is_inf("-") && $y -> is_inf("-"));
1741 3971 100       10578 return +1 if $x -> is_inf("+"); # x = +inf and y < +inf
1742 3915 100       9501 return -1 if $x -> is_inf("-"); # x = -inf and y > -inf
1743 3855 50       9717 return -1 if $y -> is_inf("+"); # x < +inf and y = +inf
1744 3855 50       9598 return +1 if $y -> is_inf("-"); # x > -inf and y = -inf
1745              
1746             # Handle all cases with opposite signs.
1747              
1748 3855 100 100     20062 return +1 if $x->{sign} eq '+' && $y->{sign} eq '-'; # also does 0 <=> -y
1749 3403 100 100     12206 return -1 if $x->{sign} eq '-' && $y->{sign} eq '+'; # also does -x <=> 0
1750              
1751             # Handle all remaining zero cases.
1752              
1753 3097         8977 my $xz = $x -> is_zero();
1754 3097         6438 my $yz = $y -> is_zero();
1755 3097 100 100     8939 return 0 if $xz && $yz; # 0 <=> 0
1756 2963 100 66     7901 return -1 if $xz && $y->{sign} eq '+'; # 0 <=> +y
1757 2843 100 66     9232 return +1 if $yz && $x->{sign} eq '+'; # +x <=> 0
1758              
1759             # Both arguments are now finite, non-zero numbers with the same sign.
1760              
1761 2255         3740 my $cmp;
1762              
1763             # The next step is to compare the exponents, but since each mantissa is an
1764             # integer of arbitrary value, the exponents must be normalized by the
1765             # length of the mantissas before we can compare them.
1766              
1767 2255         8009 my $mxl = $LIB->_len($x->{_m});
1768 2255         6067 my $myl = $LIB->_len($y->{_m});
1769              
1770             # If the mantissas have the same length, there is no point in normalizing
1771             # the exponents by the length of the mantissas, so treat that as a special
1772             # case.
1773              
1774 2255 100       5697 if ($mxl == $myl) {
1775              
1776             # First handle the two cases where the exponents have different signs.
1777              
1778 1475 50 66     8971 if ($x->{_es} eq '+' && $y->{_es} eq '-') {
    100 100        
1779 0         0 $cmp = +1;
1780             } elsif ($x->{_es} eq '-' && $y->{_es} eq '+') {
1781 20         62 $cmp = -1;
1782             }
1783              
1784             # Then handle the case where the exponents have the same sign.
1785              
1786             else {
1787 1455         5196 $cmp = $LIB->_acmp($x->{_e}, $y->{_e});
1788 1455 100       4047 $cmp = -$cmp if $x->{_es} eq '-';
1789             }
1790              
1791             # Adjust for the sign, which is the same for x and y, and bail out if
1792             # we're done.
1793              
1794 1475 100       3933 $cmp = -$cmp if $x->{sign} eq '-'; # 124 > 123, but -124 < -123
1795 1475 100       3906 return $cmp if $cmp;
1796              
1797             }
1798              
1799             # We must normalize each exponent by the length of the corresponding
1800             # mantissa. Life is a lot easier if we first make both exponents
1801             # non-negative. We do this by adding the same positive value to both
1802             # exponent. This is safe, because when comparing the exponents, only the
1803             # relative difference is important.
1804              
1805 2179         4379 my $ex;
1806             my $ey;
1807              
1808 2179 100       5258 if ($x->{_es} eq '+') {
1809              
1810             # If the exponent of x is >= 0 and the exponent of y is >= 0, there is
1811             # no need to do anything special.
1812              
1813 1400 100       5898 if ($y->{_es} eq '+') {
1814 1367         4526 $ex = $LIB->_copy($x->{_e});
1815 1367         3476 $ey = $LIB->_copy($y->{_e});
1816             }
1817              
1818             # If the exponent of x is >= 0 and the exponent of y is < 0, add the
1819             # absolute value of the exponent of y to both.
1820              
1821             else {
1822 33         113 $ex = $LIB->_copy($x->{_e});
1823 33         121 $ex = $LIB->_add($ex, $y->{_e}); # ex + |ey|
1824 33         134 $ey = $LIB->_zero(); # -ex + |ey| = 0
1825             }
1826              
1827             } else {
1828              
1829             # If the exponent of x is < 0 and the exponent of y is >= 0, add the
1830             # absolute value of the exponent of x to both.
1831              
1832 779 100       2087 if ($y->{_es} eq '+') {
1833 49         205 $ex = $LIB->_zero(); # -ex + |ex| = 0
1834 49         734 $ey = $LIB->_copy($y->{_e});
1835 49         216 $ey = $LIB->_add($ey, $x->{_e}); # ey + |ex|
1836             }
1837              
1838             # If the exponent of x is < 0 and the exponent of y is < 0, add the
1839             # absolute values of both exponents to both exponents.
1840              
1841             else {
1842 730         2360 $ex = $LIB->_copy($y->{_e}); # -ex + |ey| + |ex| = |ey|
1843 730         2102 $ey = $LIB->_copy($x->{_e}); # -ey + |ex| + |ey| = |ex|
1844             }
1845              
1846             }
1847              
1848             # Now we can normalize the exponents by adding lengths of the mantissas.
1849              
1850 2179         7488 $ex = $LIB->_add($ex, $LIB->_new($mxl));
1851 2179         8336 $ey = $LIB->_add($ey, $LIB->_new($myl));
1852              
1853             # We're done if the exponents are different.
1854              
1855 2179         7175 $cmp = $LIB->_acmp($ex, $ey);
1856 2179 100       6126 $cmp = -$cmp if $x->{sign} eq '-'; # 124 > 123, but -124 < -123
1857 2179 100       8537 return $cmp if $cmp;
1858              
1859             # Compare the mantissas, but first normalize them by padding the shorter
1860             # mantissa with zeros (shift left) until it has the same length as the
1861             # longer mantissa.
1862              
1863 1529         3006 my $mx = $x->{_m};
1864 1529         2609 my $my = $y->{_m};
1865              
1866 1529 100       4634 if ($mxl > $myl) {
    100          
1867 49         189 $my = $LIB->_lsft($LIB->_copy($my), $LIB->_new($mxl - $myl), 10);
1868             } elsif ($mxl < $myl) {
1869 81         277 $mx = $LIB->_lsft($LIB->_copy($mx), $LIB->_new($myl - $mxl), 10);
1870             }
1871              
1872 1529         3916 $cmp = $LIB->_acmp($mx, $my);
1873 1529 100       4038 $cmp = -$cmp if $x->{sign} eq '-'; # 124 > 123, but -124 < -123
1874 1529         7007 return $cmp;
1875              
1876             }
1877              
1878             sub bacmp {
1879             # Compares 2 values, ignoring their signs.
1880             # Returns one of undef, <0, =0, >0. (suitable for sort)
1881              
1882             # set up parameters
1883 9028 50 33 9028 1 61087 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
1884             ? (ref($_[0]), @_)
1885             : objectify(2, @_);
1886              
1887 9028 50       22170 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
1888              
1889             # handle +-inf and NaN
1890 9028 100 100     68911 if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/) {
1891 92 100 100     320 return if ($x -> is_nan() || $y -> is_nan());
1892 64 100 100     184 return 0 if ($x -> is_inf() && $y -> is_inf());
1893 48 100 66     105 return 1 if ($x -> is_inf() && !$y -> is_inf());
1894 16         194 return -1;
1895             }
1896              
1897             # shortcut
1898 8936         24719 my $xz = $x -> is_zero();
1899 8936         20935 my $yz = $y -> is_zero();
1900 8936 100 100     23862 return 0 if $xz && $yz; # 0 <=> 0
1901 8932 100 66     24934 return -1 if $xz && !$yz; # 0 <=> +y
1902 8892 100 66     23877 return 1 if $yz && !$xz; # +x <=> 0
1903              
1904             # adjust so that exponents are equal
1905 8852         28228 my $lxm = $LIB->_len($x->{_m});
1906 8852         24374 my $lym = $LIB->_len($y->{_m});
1907 8852         18974 my ($xes, $yes) = (1, 1);
1908 8852 100       24849 $xes = -1 if $x->{_es} ne '+';
1909 8852 100       22828 $yes = -1 if $y->{_es} ne '+';
1910             # the numify somewhat limits our length, but makes it much faster
1911 8852         29074 my $lx = $lxm + $xes * $LIB->_num($x->{_e});
1912 8852         24917 my $ly = $lym + $yes * $LIB->_num($y->{_e});
1913 8852         17439 my $l = $lx - $ly;
1914 8852 100       32917 return $l <=> 0 if $l != 0;
1915              
1916             # lengths (corrected by exponent) are equal
1917             # so make mantissa equal-length by padding with zero (shift left)
1918 4033         7119 my $diff = $lxm - $lym;
1919 4033         7240 my $xm = $x->{_m}; # not yet copy it
1920 4033         7700 my $ym = $y->{_m};
1921 4033 100       13468 if ($diff > 0) {
    100          
1922 597         2277 $ym = $LIB->_copy($y->{_m});
1923 597         2252 $ym = $LIB->_lsft($ym, $LIB->_new($diff), 10);
1924             } elsif ($diff < 0) {
1925 309         1199 $xm = $LIB->_copy($x->{_m});
1926 309         1412 $xm = $LIB->_lsft($xm, $LIB->_new(-$diff), 10);
1927             }
1928 4033         14351 $LIB->_acmp($xm, $ym);
1929             }
1930              
1931             ###############################################################################
1932             # Arithmetic methods
1933             ###############################################################################
1934              
1935             sub bneg {
1936             # (BINT or num_str) return BINT
1937             # negate number or make a negated number from string
1938 1952 50   1952 1 9341 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1939              
1940             # Don't modify constant (read-only) objects.
1941              
1942 1952 50       6636 return $x if $x -> modify('bneg');
1943              
1944             # For +0 do not negate (to have always normalized +0).
1945             $x->{sign} =~ tr/+-/-+/
1946 1952 100 100     9444 unless $x->{sign} eq '+' && $LIB->_is_zero($x->{_m});
1947              
1948 1952         7516 $x -> round(@r);
1949 1952 100 100     4999 $x -> _dng() if ($x -> is_int() ||
      100        
1950             $x -> is_inf() ||
1951             $x -> is_nan());
1952 1952         11850 return $x;
1953             }
1954              
1955             sub bnorm {
1956             # bnorm() can't support rounding, because bround() and bfround() call
1957             # bnorm(), which would recurse indefinitely.
1958              
1959             # adjust m and e so that m is smallest possible
1960 78586 50   78586 1 245478 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1961              
1962 78586 50       174332 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
1963              
1964             # inf and nan
1965 78586 100       324087 if ($x->{sign} !~ /^[+-]$/) {
1966 2         29 $x -> round(@r);
1967 2         12 $x -> _dng();
1968 2         10 return $x;
1969             }
1970              
1971 78584         305368 my $zeros = $LIB->_zeros($x->{_m}); # correct for trailing zeros
1972 78584 100       171258 if ($zeros != 0) {
1973 33451         98103 my $z = $LIB->_new($zeros);
1974 33451         126661 $x->{_m} = $LIB->_rsft($x->{_m}, $z, 10);
1975 33451 100       88802 if ($x->{_es} eq '-') {
1976 31708 100       111304 if ($LIB->_acmp($x->{_e}, $z) >= 0) {
1977 31350         99733 $x->{_e} = $LIB->_sub($x->{_e}, $z);
1978 31350 100       136636 $x->{_es} = '+' if $LIB->_is_zero($x->{_e});
1979             } else {
1980 358         1372 $x->{_e} = $LIB->_sub($LIB->_copy($z), $x->{_e});
1981 358         1095 $x->{_es} = '+';
1982             }
1983             } else {
1984 1743         6978 $x->{_e} = $LIB->_add($x->{_e}, $z);
1985             }
1986             } else {
1987             # $x can only be 0Ey if there are no trailing zeros ('0' has 0 trailing
1988             # zeros). So, for something like 0Ey, set y to 0, and -0 => +0
1989 45133 100       153086 if ($LIB->_is_zero($x->{_m})) {
1990 423         1167 $x->{sign} = '+';
1991 423         949 $x->{_es} = '+';
1992 423         1364 $x->{_e} = $LIB->_zero();
1993             }
1994             }
1995              
1996             # Inf and NaN was handled above, so no need to check for this.
1997              
1998 78584 100       211932 $x -> _dng() if $x -> is_int();
1999 78584         411075 return $x;
2000             }
2001              
2002             sub binc {
2003             # increment arg by one
2004 5045 50   5045 1 17637 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2005              
2006             # Don't modify constant (read-only) objects.
2007              
2008 5045 50       16667 return $x if $x -> modify('binc');
2009              
2010             # Inf and NaN
2011              
2012 5045 100 100     14034 if ($x -> is_inf() || $x -> is_nan()) {
2013 14         66 $x -> round(@r);
2014 14         66 $x -> _dng();
2015 14         148 return $x
2016             }
2017              
2018             # Non-integer
2019              
2020 5031 100       13884 if ($x->{_es} eq '-') {
2021 468         2160 return $x -> badd($class -> bone(), @r);
2022             }
2023              
2024             # If the exponent is non-zero, convert the internal representation, so
2025             # that, e.g., 12e+3 becomes 12000e+0 and we can easily increment the
2026             # mantissa.
2027              
2028 4563 100       16982 if (!$LIB->_is_zero($x->{_e})) {
2029 404         1830 $x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10); # 1e2 => 100
2030 404         1946 $x->{_e} = $LIB->_zero(); # normalize
2031 404         1132 $x->{_es} = '+';
2032             # we know that the last digit of $x will be '1' or '9', depending on
2033             # the sign
2034             }
2035              
2036             # now $x->{_e} == 0
2037 4563 100       11455 if ($x->{sign} eq '+') {
    50          
2038 4547         15361 $x->{_m} = $LIB->_inc($x->{_m});
2039 4547         12025 return $x -> bnorm() -> bround(@r);
2040             } elsif ($x->{sign} eq '-') {
2041 16         78 $x->{_m} = $LIB->_dec($x->{_m});
2042 16 100       58 $x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # -1 +1 => -0 => +0
2043 16         67 return $x -> bnorm() -> bround(@r);
2044             }
2045              
2046 0 0 0     0 $x -> _dng() if ($x -> is_int() ||
      0        
2047             $x -> is_inf() ||
2048             $x -> is_nan());
2049 0         0 return $x;
2050             }
2051              
2052             sub bdec {
2053             # decrement arg by one
2054 174 50   174 1 1412 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2055              
2056             # Don't modify constant (read-only) objects.
2057              
2058 174 50       823 return $x if $x -> modify('bdec');
2059              
2060             # Inf and NaN
2061              
2062 174 100 100     615 if ($x -> is_inf() || $x -> is_nan()) {
2063 14         72 $x -> round(@r);
2064 14         67 $x -> _dng();
2065 14         181 return $x
2066             }
2067              
2068             # Non-integer
2069              
2070 160 100       555 if ($x->{_es} eq '-') {
2071 120         481 return $x -> badd($class -> bone('-'), @r);
2072             }
2073              
2074             # If the exponent is non-zero, convert the internal representation, so
2075             # that, e.g., 12e+3 becomes 12000e+0 and we can easily increment the
2076             # mantissa.
2077              
2078 40 100       220 if (!$LIB->_is_zero($x->{_e})) {
2079 8         43 $x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10); # 1e2 => 100
2080 8         41 $x->{_e} = $LIB->_zero(); # normalize
2081 8         22 $x->{_es} = '+';
2082             }
2083              
2084             # now $x->{_e} == 0
2085 40         152 my $zero = $x -> is_zero();
2086 40 100 100     218 if (($x->{sign} eq '-') || $zero) { # x <= 0
    50          
2087 21         108 $x->{_m} = $LIB->_inc($x->{_m});
2088 21 100       67 $x->{sign} = '-' if $zero; # 0 => 1 => -1
2089 21 50       65 $x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # -1 +1 => -0 => +0
2090 21         438 $x -> bnorm();
2091             }
2092             elsif ($x->{sign} eq '+') { # x > 0
2093 19         97 $x->{_m} = $LIB->_dec($x->{_m});
2094 19         73 $x -> bnorm();
2095             }
2096              
2097 40         177 $x -> round(@r);
2098 40 0 33     109 $x -> _dng() if ($x -> is_int() ||
      33        
2099             $x -> is_inf() ||
2100             $x -> is_nan());
2101 40         482 return $x;
2102             }
2103              
2104             sub badd {
2105             # set up parameters
2106 14129 100 100 14129 1 80641 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2107             ? (ref($_[0]), @_)
2108             : objectify(2, @_);
2109              
2110             # Don't modify constant (read-only) objects.
2111              
2112 14129 50       46632 return $x if $x -> modify('badd');
2113              
2114 14129 100 100     37381 unless ($x -> is_finite() && $y -> is_finite()) {
2115              
2116 120 100 100     434 return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
2117              
2118 62 100       252 return $x -> is_inf("+") ? ($y -> is_inf("-") ? $x -> bnan(@r)
    100          
    100          
    100          
    100          
2119             : $x -> binf("+", @r))
2120             : $x -> is_inf("-") ? ($y -> is_inf("+") ? $x -> bnan(@r)
2121             : $x -> binf("-", @r))
2122             : ($y -> is_inf("+") ? $x -> binf("+", @r)
2123             : $x -> binf("-", @r));
2124             }
2125              
2126 14009 100       47225 return $x -> _upg() -> badd($y, @r) if $class -> upgrade();
2127              
2128 14008         29572 $r[3] = $y; # no push!
2129              
2130             # for speed: no add for $x + 0
2131 14008 100       35227 if ($y -> is_zero()) {
    100          
2132 56         275 $x -> round(@r);
2133             }
2134              
2135             # for speed: no add for 0 + $y
2136             elsif ($x -> is_zero()) {
2137             # make copy, clobbering up x (modify in place!)
2138 104         510 $x->{_e} = $LIB->_copy($y->{_e});
2139 104         357 $x->{_es} = $y->{_es};
2140 104         418 $x->{_m} = $LIB->_copy($y->{_m});
2141 104   33     514 $x->{sign} = $y->{sign} || $nan;
2142 104         619 $x -> round(@r);
2143             }
2144              
2145             # both $x and $y are non-zero
2146             else {
2147              
2148             # take lower of the two e's and adapt m1 to it to match m2
2149 13848         27505 my $e = $y->{_e};
2150 13848 50       32082 $e = $LIB->_zero() if !defined $e; # if no BFLOAT?
2151 13848         41692 $e = $LIB->_copy($e); # make copy (didn't do it yet)
2152              
2153 13848         23521 my $es;
2154              
2155 13848   50     72979 ($e, $es) = $LIB -> _ssub($e, $y->{_es} || '+', $x->{_e}, $x->{_es});
2156              
2157 13848         47668 my $add = $LIB->_copy($y->{_m});
2158              
2159 13848 100       44282 if ($es eq '-') { # < 0
    100          
2160 8035         28651 $x->{_m} = $LIB->_lsft($x->{_m}, $e, 10);
2161 8035         36418 ($x->{_e}, $x->{_es}) = $LIB -> _sadd($x->{_e}, $x->{_es}, $e, $es);
2162             } elsif (!$LIB->_is_zero($e)) { # > 0
2163 821         3028 $add = $LIB->_lsft($add, $e, 10);
2164             }
2165              
2166             # else: both e are the same, so just leave them
2167              
2168 13848 100       42102 if ($x->{sign} eq $y->{sign}) {
2169 12078         36013 $x->{_m} = $LIB->_add($x->{_m}, $add);
2170             } else {
2171             ($x->{_m}, $x->{sign}) =
2172 1770         6491 $LIB -> _sadd($x->{_m}, $x->{sign}, $add, $y->{sign});
2173             }
2174              
2175             # delete trailing zeros, then round
2176 13848         44790 $x -> bnorm() -> round(@r);
2177             }
2178              
2179 14008 100 66     40370 $x -> _dng() if ($x -> is_int() ||
      100        
2180             $x -> is_inf() ||
2181             $x -> is_nan());
2182 14008         79588 return $x;
2183             }
2184              
2185             sub bsub {
2186             # set up parameters
2187 1528 100 100 1528 1 12810 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2188             ? (ref($_[0]), @_)
2189             : objectify(2, @_);
2190              
2191             # Don't modify constant (read-only) objects.
2192              
2193 1528 50       5604 return $x if $x -> modify('bsub');
2194              
2195 1528         3339 $r[3] = $y; # no push!
2196              
2197 1528 100 100     4328 unless ($x -> is_finite() && $y -> is_finite()) {
2198              
2199 120 100 100     483 return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
2200              
2201 62 100       213 return $x -> is_inf("+") ? ($y -> is_inf("+") ? $x -> bnan(@r)
    100          
    100          
    100          
    100          
2202             : $x -> binf("+", @r))
2203             : $x -> is_inf("-") ? ($y -> is_inf("-") ? $x -> bnan(@r)
2204             : $x -> binf("-", @r))
2205             : ($y -> is_inf("+") ? $x -> binf("-", @r)
2206             : $x -> binf("+", @r));
2207             }
2208              
2209 1408         4435 $x -> badd($y -> copy() -> bneg(), @r);
2210 1408         11348 return $x;
2211             }
2212              
2213             sub bmul {
2214             # multiply two numbers
2215              
2216             # set up parameters
2217 20716 100 100 20716 1 113403 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2218             ? (ref($_[0]), @_)
2219             : objectify(2, @_);
2220              
2221             # Don't modify constant (read-only) objects.
2222              
2223 20716 50       72240 return $x if $x -> modify('bmul');
2224              
2225 20716 100 100     54310 return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
2226              
2227             # inf handling
2228 20663 100 100     88893 if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/)) {
2229 85 100 100     400 return $x -> bnan(@r) if $x -> is_zero() || $y -> is_zero();
2230             # result will always be +-inf:
2231             # +inf * +/+inf => +inf, -inf * -/-inf => +inf
2232             # +inf * -/-inf => -inf, -inf * +/+inf => -inf
2233 73 100 100     565 return $x -> binf(@r) if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
2234 50 100 100     364 return $x -> binf(@r) if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
2235 36         115 return $x -> binf('-', @r);
2236             }
2237              
2238 20578 100       67423 return $x -> _upg() -> bmul($y, @r) if $class -> upgrade();
2239              
2240             # aEb * cEd = (a*c)E(b+d)
2241 20577         86593 $x->{_m} = $LIB->_mul($x->{_m}, $y->{_m});
2242             ($x->{_e}, $x->{_es})
2243 20577         96810 = $LIB -> _sadd($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
2244              
2245 20577         44292 $r[3] = $y; # no push!
2246              
2247             # adjust sign:
2248 20577 100       60543 $x->{sign} = $x->{sign} ne $y->{sign} ? '-' : '+';
2249 20577         57633 $x -> bnorm -> round(@r);
2250              
2251 20577 100 66     48273 $x -> _dng() if ($x -> is_int() ||
      100        
2252             $x -> is_inf() ||
2253             $x -> is_nan());
2254 20577         93613 return $x;
2255             }
2256              
2257             *bdiv = \&bfdiv;
2258             *bmod = \&bfmod;
2259              
2260             sub bfdiv {
2261             # This does floored division (or floor division) where the quotient is
2262             # rounded towards minus infinity.
2263             #
2264             # ($q, $r) = $x -> btdiv($y) returns $q and $r so that $q is floor($x / $y)
2265             # and $q * $y + $r = $x.
2266              
2267             # Set up parameters.
2268 9639 100 100 9639 1 73563 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2269             ? (ref($_[0]), @_)
2270             : objectify(2, @_);
2271              
2272             ###########################################################################
2273             # Code for all classes that share the common interface.
2274             ###########################################################################
2275              
2276             # Don't modify constant (read-only) objects.
2277              
2278 9639 50       35182 return $x if $x -> modify('bfdiv');
2279              
2280 9639         19297 my $wantarray = wantarray; # call only once
2281              
2282             # At least one argument is NaN. This is handled the same way as in
2283             # Math::BigInt -> bdiv(). See the comment in the code for Math::BigInt ->
2284             # bdiv() for further details.
2285              
2286 9639 100 100     28275 if ($x -> is_nan() || $y -> is_nan()) {
2287 68 100       383 return $wantarray ? ($x -> bnan(@r), $class -> bnan(@r))
2288             : $x -> bnan(@r);
2289             }
2290              
2291             # Divide by zero and modulo zero. This is handled the same way as in
2292             # Math::BigInt -> bdiv(). See the comment in the code for Math::BigInt ->
2293             # bdiv() for further details.
2294              
2295 9571 100       26061 if ($y -> is_zero()) {
2296 52         122 my $rem;
2297 52 100       229 if ($wantarray) {
2298 16         87 $rem = $x -> copy() -> round(@r);
2299 16 100       63 $rem -> _dng() if $rem -> is_int();
2300             }
2301 52 100       151 if ($x -> is_zero()) {
2302 18         96 $x -> bnan(@r);
2303             } else {
2304 34         185 $x -> binf($x->{sign}, @r);
2305             }
2306 48 100       572 return $wantarray ? ($x, $rem) : $x;
2307             }
2308              
2309             # Numerator (dividend) is +/-inf. This is handled the same way as in
2310             # Math::BigInt -> bdiv(). See the comment in the code for Math::BigInt ->
2311             # bdiv() for further details.
2312              
2313 9519 100       27858 if ($x -> is_inf()) {
2314 40         86 my $rem;
2315 40 100       210 $rem = $class -> bnan(@r) if $wantarray;
2316 40 100       159 if ($y -> is_inf()) {
2317 16         76 $x -> bnan(@r);
2318             } else {
2319 24 100       120 my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
2320 24         106 $x -> binf($sign, @r);
2321             }
2322 40 100       320 return $wantarray ? ($x, $rem) : $x;
2323             }
2324              
2325             # Denominator (divisor) is +/-inf. This is handled the same way as in
2326             # Math::BigInt -> bdiv(), with one exception: In scalar context,
2327             # Math::BigFloat does true division (although rounded), not floored
2328             # division (F-division), so a finite number divided by +/-inf is always
2329             # zero. See the comment in the code for Math::BigInt -> bdiv() for further
2330             # details.
2331              
2332 9479 100       22492 if ($y -> is_inf()) {
2333 40         91 my $rem;
2334 40 100       142 if ($wantarray) {
2335 16 100 100     52 if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
2336 12         65 $rem = $x -> copy() -> round(@r);
2337 12 50       43 $rem -> _dng() if $rem -> is_int();
2338 12         82 $x -> bzero(@r);
2339             } else {
2340 4         27 $rem = $class -> binf($y -> {sign}, @r);
2341 4         32 $x -> bone('-', @r);
2342             }
2343             } else {
2344 24         126 $x -> bzero(@r);
2345             }
2346 40 100       363 return $wantarray ? ($x, $rem) : $x;
2347             }
2348              
2349             # At this point, both the numerator and denominator are finite, non-zero
2350             # numbers.
2351              
2352             # we need to limit the accuracy to protect against overflow
2353 9439         16818 my $fallback = 0;
2354 9439         16480 my (@params, $scale);
2355 9439         51118 ($x, @params) = $x->_find_round_parameters($r[0], $r[1], $r[2], $y);
2356              
2357 9439 50       41060 if ($x -> is_nan()) { # error in _find_round_parameters?
2358 0         0 $x -> round(@r);
2359 0 0       0 return $wantarray ? ($x, $class -> bnan(@r)) : $x;
2360             }
2361              
2362             # no rounding at all, so must use fallback
2363 9439 100       22314 if (scalar @params == 0) {
2364             # simulate old behaviour
2365 594         2388 $params[0] = $class -> div_scale(); # and round to it as accuracy
2366 594         1177 $scale = $params[0]+4; # at least four more for proper round
2367 594         1266 $params[2] = $r[2]; # round mode by caller or undef
2368 594         1114 $fallback = 1; # to clear a/p afterwards
2369             } else {
2370             # the 4 below is empirical, and there might be cases where it is not
2371             # enough...
2372 8845   66     25058 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
2373             }
2374              
2375             # Temporarily disable downgrading
2376              
2377 9439         33076 my $dng = Math::BigFloat -> downgrade();
2378 9439         28925 Math::BigFloat -> downgrade(undef);
2379              
2380 9439         19160 my $rem;
2381 9439 100       22693 $rem = $class -> bzero() if $wantarray;
2382              
2383 9439 50       29417 $y = $class -> new($y) unless $y -> isa('Math::BigFloat');
2384              
2385 9439         48632 my $lx = $LIB -> _len($x->{_m});
2386 9439         28732 my $ly = $LIB -> _len($y->{_m});
2387 9439 100       23914 $scale = $lx if $lx > $scale;
2388 9439 100       20733 $scale = $ly if $ly > $scale;
2389 9439         16638 my $diff = $ly - $lx;
2390 9439 100       21114 $scale += $diff if $diff > 0; # if lx << ly, but not if ly << lx!
2391              
2392             # Are both operands the same object, i.e., like $x -> bdiv($x)? If so,
2393             # flipping the sign of $y also flips the sign of $x.
2394              
2395 9439         19916 my $xsign = $x -> {sign};
2396 9439         17417 my $ysign = $y -> {sign};
2397              
2398 9439         27898 $y -> {sign} =~ tr/+-/-+/; # Flip the sign of $y, and see ...
2399 9439         21631 my $same = $xsign ne $x -> {sign}; # ... if that changed the sign of $x.
2400 9439         18735 $y -> {sign} = $ysign; # Re-insert the original sign.
2401              
2402 9439 100       21797 if ($same) { # $x -> bdiv($x)
2403 8         33 $x -> bone();
2404             } else {
2405             # make copy of $x in case of list context for later remainder
2406             # calculation
2407 9431 100       20825 $rem = $x -> copy() if $wantarray;
2408              
2409 9431 100       27571 $x->{sign} = $x->{sign} ne $y->{sign} ? '-' : '+';
2410              
2411             # promote Math::BigInt and its subclasses (except when already a
2412             # Math::BigFloat)
2413 9431 50       21697 $y = $class -> new($y) unless $y -> isa('Math::BigFloat');
2414              
2415             # calculate the result to $scale digits and then round it
2416             # (a * 10 ** b) / (c * 10 ** d) => (a/c) * 10 ** (b-d)
2417 9431         37887 $x->{_m} = $LIB->_lsft($x->{_m}, $LIB->_new($scale), 10); # scale up
2418 9431         48236 $x->{_m} = $LIB->_div($x->{_m}, $y->{_m}); # divide
2419              
2420             # correct exponent of $x
2421             ($x->{_e}, $x->{_es})
2422 9431         57410 = $LIB -> _ssub($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
2423              
2424             # correct for 10**scale
2425             ($x->{_e}, $x->{_es})
2426 9431         38960 = $LIB -> _ssub($x->{_e}, $x->{_es}, $LIB->_new($scale), '+');
2427              
2428 9431         39981 $x -> bnorm(); # remove trailing zeros
2429             }
2430              
2431             # shortcut to not run through _find_round_parameters again
2432 9439 100       23046 if (defined $params[0]) {
2433 9406         19672 $x->{accuracy} = undef; # clear before round
2434 9406         34051 $x -> bround($params[0], $params[2]); # then round accordingly
2435             } else {
2436 33         138 $x->{precision} = undef; # clear before round
2437 33         145 $x -> bfround($params[1], $params[2]); # then round accordingly
2438             }
2439 9439 100       25373 if ($fallback) {
2440             # clear a/p after round, since user did not request it
2441 594         1446 $x->{accuracy} = undef;
2442 594         1665 $x->{precision} = undef;
2443             }
2444              
2445             # Restore downgrading
2446              
2447 9439         41260 Math::BigFloat -> downgrade($dng);
2448              
2449 9439 100       22733 if ($wantarray) {
2450 47         242 $x -> bfloor();
2451 47         312 $rem -> bfmod($y, @params); # copy already done
2452 47 50       137 if ($fallback) {
2453             # clear a/p after round, since user did not request it
2454 47         96 $rem->{accuracy} = undef;
2455 47         111 $rem->{precision} = undef;
2456             }
2457 47 50       123 $x -> _dng() if $x -> is_int();
2458 47 100       102 $rem -> _dng() if $rem -> is_int();
2459 47         328 return $x, $rem;
2460             }
2461              
2462 9392 100       21271 $x -> _dng() if $x -> is_int();
2463 9392         43799 $x; # rounding already done above
2464             }
2465              
2466             sub bfmod {
2467             # (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return
2468             # remainder
2469              
2470             # set up parameters
2471 813 100 100 813 1 11073 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2472             ? (ref($_[0]), @_)
2473             : objectify(2, @_);
2474              
2475             # Don't modify constant (read-only) objects.
2476              
2477 813 50       3235 return $x if $x -> modify('bfmod');
2478              
2479             # At least one argument is NaN. This is handled the same way as in
2480             # Math::BigInt -> bfmod().
2481              
2482 813 100 100     2867 return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
2483              
2484             # Modulo zero. This is handled the same way as in Math::BigInt -> bfmod().
2485              
2486 777 100       2371 if ($y -> is_zero()) {
2487 40         165 return $x -> round(@r);
2488             }
2489              
2490             # Numerator (dividend) is +/-inf. This is handled the same way as in
2491             # Math::BigInt -> bfmod().
2492              
2493 737 100       2200 if ($x -> is_inf()) {
2494 48         188 return $x -> bnan(@r);
2495             }
2496              
2497             # Denominator (divisor) is +/-inf. This is handled the same way as in
2498             # Math::BigInt -> bfmod().
2499              
2500 689 100       1687 if ($y -> is_inf()) {
2501 40 100 100     110 if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
2502 28         97 return $x -> round(@r);
2503             } else {
2504 12         108 return $x -> binf($y -> sign(), @r);
2505             }
2506             }
2507              
2508             # Modulo is zero if $x is zero or if $x is an integer and $y is +/-1.
2509              
2510             return $x -> bzero(@r) if $x -> is_zero()
2511             || ($x -> is_int() &&
2512             # check that $y == +1 or $y == -1:
2513 649 100 100     1529 ($LIB->_is_zero($y->{_e}) && $LIB->_is_one($y->{_m})));
      100        
      100        
2514              
2515             # Numerator (dividend) and denominator (divisor) are identical. Return
2516             # zero.
2517              
2518 537         1826 my $cmp = $x -> bacmp($y); # $x <=> $y
2519 537 100       1371 if ($cmp == 0) { # $x == $y => result 0
2520 24         313 return $x -> bzero(@r);
2521             }
2522              
2523             # Compare the exponents of $x and $y.
2524              
2525 513         2787 my $ecmp = $LIB->_scmp($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
2526              
2527 513         1065 my $ym = $y->{_m}; # mantissa of y, scaled if necessary
2528              
2529 513 100       1558 if ($ecmp > 0) {
    100          
2530              
2531             # $x has a larger exponent than $y, so shift the mantissa of $x by the
2532             # difference between the exponents of $x and $y.
2533             #
2534             # 123e+2 % 456e+1 => 1230 % 456 (+2 - +1 = 1)
2535             # 123e+2 % 456e-1 => 123000 % 456 (+2 - -1 = 3)
2536             # 456e-1 % 123e-3 => 12300 % 456 (-1 - -3 = 2)
2537              
2538             # get the difference between exponents; $ds is always "+" here
2539             my ($de, $ds) = $LIB->_ssub($LIB->_copy($x->{_e}), $x->{_es},
2540 176         734 $y->{_e}, $y->{_es});
2541              
2542             # adjust the mantissa of x by the difference between exponents
2543 176         842 $x->{_m} = $LIB->_lsft($x->{_m}, $de, 10);
2544              
2545             # compute the modulus
2546 176         898 $x->{_m} = $LIB->_mod($x->{_m}, $ym);
2547              
2548             # adjust the exponent of x to correct for the ajustment of the mantissa
2549 176         752 ($x->{_e}, $x->{_es}) = $LIB->_ssub($x->{_e}, $x->{_es}, $de, $ds);
2550              
2551             } elsif ($ecmp < 0) {
2552              
2553             # $x has a smaller exponent than $y, so shift the mantissa of $y by the
2554             # difference between the exponents of $x and $y.
2555             #
2556             # 123456e+1 % 78e+2 => 123456 % 780 (+2 - +1 = 1)
2557             # 123456e-2 % 78e+1 => 123456 % 78000 (+1 - -2 = 3)
2558              
2559             # get the difference between exponents; $ds is always "+" here
2560             my ($de, $ds) = $LIB->_ssub($LIB->_copy($y->{_e}), $y->{_es},
2561 79         332 $x->{_e}, $x->{_es});
2562              
2563             # adjust the mantissa of y by the difference between exponents
2564 79         358 $ym = $LIB->_lsft($LIB->_copy($ym), $de, 10);
2565              
2566             # compute the modulus
2567 79         370 $x->{_m} = $LIB->_mod($x->{_m}, $ym);
2568              
2569             } else {
2570              
2571             # $x has the same exponent as $y, so compute the modulus directly
2572              
2573             # compute the modulus
2574 258         935 $x->{_m} = $LIB->_mod($x->{_m}, $ym);
2575             }
2576              
2577 513 100       1671 if ($LIB->_is_zero($x->{_m})) {
2578 100         253 $x->{sign} = '+';
2579             } else {
2580             # adjust for floored division/modulus
2581             $x->{_m} = $LIB->_sub($ym, $x->{_m}, 1)
2582 413 100       1416 if $x->{sign} ne $y->{sign};
2583 413         943 $x->{sign} = $y->{sign};
2584             }
2585              
2586 513         1895 $x -> bnorm();
2587 513         4471 $x -> round($r[0], $r[1], $r[2], $y);
2588 513 100       1991 $x -> _dng() if $x -> is_int();
2589 513         5220 return $x;
2590             }
2591              
2592             sub btdiv {
2593             # This does truncated division, where the quotient is truncted, i.e.,
2594             # rounded towards zero.
2595             #
2596             # ($q, $r) = $x -> btdiv($y) returns $q and $r so that $q is int($x / $y)
2597             # and $q * $y + $r = $x.
2598              
2599             # Set up parameters
2600 0 0 0 0 1 0 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2601             ? (ref($_[0]), @_)
2602             : objectify(2, @_);
2603              
2604             ###########################################################################
2605             # Code for all classes that share the common interface.
2606             ###########################################################################
2607              
2608             # Don't modify constant (read-only) objects.
2609              
2610 0 0       0 return $x if $x -> modify('btdiv');
2611              
2612 0         0 my $wantarray = wantarray; # call only once
2613              
2614             # At least one argument is NaN. Return NaN for both quotient and the
2615             # modulo/remainder.
2616              
2617 0 0 0     0 if ($x -> is_nan() || $y -> is_nan()) {
2618 0 0       0 return $wantarray ? ($x -> bnan(@r), $class -> bnan(@r))
2619             : $x -> bnan(@r);
2620             }
2621              
2622             # Divide by zero and modulo zero.
2623             #
2624             # Division: Use the common convention that x / 0 is inf with the same sign
2625             # as x, except when x = 0, where we return NaN. This is also what earlier
2626             # versions did.
2627             #
2628             # Modulo: In modular arithmetic, the congruence relation z = x (mod y)
2629             # means that there is some integer k such that z - x = k y. If y = 0, we
2630             # get z - x = 0 or z = x. This is also what earlier versions did, except
2631             # that 0 % 0 returned NaN.
2632             #
2633             # inf / 0 = inf inf % 0 = inf
2634             # 5 / 0 = inf 5 % 0 = 5
2635             # 0 / 0 = NaN 0 % 0 = 0
2636             # -5 / 0 = -inf -5 % 0 = -5
2637             # -inf / 0 = -inf -inf % 0 = -inf
2638              
2639 0 0       0 if ($y -> is_zero()) {
2640 0         0 my $rem;
2641 0 0       0 if ($wantarray) {
2642 0         0 $rem = $x -> copy(@r);
2643             }
2644 0 0       0 if ($x -> is_zero()) {
2645 0         0 $x -> bnan(@r);
2646             } else {
2647 0         0 $x -> binf($x -> {sign}, @r);
2648             }
2649 0 0       0 return $wantarray ? ($x, $rem) : $x;
2650             }
2651              
2652             # Numerator (dividend) is +/-inf, and denominator is finite and non-zero.
2653             # The divide by zero cases are covered above. In all of the cases listed
2654             # below we return the same as core Perl.
2655             #
2656             # inf / -inf = NaN inf % -inf = NaN
2657             # inf / -5 = -inf inf % -5 = NaN
2658             # inf / 5 = inf inf % 5 = NaN
2659             # inf / inf = NaN inf % inf = NaN
2660             #
2661             # -inf / -inf = NaN -inf % -inf = NaN
2662             # -inf / -5 = inf -inf % -5 = NaN
2663             # -inf / 5 = -inf -inf % 5 = NaN
2664             # -inf / inf = NaN -inf % inf = NaN
2665              
2666 0 0       0 if ($x -> is_inf()) {
2667 0         0 my $rem;
2668 0 0       0 $rem = $class -> bnan(@r) if $wantarray;
2669 0 0       0 if ($y -> is_inf()) {
2670 0         0 $x -> bnan(@r);
2671             } else {
2672 0 0       0 my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
2673 0         0 $x -> binf($sign,@r );
2674             }
2675 0 0       0 return $wantarray ? ($x, $rem) : $x;
2676             }
2677              
2678             # Denominator (divisor) is +/-inf. The cases when the numerator is +/-inf
2679             # are covered above. In the modulo cases (in the right column) we return
2680             # the same as core Perl, which does floored division, so for consistency we
2681             # also do floored division in the division cases (in the left column).
2682             #
2683             # -5 / inf = 0 -5 % inf = -5
2684             # 0 / inf = 0 0 % inf = 0
2685             # 5 / inf = 0 5 % inf = 5
2686             #
2687             # -5 / -inf = 0 -5 % -inf = -5
2688             # 0 / -inf = 0 0 % -inf = 0
2689             # 5 / -inf = 0 5 % -inf = 5
2690              
2691 0 0       0 if ($y -> is_inf()) {
2692 0         0 my $rem;
2693 0 0       0 if ($wantarray) {
2694 0         0 $rem = $x -> copy() -> round(@r);
2695 0 0       0 $rem -> _dng() if $rem -> is_int();
2696             }
2697 0         0 $x -> bzero(@r);
2698 0 0       0 return $wantarray ? ($x, $rem) : $x;
2699             }
2700              
2701             # At this point, both the numerator and denominator are finite, non-zero
2702             # numbers.
2703              
2704             # we need to limit the accuracy to protect against overflow
2705 0         0 my $fallback = 0;
2706 0         0 my (@params, $scale);
2707 0         0 ($x, @params) = $x->_find_round_parameters($r[0], $r[1], $r[2], $y);
2708              
2709 0 0       0 if ($x -> is_nan()) { # error in _find_round_parameters?
2710 0         0 $x -> round(@r);
2711 0 0       0 return $wantarray ? ($x, $class -> bnan(@r)) : $x;
2712             }
2713              
2714             # no rounding at all, so must use fallback
2715 0 0       0 if (scalar @params == 0) {
2716             # simulate old behaviour
2717 0         0 $params[0] = $class -> div_scale(); # and round to it as accuracy
2718 0         0 $scale = $params[0]+4; # at least four more for proper round
2719 0         0 $params[2] = $r[2]; # round mode by caller or undef
2720 0         0 $fallback = 1; # to clear a/p afterwards
2721             } else {
2722             # the 4 below is empirical, and there might be cases where it is not
2723             # enough...
2724 0   0     0 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
2725             }
2726              
2727             # Temporarily disable downgrading
2728              
2729 0         0 my $dng = Math::BigFloat -> downgrade();
2730 0         0 Math::BigFloat -> downgrade(undef);
2731              
2732 0         0 my $rem;
2733 0 0       0 $rem = $class -> bzero() if $wantarray;
2734              
2735 0 0       0 $y = $class -> new($y) unless $y -> isa('Math::BigFloat');
2736              
2737 0         0 my $lx = $LIB -> _len($x->{_m});
2738 0         0 my $ly = $LIB -> _len($y->{_m});
2739 0 0       0 $scale = $lx if $lx > $scale;
2740 0 0       0 $scale = $ly if $ly > $scale;
2741 0         0 my $diff = $ly - $lx;
2742 0 0       0 $scale += $diff if $diff > 0; # if lx << ly, but not if ly << lx!
2743              
2744             # Are both operands the same object, i.e., like $x -> bdiv($x)? If so,
2745             # flipping the sign of $y also flips the sign of $x.
2746              
2747 0         0 my $xsign = $x -> {sign};
2748 0         0 my $ysign = $y -> {sign};
2749              
2750 0         0 $y -> {sign} =~ tr/+-/-+/; # Flip the sign of $y, and see ...
2751 0         0 my $same = $xsign ne $x -> {sign}; # ... if that changed the sign of $x.
2752 0         0 $y -> {sign} = $ysign; # Re-insert the original sign.
2753              
2754 0 0       0 if ($same) { # $x -> bdiv($x)
2755 0         0 $x -> bone();
2756             } else {
2757             # make copy of $x in case of list context for later remainder
2758             # calculation
2759 0 0       0 $rem = $x -> copy() if $wantarray;
2760              
2761 0 0       0 $x->{sign} = $x->{sign} ne $y->{sign} ? '-' : '+';
2762              
2763             # promote Math::BigInt and its subclasses (except when already a
2764             # Math::BigFloat)
2765 0 0       0 $y = $class -> new($y) unless $y -> isa('Math::BigFloat');
2766              
2767             # calculate the result to $scale digits and then round it
2768             # (a * 10 ** b) / (c * 10 ** d) => (a/c) * 10 ** (b-d)
2769 0         0 $x->{_m} = $LIB->_lsft($x->{_m}, $LIB->_new($scale), 10); # scale up
2770 0         0 $x->{_m} = $LIB->_div($x->{_m}, $y->{_m}); # divide
2771              
2772             # correct exponent of $x
2773             ($x->{_e}, $x->{_es})
2774 0         0 = $LIB -> _ssub($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
2775              
2776             # correct for 10**scale
2777             ($x->{_e}, $x->{_es})
2778 0         0 = $LIB -> _ssub($x->{_e}, $x->{_es}, $LIB->_new($scale), '+');
2779              
2780 0         0 $x -> bnorm(); # remove trailing zeros in mantissa
2781             }
2782              
2783             # shortcut to not run through _find_round_parameters again
2784 0 0       0 if (defined $params[0]) {
2785 0         0 $x->{accuracy} = undef; # clear before round
2786 0         0 $x -> bround($params[0], $params[2]); # then round accordingly
2787             } else {
2788 0         0 $x->{precision} = undef; # clear before round
2789 0         0 $x -> bfround($params[1], $params[2]); # then round accordingly
2790             }
2791 0 0       0 if ($fallback) {
2792             # clear a/p after round, since user did not request it
2793 0         0 $x->{accuracy} = undef;
2794 0         0 $x->{precision} = undef;
2795             }
2796              
2797             # Restore downgrading
2798              
2799 0         0 Math::BigFloat -> downgrade($dng);
2800              
2801 0 0       0 if ($wantarray) {
2802 0         0 $x -> bint();
2803 0         0 $rem -> btmod($y, @params); # copy already done
2804              
2805 0 0       0 if ($fallback) {
2806             # clear a/p after round, since user did not request it
2807 0         0 $rem->{accuracy} = undef;
2808 0         0 $rem->{precision} = undef;
2809             }
2810 0 0       0 $x -> _dng() if $x -> is_int();
2811 0 0       0 $rem -> _dng() if $rem -> is_int();
2812 0         0 return $x, $rem;
2813             }
2814              
2815 0 0       0 $x -> _dng() if $x -> is_int();
2816 0         0 $x; # rounding already done above
2817             }
2818              
2819             sub btmod {
2820             # (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return
2821             # remainder
2822              
2823             # set up parameters
2824 0 0 0 0 1 0 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2825             ? (ref($_[0]), @_)
2826             : objectify(2, @_);
2827              
2828             # Don't modify constant (read-only) objects.
2829              
2830 0 0       0 return $x if $x -> modify('btmod');
2831              
2832             # At least one argument is NaN. This is handled the same way as in
2833             # Math::BigInt -> btmod().
2834              
2835 0 0 0     0 return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
2836              
2837             # Modulo zero. This is handled the same way as in Math::BigInt -> btmod().
2838              
2839 0 0       0 if ($y -> is_zero()) {
2840 0         0 return $x -> round(@r);
2841             }
2842              
2843             # Numerator (dividend) is +/-inf. This is handled the same way as in
2844             # Math::BigInt -> btmod().
2845              
2846 0 0       0 if ($x -> is_inf()) {
2847 0         0 return $x -> bnan(@r);
2848             }
2849              
2850             # Denominator (divisor) is +/-inf. This is handled the same way as in
2851             # Math::BigInt -> btmod().
2852              
2853 0 0       0 if ($y -> is_inf()) {
2854 0         0 return $x -> round(@r);
2855             }
2856              
2857             # Modulo is zero if $x is zero or if $x is an integer and $y is +/-1.
2858              
2859             return $x -> bzero(@r) if $x -> is_zero()
2860             || ($x -> is_int() &&
2861             # check that $y == +1 or $y == -1:
2862 0 0 0     0 ($LIB->_is_zero($y->{_e}) && $LIB->_is_one($y->{_m})));
      0        
      0        
2863              
2864             # Numerator (dividend) and denominator (divisor) are identical. Return
2865             # zero.
2866              
2867 0         0 my $cmp = $x -> bacmp($y); # $x <=> $y
2868 0 0       0 if ($cmp == 0) { # $x == $y => result 0
2869 0         0 return $x -> bzero(@r);
2870             }
2871              
2872             # Compare the exponents of $x and $y.
2873              
2874 0         0 my $ecmp = $LIB->_scmp($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
2875              
2876 0 0       0 if ($ecmp > 0) {
    0          
2877              
2878             # $x has a larger exponent than $y, so shift the mantissa of $x by the
2879             # difference between the exponents of $x and $y.
2880             #
2881             # 123e+2 % 456e+1 => 1230 % 456 (+2 - +1 = 1)
2882             # 123e+2 % 456e-1 => 123000 % 456 (+2 - -1 = 3)
2883             # 456e-1 % 123e-3 => 12300 % 456 (-1 - -3 = 2)
2884              
2885             # get the difference between exponents; $ds is always "+" here
2886             my ($de, $ds) = $LIB->_ssub($LIB->_copy($x->{_e}), $x->{_es},
2887 0         0 $y->{_e}, $y->{_es});
2888              
2889             # adjust the mantissa of x by the difference between exponents
2890 0         0 $x->{_m} = $LIB->_lsft($x->{_m}, $de, 10);
2891              
2892             # compute the modulus
2893 0         0 $x->{_m} = $LIB->_mod($x->{_m}, $y->{_m});
2894              
2895             # adjust the exponent of x to correct for the ajustment of the mantissa
2896 0         0 ($x->{_e}, $x->{_es}) = $LIB->_ssub($x->{_e}, $x->{_es}, $de, $ds);
2897              
2898             } elsif ($ecmp < 0) {
2899              
2900             # $x has a smaller exponent than $y, so shift the mantissa of $y by the
2901             # difference between the exponents of $x and $y.
2902             #
2903             # 123456e+1 % 78e+2 => 123456 % 780 (+2 - +1 = 1)
2904             # 123456e-2 % 78e+1 => 123456 % 78000 (+1 - -2 = 3)
2905              
2906             # get the difference between exponents; $ds is always "+" here
2907             my ($de, $ds) = $LIB->_ssub($LIB->_copy($y->{_e}), $y->{_es},
2908 0         0 $x->{_e}, $x->{_es});
2909              
2910             # adjust the mantissa of y by the difference between exponents
2911 0         0 my $ym = $LIB->_lsft($LIB->_copy($y->{_m}), $de, 10);
2912              
2913             # compute the modulus
2914 0         0 $x->{_m} = $LIB->_mod($x->{_m}, $ym);
2915              
2916             } else {
2917              
2918             # $x has the same exponent as $y, so compute the modulus directly
2919              
2920             # compute the modulus
2921 0         0 $x->{_m} = $LIB->_mod($x->{_m}, $y->{_m});
2922             }
2923              
2924 0 0       0 $x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # fix sign for -0
2925              
2926 0         0 $x -> bnorm();
2927 0         0 $x -> round($r[0], $r[1], $r[2], $y);
2928 0 0       0 $x -> _dng() if $x -> is_int();
2929 0         0 return $x;
2930             }
2931              
2932             sub binv {
2933 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2934              
2935             # Don't modify constant (read-only) objects.
2936              
2937 0 0       0 return $x if $x -> modify('binv');
2938              
2939             # bone() might perform downgrading, so temporarily disable downgrading
2940              
2941 0         0 my $dng = Math::BigFloat -> downgrade();
2942 0         0 Math::BigFloat -> downgrade(undef);
2943              
2944 0         0 my $inv = $class -> bone() -> bdiv($x, @r);
2945              
2946             # Restore downgrading
2947              
2948 0         0 Math::BigFloat -> downgrade($dng);
2949              
2950 0         0 %$x = %$inv;
2951              
2952 0         0 $x -> round(@r);
2953 0 0 0     0 $x -> _dng() if ($x -> is_int() ||
      0        
2954             $x -> is_inf() ||
2955             $x -> is_nan());
2956 0         0 return $x;
2957             }
2958              
2959             sub bsqrt {
2960             # calculate square root
2961 445 50   445 1 3141 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2962              
2963             # Don't modify constant (read-only) objects.
2964              
2965 445 50       1953 return $x if $x -> modify('bsqrt');
2966              
2967             # Handle trivial cases.
2968              
2969 445 100       1542 return $x -> bnan(@r) if $x -> is_nan();
2970 437 100       1299 return $x -> binf("+", @r) if $x -> is_inf("+");
2971 433 100 100     1544 return $x -> round(@r) if $x -> is_zero() || $x -> is_one();
2972              
2973             # We don't support complex numbers.
2974              
2975 425 100       1768 if ($x -> is_neg()) {
2976 20 50       99 return $x -> _upg() -> bsqrt(@r) if $class -> upgrade();
2977 20         93 return $x -> bnan(@r);
2978             }
2979              
2980             # we need to limit the accuracy to protect against overflow
2981 405         990 my $fallback = 0;
2982 405         803 my (@params, $scale);
2983 405         1645 ($x, @params) = $x->_find_round_parameters(@r);
2984              
2985             # error in _find_round_parameters?
2986 405 50       1336 return $x -> bnan(@r) if $x -> is_nan();
2987              
2988             # no rounding at all, so must use fallback
2989 405 100       1318 if (scalar @params == 0) {
2990             # simulate old behaviour
2991 125         605 $params[0] = $class -> div_scale(); # and round to it as accuracy
2992 125         284 $scale = $params[0]+4; # at least four more for proper round
2993 125         252 $params[2] = $r[2]; # round mode by caller or undef
2994 125         266 $fallback = 1; # to clear a/p afterwards
2995             } else {
2996             # the 4 below is empirical, and there might be cases where it is not
2997             # enough...
2998 280   100     1081 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
2999             }
3000              
3001             # Shift the significand left or right to get the desired number of digits,
3002             # which is 2*$scale with possibly one extra digit to ensure that the
3003             # exponent is an even number.
3004              
3005 405         2073 my $l = $LIB -> _len($x->{_m});
3006 405         959 my $n = 2 * $scale - $l; # how much should we shift?
3007 405 100 100     1902 $n++ if ($l % 2 xor $LIB -> _is_odd($x->{_e}));
3008 405 100       1669 my ($na, $ns) = $n < 0 ? (abs($n), "-") : ($n, "+");
3009 405         1569 $na = $LIB -> _new($na);
3010              
3011             $x->{_m} = $ns eq "+" ? $LIB -> _lsft($x->{_m}, $na, 10)
3012 405 100       2366 : $LIB -> _rsft($x->{_m}, $na, 10);
3013              
3014 405         2215 $x->{_m} = $LIB -> _sqrt($x->{_m});
3015              
3016             # Adjust the exponent by the amount that we shifted the significand. The
3017             # square root of the exponent is simply half of it: sqrt(10^(2*a)) = 10^a.
3018              
3019 405         2309 ($x->{_e}, $x->{_es}) = $LIB -> _ssub($x->{_e}, $x->{_es}, $na, $ns);
3020 405         1847 $x->{_e} = $LIB -> _div($x->{_e}, $LIB -> _new("2"));
3021              
3022             # Normalize to get rid of any trailing zeros in the significand.
3023              
3024 405         2136 $x -> bnorm();
3025              
3026             # shortcut to not run through _find_round_parameters again
3027 405 100       1036 if (defined $params[0]) {
3028 383         1812 $x -> bround($params[0], $params[2]); # then round accordingly
3029             } else {
3030 22         101 $x -> bfround($params[1], $params[2]); # then round accordingly
3031             }
3032              
3033 405 100       1319 if ($fallback) {
3034             # clear a/p after round, since user did not request it
3035 125         337 $x->{accuracy} = undef;
3036 125         340 $x->{precision} = undef;
3037             }
3038              
3039 405         1952 $x -> round(@r);
3040 405 100       1116 $x -> _dng() if $x -> is_int();
3041 405         3790 $x;
3042             }
3043              
3044             sub bpow {
3045             # (BFLOAT or num_str, BFLOAT or num_str) return BFLOAT
3046             # compute power of two numbers, second arg is used as integer
3047             # modifies first argument
3048              
3049             # set up parameters
3050 1077     1077 1 18470 my ($class, $x, $y, $a, $p, $r) = (ref($_[0]), @_);
3051             # objectify is costly, so avoid it
3052 1077 100 100     5917 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
3053 98         415 ($class, $x, $y, $a, $p, $r) = objectify(2, @_);
3054             }
3055              
3056             # Don't modify constant (read-only) objects.
3057              
3058 1077 50       4212 return $x if $x -> modify('bpow');
3059              
3060             # $x and/or $y is a NaN
3061 1077 100 100     3509 return $x -> bnan() if $x -> is_nan() || $y -> is_nan();
3062              
3063             # $x and/or $y is a +/-Inf
3064 961 100       2918 if ($x -> is_inf("-")) {
    100          
    100          
    100          
3065 60 100       259 return $x -> bzero() if $y -> is_negative();
3066 32 100       137 return $x -> bnan() if $y -> is_zero();
3067 28 100       128 return $x if $y -> is_odd();
3068 20         99 return $x -> bneg();
3069             } elsif ($x -> is_inf("+")) {
3070 60 100       241 return $x -> bzero() if $y -> is_negative();
3071 32 100       115 return $x -> bnan() if $y -> is_zero();
3072 28         357 return $x;
3073             } elsif ($y -> is_inf("-")) {
3074 44 100       242 return $x -> bnan() if $x -> is_one("-");
3075 40 100 100     221 return $x -> binf("+") if $x > -1 && $x < 1;
3076 28 100       162 return $x -> bone() if $x -> is_one("+");
3077 24         134 return $x -> bzero();
3078             } elsif ($y -> is_inf("+")) {
3079 44 100       253 return $x -> bnan() if $x -> is_one("-");
3080 40 100 100     248 return $x -> bzero() if $x > -1 && $x < 1;
3081 28 100       170 return $x -> bone() if $x -> is_one("+");
3082 24         89 return $x -> binf("+");
3083             }
3084              
3085 753 100       3034 if ($x -> is_zero()) {
3086 48 100       122 return $x -> bone() if $y -> is_zero();
3087 44 100       191 return $x -> binf() if $y -> is_negative();
3088 24         331 return $x;
3089             }
3090              
3091             # We don't support complex numbers, so upgrade or return NaN.
3092              
3093 705 100 100     2639 if ($x -> is_negative() && !$y -> is_int()) {
3094 80 50       432 return $x -> _upg() -> bpow($y, $a, $p, $r) if $class -> upgrade();
3095 80         467 return $x -> bnan();
3096             }
3097              
3098 625 100 100     2263 if ($x -> is_one("+") || $y -> is_one()) {
3099 148         1733 return $x;
3100             }
3101              
3102 477 100       1496 if ($x -> is_one("-")) {
3103 24 100       93 return $x if $y -> is_odd();
3104 12         75 return $x -> bneg();
3105             }
3106              
3107 453 100       1336 return $x -> _pow($y, $a, $p, $r) if !$y -> is_int();
3108              
3109             # We should NOT be looking at private variables of other objects. Fixme XXX
3110 338         1482 my $y1 = $y -> as_int()->{value}; # make MBI part
3111              
3112 338         1426 my $new_sign = '+';
3113 338 100       1690 $new_sign = $LIB -> _is_odd($y1) ? '-' : '+' if $x->{sign} ne '+';
    100          
3114              
3115             # calculate $x->{_m} ** $y and $x->{_e} * $y separately (faster)
3116 338         1943 $x->{_m} = $LIB -> _pow($x->{_m}, $y1);
3117 338         1636 $x->{_e} = $LIB -> _mul($x->{_e}, $y1);
3118              
3119 338         885 $x->{sign} = $new_sign;
3120 338         1747 $x -> bnorm();
3121              
3122             # x ** (-y) = 1 / (x ** y)
3123              
3124 338 100       1146 if ($y->{sign} eq '-') {
3125             # modify $x in place!
3126 107         428 my $z = $x -> copy();
3127 107         624 $x -> bone();
3128             # round in one go (might ignore y's A!)
3129 107         622 return scalar $x -> bdiv($z, $a, $p, $r);
3130             }
3131              
3132 231         1048 $x -> round($a, $p, $r, $y);
3133              
3134 231 100 66     628 $x -> _dng() if ($x -> is_int() ||
      100        
3135             $x -> is_inf() ||
3136             $x -> is_nan());
3137 231         3096 return $x;
3138             }
3139              
3140             sub broot {
3141             # calculate $y'th root of $x
3142              
3143             # set up parameters
3144 193 100 66 193 1 3400 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
3145             ? (ref($_[0]), @_)
3146             : objectify(2, @_);
3147              
3148             # Don't modify constant (read-only) objects.
3149              
3150 193 50       823 return $x if $x -> modify('broot');
3151              
3152             # Handle trivial cases.
3153              
3154 193 100 100     606 return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
3155              
3156 157 100       553 if ($x -> is_neg()) {
3157             # -27 ** (1/3) = -(27 ** (1/3)) = -3
3158 44 100 66     150 return $x -> broot($y -> copy() -> bneg(), @r) -> bneg()
      100        
      66        
3159             if ($x -> is_int() && $y -> is_int() &&
3160             $y -> is_neg() && $y -> is_odd());
3161 40 50       162 return $x -> _upg -> broot($y, @r) if $class -> upgrade();
3162 40         145 return $x -> bnan(@r);
3163             }
3164              
3165             # NaN handling: $x ** 1/0, x or y NaN, or y inf/-inf or y == 0
3166             return $x -> bnan(@r) if ($x->{sign} !~ /^\+/ || $y -> is_zero() ||
3167 113 100 66     723 $y->{sign} !~ /^\+$/);
      100        
3168              
3169             # Trivial cases.
3170 89 100 100     218 return $x if ($x -> is_zero() || $x -> is_one() ||
      100        
      100        
3171             $x -> is_inf() || $y -> is_one());
3172              
3173             # we need to limit the accuracy to protect against overflow
3174 73         152 my $fallback = 0;
3175 73         163 my (@params, $scale);
3176 73         354 ($x, @params) = $x->_find_round_parameters(@r);
3177              
3178 73 50       222 return $x if $x -> is_nan(); # error in _find_round_parameters?
3179              
3180             # no rounding at all, so must use fallback
3181 73 50       248 if (scalar @params == 0) {
3182             # simulate old behaviour
3183 73         312 $params[0] = $class -> div_scale(); # and round to it as accuracy
3184 73         175 $scale = $params[0]+4; # at least four more for proper round
3185 73         144 $params[2] = $r[2]; # round mode by caller or undef
3186 73         159 $fallback = 1; # to clear a/p afterwards
3187             } else {
3188             # the 4 below is empirical, and there might be cases where it is not
3189             # enough...
3190 0   0     0 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
3191             }
3192              
3193             # When user set globals, they would interfere with our calculation, so
3194             # disable them and later re-enable them.
3195              
3196 73         213 my $ab = $class -> accuracy();
3197 73         203 my $pb = $class -> precision();
3198 73         239 $class -> accuracy(undef);
3199 73         228 $class -> precision(undef);
3200              
3201             # Disabling upgrading and downgrading is no longer necessary to avoid an
3202             # infinite recursion, but it avoids unnecessary upgrading and downgrading
3203             # in the intermediate computations.
3204              
3205 73         270 my $upg = $class -> upgrade();
3206 73         216 my $dng = $class -> downgrade();
3207 73         250 $class -> upgrade(undef);
3208 73         232 $class -> downgrade(undef);
3209              
3210             # We also need to disable any set A or P on $x (_find_round_parameters took
3211             # them already into account), since these would interfere, too.
3212              
3213 73         197 $x->{accuracy} = undef;
3214 73         250 $x->{precision} = undef;
3215              
3216             # remember sign and make $x positive, since -4 ** (1/2) => -2
3217 73         132 my $sign = 0;
3218 73 50       239 $sign = 1 if $x->{sign} eq '-';
3219 73         173 $x->{sign} = '+';
3220              
3221 73         141 my $is_two = 0;
3222 73 50       241 if ($y -> isa('Math::BigFloat')) {
3223             $is_two = $y->{sign} eq '+' && $LIB->_is_two($y->{_m})
3224 73   66     519 && $LIB->_is_zero($y->{_e});
3225             } else {
3226 0         0 $is_two = $y == 2;
3227             }
3228              
3229             # Normal square root if $y == 2
3230              
3231 73 100       258 if ($is_two) {
    50          
3232 49         194 $x -> bsqrt($scale + 4);
3233             }
3234              
3235             # Inverse: $x ** (-1) => 1 / $x
3236              
3237             elsif ($y -> is_one('-')) {
3238 0         0 $x -> binv($scale + 4);
3239             }
3240              
3241             # General case: calculate the broot() as integer result first, and if it
3242             # fits, return it rightaway (but only if $x and $y are integer).
3243             #
3244             # This code should be improved. XXX
3245              
3246             else {
3247              
3248             # Temporarily disable upgrading in Math::BigInt.
3249              
3250 24         99 my $mbi_upg = Math::BigInt -> upgrade();
3251 24         90 Math::BigInt -> upgrade(undef);
3252              
3253 24         75 my $done = 0; # not yet
3254 24 100 66     79 if ($y -> is_int() && $x -> is_int()) {
3255 23         103 my $i = $LIB->_copy($x->{_m});
3256 23 50       88 $i = $LIB->_lsft($i, $x->{_e}, 10) unless $LIB->_is_zero($x->{_e});
3257 23         123 my $int = Math::BigInt -> bzero();
3258 23         78 $int->{value} = $i;
3259 23         105 $int -> broot($y -> as_int());
3260             # if ($exact)
3261 23 100       205 if ($int -> copy() -> bpow($y -> as_int()) == $x -> as_int()) {
3262             # found result, return it
3263 17         72 $x->{_m} = $int->{value};
3264 17         171 $x->{_e} = $LIB->_zero();
3265 17         52 $x->{_es} = '+';
3266 17         92 $x -> bnorm();
3267 17         75 $done = 1;
3268             }
3269             }
3270              
3271 24 100       180 if ($done == 0) {
3272 7         40 my $u = $class -> bone() -> bdiv($y, $scale+4);
3273 7         19 $u->{accuracy} = undef;
3274 7         18 $u->{precision} = undef;
3275 7         32 $x -> bpow($u, $scale+4); # el cheapo
3276             }
3277              
3278 24         125 Math::BigInt -> upgrade($mbi_upg);
3279             }
3280              
3281 73 50       216 $x -> bneg() if $sign == 1;
3282              
3283             # shortcut to not run through _find_round_parameters again
3284 73 50       203 if (defined $params[0]) {
3285 73         331 $x -> bround($params[0], $params[2]); # then round accordingly
3286             } else {
3287 0         0 $x -> bfround($params[1], $params[2]); # then round accordingly
3288             }
3289 73 50       211 if ($fallback) {
3290             # clear a/p after round, since user did not request it
3291 73         163 $x->{accuracy} = undef;
3292 73         146 $x->{precision} = undef;
3293             }
3294              
3295             # Restore globals. We need to do it like this, because setting one
3296             # undefines the other.
3297              
3298 73 50       192 if (defined $ab) {
3299 0         0 $class -> accuracy($ab);
3300             } else {
3301 73         326 $class -> precision($pb);
3302             }
3303              
3304 73         287 $class -> upgrade($upg);
3305 73         231 $class -> downgrade($dng);
3306              
3307 73         334 $x -> round(@r);
3308 73 50 66     180 $x -> _dng() if ($x -> is_int() ||
      66        
3309             $x -> is_inf() ||
3310             $x -> is_nan());
3311 73         1156 return $x;
3312             }
3313              
3314             sub bmuladd {
3315             # multiply two numbers and add the third to the result
3316              
3317             # set up parameters
3318 247 100 66 247 1 5684 my ($class, $x, $y, $z, @r)
3319             = ref($_[0]) && ref($_[0]) eq ref($_[1]) && ref($_[1]) eq ref($_[2])
3320             ? (ref($_[0]), @_)
3321             : objectify(3, @_);
3322              
3323             # Don't modify constant (read-only) objects.
3324              
3325 247 50       1064 return $x if $x -> modify('bmuladd');
3326              
3327             # At least one of x, y, and z is a NaN
3328              
3329 247 100 100     807 return $x -> bnan(@r) if ($x -> is_nan() ||
      100        
3330             $y -> is_nan() ||
3331             $z -> is_nan());
3332              
3333             # At least one of x, y, and z is an Inf
3334              
3335 214 100       808 if ($x -> is_inf("-")) {
    100          
    100          
    100          
    50          
3336              
3337 8 100       37 if ($y -> is_neg()) { # x = -inf, y < 0
    50          
3338 4 50       457 if ($z -> is_inf("-")) {
3339 0         0 return $x -> bnan(@r);
3340             } else {
3341 4         341 return $x -> binf("+", @r);
3342             }
3343             } elsif ($y -> is_zero()) { # x = -inf, y = 0
3344 0         0 return $x -> bnan(@r);
3345             } else { # x = -inf, y > 0
3346 4 50       17 if ($z->{sign} eq "+inf") {
3347 0         0 return $x -> bnan(@r);
3348             } else {
3349 4         17 return $x -> binf("-", @r);
3350             }
3351             }
3352              
3353             } elsif ($x->{sign} eq "+inf") {
3354              
3355 10 100       56 if ($y -> is_neg()) { # x = +inf, y < 0
    50          
3356 4 50       21 if ($z->{sign} eq "+inf") {
3357 0         0 return $x -> bnan(@r);
3358             } else {
3359 4         24 return $x -> binf("-", @r);
3360             }
3361             } elsif ($y -> is_zero()) { # x = +inf, y = 0
3362 0         0 return $x -> bnan(@r);
3363             } else { # x = +inf, y > 0
3364 6 50       20 if ($z -> is_inf("-")) {
3365 0         0 return $x -> bnan(@r);
3366             } else {
3367 6         24 return $x -> binf("+", @r);
3368             }
3369             }
3370              
3371             } elsif ($x -> is_neg()) {
3372              
3373 40 50       131 if ($y -> is_inf("-")) { # -inf < x < 0, y = -inf
    50          
3374 0 0       0 if ($z -> is_inf("-")) {
3375 0         0 return $x -> bnan(@r);
3376             } else {
3377 0         0 return $x -> binf("+", @r);
3378             }
3379             } elsif ($y->{sign} eq "+inf") { # -inf < x < 0, y = +inf
3380 0 0       0 if ($z->{sign} eq "+inf") {
3381 0         0 return $x -> bnan(@r);
3382             } else {
3383 0         0 return $x -> binf("-", @r);
3384             }
3385             } else { # -inf < x < 0, -inf < y < +inf
3386 40 50       128 if ($z -> is_inf("-")) {
    50          
3387 0         0 return $x -> binf("-", @r);
3388             } elsif ($z->{sign} eq "+inf") {
3389 0         0 return $x -> binf("+", @r);
3390             }
3391             }
3392              
3393             } elsif ($x -> is_zero()) {
3394              
3395 17 50       50 if ($y -> is_inf("-")) { # x = 0, y = -inf
    50          
3396 0         0 return $x -> bnan(@r);
3397             } elsif ($y->{sign} eq "+inf") { # x = 0, y = +inf
3398 0         0 return $x -> bnan(@r);
3399             } else { # x = 0, -inf < y < +inf
3400 17 50       52 if ($z -> is_inf("-")) {
    50          
3401 0         0 return $x -> binf("-", @r);
3402             } elsif ($z->{sign} eq "+inf") {
3403 0         0 return $x -> binf("+", @r);
3404             }
3405             }
3406              
3407             } elsif ($x -> is_pos()) {
3408              
3409 139 50       388 if ($y -> is_inf("-")) { # 0 < x < +inf, y = -inf
    50          
3410 0 0       0 if ($z->{sign} eq "+inf") {
3411 0         0 return $x -> bnan(@r);
3412             } else {
3413 0         0 return $x -> binf("-", @r);
3414             }
3415             } elsif ($y->{sign} eq "+inf") { # 0 < x < +inf, y = +inf
3416 0 0       0 if ($z -> is_inf("-")) {
3417 0         0 return $x -> bnan(@r);
3418             } else {
3419 0         0 return $x -> binf("+", @r);
3420             }
3421             } else { # 0 < x < +inf, -inf < y < +inf
3422 139 50       392 if ($z -> is_inf("-")) {
    100          
3423 0         0 return $x -> binf("-", @r);
3424             } elsif ($z->{sign} eq "+inf") {
3425 1         5 return $x -> binf("+", @r);
3426             }
3427             }
3428             }
3429              
3430             # At this point, we know that x, y, and z are finite numbers
3431              
3432             # Rather than copying $y and/or $z, perhaps we should assign the output to
3433             # a temporary $x value, and assign the final result to $x? XXX
3434              
3435 195 50       1689 $y = $y -> copy() if refaddr($y) eq refaddr($x);
3436 195 50       742 $z = $z -> copy() if refaddr($z) eq refaddr($x);
3437              
3438             # aEb * cEd = (a*c)E(b+d)
3439 195         1625 $x->{_m} = $LIB->_mul($x->{_m}, $y->{_m});
3440             ($x->{_e}, $x->{_es})
3441 195         1099 = $LIB -> _sadd($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
3442              
3443 195         556 $r[3] = $y; # no push!
3444              
3445             # adjust sign:
3446 195 100       660 $x->{sign} = $x->{sign} ne $y->{sign} ? '-' : '+';
3447              
3448             # take lower of the two e's and adapt m1 to it to match m2
3449 195         355 my $e = $z->{_e};
3450 195 50       483 $e = $LIB->_zero() if !defined $e; # if no BFLOAT?
3451 195         673 $e = $LIB->_copy($e); # make copy (didn't do it yet)
3452              
3453 195         360 my $es;
3454              
3455 195   50     926 ($e, $es) = $LIB -> _ssub($e, $z->{_es} || '+', $x->{_e}, $x->{_es});
3456              
3457 195         716 my $add = $LIB->_copy($z->{_m});
3458              
3459 195 100       737 if ($es eq '-') # < 0
    100          
3460             {
3461 4         33 $x->{_m} = $LIB->_lsft($x->{_m}, $e, 10);
3462 4         24 ($x->{_e}, $x->{_es}) = $LIB -> _sadd($x->{_e}, $x->{_es}, $e, $es);
3463             } elsif (!$LIB->_is_zero($e)) # > 0
3464             {
3465 9         58 $add = $LIB->_lsft($add, $e, 10);
3466             }
3467             # else: both e are the same, so just leave them
3468              
3469 195 100       551 if ($x->{sign} eq $z->{sign}) {
3470             # add
3471 151         489 $x->{_m} = $LIB->_add($x->{_m}, $add);
3472             } else {
3473             ($x->{_m}, $x->{sign}) =
3474 44         181 $LIB -> _sadd($x->{_m}, $x->{sign}, $add, $z->{sign});
3475             }
3476              
3477             # delete trailing zeros, then round
3478 195         716 $x -> bnorm() -> round(@r);
3479              
3480 195 50 66     578 $x -> _dng() if ($x -> is_int() ||
      66        
3481             $x -> is_inf() ||
3482             $x -> is_nan());
3483 195         3510 return $x;
3484             }
3485              
3486             sub bmodpow {
3487             # takes a very large number to a very large exponent in a given very
3488             # large modulus, quickly, thanks to binary exponentiation. Supports
3489             # negative exponents.
3490 20 50 33 20 1 584 my ($class, $num, $exp, $mod, @r)
3491             = ref($_[0]) && ref($_[0]) eq ref($_[1]) && ref($_[1]) eq ref($_[2])
3492             ? (ref($_[0]), @_)
3493             : objectify(3, @_);
3494              
3495             # Don't modify constant (read-only) objects.
3496              
3497 20 50       98 return $num if $num -> modify('bmodpow');
3498              
3499 20 50 33     78 return $num -> bnan(@r)
      33        
3500             if $mod -> is_nan() || $exp -> is_nan() || $mod -> is_nan();
3501              
3502             # check modulus for valid values
3503 20 50 33     539 return $num -> bnan(@r) if $mod->{sign} ne '+' || $mod -> is_zero();
3504              
3505             # check exponent for valid values
3506 20 50       90 if ($exp->{sign} =~ /\w/) {
3507             # i.e., if it's NaN, +inf, or -inf...
3508 0         0 return $num -> bnan(@r);
3509             }
3510              
3511 20 50       98 $num -> bmodinv($mod, @r) if $exp->{sign} eq '-';
3512              
3513             # check num for valid values (also NaN if there was no inverse but $exp < 0)
3514 20 50       124 return $num -> bnan(@r) if $num->{sign} !~ /^[+-]$/;
3515              
3516             # $mod is positive, sign on $exp is ignored, result also positive
3517              
3518             # XXX TODO: speed it up when all three numbers are integers
3519 20         114 $num -> bpow($exp) -> bmod($mod);
3520              
3521 20         79 $num -> round(@r);
3522 20 50 66     53 $num -> _dng() if ($num -> is_int() ||
      66        
3523             $num -> is_inf() ||
3524             $num -> is_nan());
3525 20         424 return $num;
3526             }
3527              
3528             sub blog {
3529             # Return the logarithm of the operand. If a second operand is defined, that
3530             # value is used as the base, otherwise the base is assumed to be Euler's
3531             # constant.
3532              
3533 263     263 1 2112 my ($class, $x, $base, @r);
3534              
3535             # Only objectify the base if it is defined, since an undefined base, as in
3536             # $x->blog() or $x->blog(undef) signals that the base is Euler's number =
3537             # 2.718281828...
3538              
3539 263 100 66     1266 if (!ref($_[0]) && $_[0] =~ /^[A-Za-z]|::/) {
3540             # E.g., Math::BigFloat->blog(256, 2)
3541 1 50       9 ($class, $x, $base, @r) =
3542             defined $_[2] ? objectify(2, @_) : objectify(1, @_);
3543             } else {
3544             # E.g., $x->blog(2) or the deprecated Math::BigFloat::blog(256, 2)
3545 262 100       1555 ($class, $x, $base, @r) =
3546             defined $_[1] ? objectify(2, @_) : objectify(1, @_);
3547             }
3548              
3549             # Don't modify constant (read-only) objects.
3550              
3551 263 50       1356 return $x if $x -> modify('blog');
3552              
3553             # Handle all exception cases and all trivial cases. I have used Wolfram
3554             # Alpha (http://www.wolframalpha.com) as the reference for these cases.
3555              
3556 263 100       1004 return $x -> bnan(@r) if $x -> is_nan();
3557              
3558 259 100       886 if (defined $base) {
3559 44 50 33     220 $base = $class -> new($base)
3560             unless defined(blessed($base)) && $base -> isa(__PACKAGE__);
3561 44 100 66     192 if ($base -> is_nan() || $base -> is_one()) {
    100 66        
    100          
3562 8         39 return $x -> bnan(@r);
3563             } elsif ($base -> is_inf() || $base -> is_zero()) {
3564 4 50 33     23 return $x -> bnan(@r) if $x -> is_inf() || $x -> is_zero();
3565 4         24 return $x -> bzero(@r);
3566             } elsif ($base -> is_negative()) { # -inf < base < 0
3567 4 50       17 return $x -> bzero(@r) if $x -> is_one(); # x = 1
3568 4 50       23 return $x -> bone('+', @r) if $x == $base; # x = base
3569             # we can't handle these cases, so upgrade, if we can
3570 4 50       26 return $x -> _upg() -> blog($base, @r) if $class -> upgrade();
3571 4         22 return $x -> bnan(@r);
3572             }
3573 28 100       136 return $x -> bone(@r) if $x == $base; # 0 < base && 0 < x < inf
3574             }
3575              
3576 232 100       843 if ($x -> is_inf()) { # x = +/-inf
    100          
    100          
    100          
3577 8 50 33     47 my $sign = defined($base) && $base < 1 ? '-' : '+';
3578 8         33 return $x -> binf($sign, @r);
3579             } elsif ($x -> is_neg()) { # -inf < x < 0
3580 16 50       126 return $x -> _upg() -> blog($base, @r) if $class -> upgrade();
3581 16         79 return $x -> bnan(@r);
3582             } elsif ($x -> is_one()) { # x = 1
3583 16         92 return $x -> bzero(@r);
3584             } elsif ($x -> is_zero()) { # x = 0
3585 8 50 33     48 my $sign = defined($base) && $base < 1 ? '+' : '-';
3586 8         43 return $x -> binf($sign, @r);
3587             }
3588              
3589             # we need to limit the accuracy to protect against overflow
3590 184         447 my $fallback = 0;
3591 184         416 my ($scale, @params);
3592 184         908 ($x, @params) = $x->_find_round_parameters(@r);
3593              
3594             # no rounding at all, so must use fallback
3595 184 100       657 if (scalar @params == 0) {
3596             # simulate old behaviour
3597 97         482 $params[0] = $class -> div_scale(); # and round to it as accuracy
3598 97         231 $params[1] = undef; # P = undef
3599 97         232 $scale = $params[0]+4; # at least four more for proper round
3600 97         225 $params[2] = $r[2]; # round mode by caller or undef
3601 97         218 $fallback = 1; # to clear a/p afterwards
3602             } else {
3603             # the 4 below is empirical, and there might be cases where it is not
3604             # enough...
3605 87   33     423 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
3606             }
3607              
3608             # When user set globals, they would interfere with our calculation, so
3609             # disable them and later re-enable them.
3610              
3611 184         677 my $ab = $class -> accuracy();
3612 184         556 my $pb = $class -> precision();
3613 184         819 $class -> accuracy(undef);
3614 184         631 $class -> precision(undef);
3615              
3616             # Disabling upgrading and downgrading is no longer necessary to avoid an
3617             # infinite recursion, but it avoids unnecessary upgrading and downgrading
3618             # in the intermediate computations.
3619              
3620 184         633 my $upg = $class -> upgrade();
3621 184         2273 my $dng = $class -> downgrade();
3622 184         623 $class -> upgrade(undef);
3623 184         631 $class -> downgrade(undef);
3624              
3625             # We also need to disable any set A or P on $x (_find_round_parameters took
3626             # them already into account), since these would interfere, too.
3627              
3628 184         492 $x->{accuracy} = undef;
3629 184         533 $x->{precision} = undef;
3630              
3631 184         440 my $done = 0;
3632              
3633             # If both $x and $base are integers, try to calculate an integer result
3634             # first. This is very fast, and if the exact result was found, we are done.
3635              
3636 184 100 66     722 if (defined($base) && $base -> is_int() && $x -> is_int()) {
      100        
3637 11         46 my $x_lib = $LIB -> _new($x -> bdstr());
3638 11         41 my $b_lib = $LIB -> _new($base -> bdstr());
3639 11         55 ($x_lib, my $exact) = $LIB -> _log_int($x_lib, $b_lib);
3640 11 100       54 if ($exact) {
3641 10         38 $x->{_m} = $x_lib;
3642 10         37 $x->{_e} = $LIB -> _zero();
3643 10         63 $x -> bnorm();
3644 10         38 $done = 1;
3645             }
3646             }
3647              
3648             # If the integer result was not accurate, compute the natural logarithm
3649             # log($x) (using reduction by 10 and possibly also by 2), and if a
3650             # different base was requested, convert the result with log($x)/log($base).
3651              
3652 184 100       549 unless ($done) {
3653 174         899 $x -> _log_10($scale);
3654 174 100       688 if (defined $base) {
3655             # log_b(x) = ln(x) / ln(b), so compute ln(b)
3656 3         13 my $base_log_e = $base -> copy() -> _log_10($scale);
3657 3         16 $x -> bdiv($base_log_e, $scale);
3658             }
3659             }
3660              
3661             # shortcut to not run through _find_round_parameters again
3662              
3663 184 50       599 if (defined $params[0]) {
3664 184         839 $x -> bround($params[0], $params[2]); # then round accordingly
3665             } else {
3666 0         0 $x -> bfround($params[1], $params[2]); # then round accordingly
3667             }
3668 184 100       746 if ($fallback) {
3669             # clear a/p after round, since user did not request it
3670 97         271 $x->{accuracy} = undef;
3671 97         242 $x->{precision} = undef;
3672             }
3673              
3674             # Restore globals. We need to do it like this, because setting one
3675             # undefines the other.
3676              
3677 184 50       550 if (defined $ab) {
3678 0         0 $class -> accuracy($ab);
3679             } else {
3680 184         884 $class -> precision($pb);
3681             }
3682              
3683 184         753 $class -> upgrade($upg);
3684 184         748 $class -> downgrade($dng);
3685              
3686 184         790 $x -> round(@r);
3687 184 100       564 return $x -> _dng() if $x -> is_int();
3688 169         2222 return $x;
3689             }
3690              
3691             sub bexp {
3692             # Calculate e ** X (Euler's number to the power of X)
3693 20 100   20 1 153 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
3694              
3695             # Don't modify constant (read-only) objects.
3696              
3697 20 50       137 return $x if $x -> modify('bexp');
3698              
3699 20 50       109 return $x -> bnan(@r) if $x -> is_nan();
3700 20 50       80 return $x -> binf(@r) if $x -> is_inf("+");
3701 20 50       85 return $x -> bzero(@r) if $x -> is_inf("-");
3702              
3703             # Get the rounding parameters, if any.
3704              
3705 20         52 my $fallback = 0;
3706 20         44 my ($scale, @params);
3707 20         104 ($x, @params) = $x -> _find_round_parameters(@r);
3708              
3709             # Error in _find_round_parameters?
3710 20 50       76 return $x -> bnan(@r) if $x -> is_nan();
3711              
3712 20 50       115 return $x -> bone(@r) if $x -> is_zero();
3713              
3714             # If no rounding parameters are give, use fallback.
3715              
3716 20 100       81 if (!@params) {
3717 11         62 $params[0] = $class -> div_scale(); # fallback accuracy
3718 11         34 $params[1] = undef; # no precision
3719 11         27 $params[2] = $r[2]; # rounding mode
3720 11         25 $scale = $params[0];
3721 11         24 $fallback = 1; # to clear a/p afterwards
3722             } else {
3723 9 50       35 if (defined($params[0])) {
3724 9         21 $scale = $params[0];
3725             } else {
3726             # We perform the computations below using accuracy only, not
3727             # precision, so when precision is given, we need to "convert" this
3728             # to accuracy. To do that, we need to know, at least approximately,
3729             # how many digits there will be in the final result.
3730             #
3731             # log10(exp($x)) = log(exp($x)) / log(10) = $x / log(10)
3732              
3733             #$scale = 1 + int(log($ms) / log(10) + $es) - $params[1];
3734 0         0 my $ndig = $x -> numify() / log(10);
3735 0         0 $scale = 1 + int($ndig) - $params[1];
3736             }
3737             }
3738              
3739             # Add extra digits to reduce the consequence of round-off errors in the
3740             # intermediate computations.
3741              
3742 20         50 $scale += 4;
3743              
3744 20 50       71 if (!$x -> isa('Math::BigFloat')) {
3745 0         0 $x = Math::BigFloat -> new($x);
3746 0         0 $class = ref($x);
3747             }
3748              
3749             # When user set globals, they would interfere with our calculation, so
3750             # disable them and later re-enable them.
3751              
3752 20         84 my $ab = $class -> accuracy();
3753 20         67 my $pb = $class -> precision();
3754 20         76 $class -> accuracy(undef);
3755 20         71 $class -> precision(undef);
3756              
3757             # Disabling upgrading and downgrading is no longer necessary to avoid an
3758             # infinite recursion, but it avoids unnecessary upgrading and downgrading
3759             # in the intermediate computations.
3760              
3761 20         81 my $upg = $class -> upgrade();
3762 20         69 my $dng = $class -> downgrade();
3763 20         73 $class -> upgrade(undef);
3764 20         75 $class -> downgrade(undef);
3765              
3766             # We also need to disable any set A or P on $x (_find_round_parameters took
3767             # them already into account), since these would interfere, too.
3768              
3769 20         81 $x->{accuracy} = undef;
3770 20         50 $x->{precision} = undef;
3771              
3772 20         100 my $x_orig = $x -> copy();
3773              
3774             # We use the following Taylor series:
3775              
3776             # x x^2 x^3 x^4
3777             # e = 1 + --- + --- + --- + --- ...
3778             # 1! 2! 3! 4!
3779              
3780             # The difference for each term is X and N, which would result in:
3781             # 2 copy, 2 mul, 2 add, 1 inc, 1 div operations per term
3782              
3783             # But it is faster to compute exp(1) and then raising it to the
3784             # given power, esp. if $x is really big and an integer because:
3785              
3786             # * The numerator is always 1, making the computation faster
3787             # * the series converges faster in the case of x == 1
3788             # * We can also easily check when we have reached our limit: when the
3789             # term to be added is smaller than "1E$scale", we can stop - f.i.
3790             # scale == 5, and we have 1/40320, then we stop since 1/40320 < 1E-5.
3791             # * we can compute the *exact* result by simulating bigrat math:
3792              
3793             # 1 1 gcd(3, 4) = 1 1*24 + 1*6 5
3794             # - + - = ---------- = --
3795             # 6 24 6*24 24
3796              
3797             # We do not compute the gcd() here, but simple do:
3798             # 1 1 1*24 + 1*6 30
3799             # - + - = --------- = --
3800             # 6 24 6*24 144
3801              
3802             # In general:
3803             # a c a*d + c*b and note that c is always 1 and d = (b*f)
3804             # - + - = ---------
3805             # b d b*d
3806              
3807             # This leads to: which can be reduced by b to:
3808             # a 1 a*b*f + b a*f + 1
3809             # - + - = --------- = -------
3810             # b b*f b*b*f b*f
3811              
3812             # The first terms in the series are:
3813              
3814             # 1 1 1 1 1 1 1 1 13700
3815             # -- + -- + -- + -- + -- + --- + --- + ---- = -----
3816             # 1 1 2 6 24 120 720 5040 5040
3817              
3818             # Note that we cannot simply reduce 13700/5040 to 685/252, but must keep
3819             # the numerator and the denominator!
3820              
3821 20 100       71 if ($scale <= 75) {
3822             # set $x directly from a cached string form
3823 17         80 $x->{_m} = $LIB->_new("2718281828459045235360287471352662497757" .
3824             "2470936999595749669676277240766303535476");
3825 17         78 $x->{sign} = '+';
3826 17         48 $x->{_es} = '-';
3827 17         60 $x->{_e} = $LIB->_new(79);
3828             } else {
3829             # compute A and B so that e = A / B.
3830              
3831             # After some terms we end up with this, so we use it as a starting
3832             # point:
3833 3         1830 my $A = $LIB->_new("9093339520860578540197197" .
3834             "0164779391644753259799242");
3835 3         14 my $F = $LIB->_new(42);
3836 3         7 my $step = 42;
3837              
3838             # Compute number of steps needed to get $A and $B sufficiently large.
3839              
3840 3         17 my $steps = _len_to_steps($scale - 4);
3841             # print STDERR "# Doing $steps steps for ", $scale-4, " digits\n";
3842              
3843 3         11 while ($step++ <= $steps) {
3844             # calculate $a * $f + 1
3845 79         200 $A = $LIB -> _mul($A, $F);
3846 79         243 $A = $LIB -> _inc($A);
3847             # increment f
3848 79         221 $F = $LIB -> _inc($F);
3849             }
3850              
3851             # Compute $B as factorial of $steps (this is faster than doing it
3852             # manually)
3853 3         13 my $B = $LIB->_fac($LIB->_new($steps));
3854              
3855             # print "A ", $LIB->_str($A), "\nB ", $LIB->_str($B), "\n";
3856              
3857             # compute A/B with $scale digits in the result (truncate, not round)
3858 3         17 $A = $LIB->_lsft($A, $LIB->_new($scale), 10);
3859 3         18 $A = $LIB->_div($A, $B);
3860              
3861 3         13 $x->{_m} = $A;
3862 3         9 $x->{sign} = '+';
3863 3         7 $x->{_es} = '-';
3864 3         46 $x->{_e} = $LIB->_new($scale);
3865             }
3866              
3867             # Now $x contains now an estimate of e, with some additional digits.
3868              
3869 20 100       88 if ($x_orig -> is_one()) {
3870              
3871             # else just round the already computed result
3872              
3873 10         52 $x->{accuracy} = undef;
3874 10         24 $x->{precision} = undef;
3875              
3876             # shortcut to not run through _find_round_parameters again
3877              
3878 10 50       49 if (defined $params[0]) {
3879 10         52 $x -> bround($params[0], $params[2]); # then round accordingly
3880             } else {
3881 0         0 $x -> bfround($params[1], $params[2]); # then round accordingly
3882             }
3883              
3884             } else {
3885              
3886             # Use the fact exp(x) = exp(x/n)**n. In our case, n = 2**i for some
3887             # integer i. We use this to compute exp(y) where y = x / (2**i) and
3888             # 1 <= |y| < 2.
3889             #
3890             # The code below is similar to the code found in to_ieee754().
3891              
3892             # We need to find the base 2 exponent. First make an estimate of the
3893             # base 2 exponent, before adjusting it below. We could skip this
3894             # estimation and go straight to the while-loops below, but the loops
3895             # are slow, especially when the final exponent is far from zero and
3896             # even more so if the number of digits is large. This initial
3897             # estimation speeds up the computation dramatically.
3898             #
3899             # log2($m * 10**$e) = log10($m + 10**$e) * log(10)/log(2)
3900             # = (log10($m) + $e) * log(10)/log(2)
3901             # = (log($m)/log(10) + $e) * log(10)/log(2)
3902              
3903 10         65 my ($m, $e) = $x_orig -> nparts();
3904 10         71 my $ms = $m -> numify();
3905 10         66 my $es = $e -> numify();
3906              
3907             # We start off by initializing the exponent to zero and the mantissa to
3908             # the input value. Then we increase the mantissa and decrease the
3909             # exponent, or vice versa, until the mantissa is in the desired range
3910             # or we hit one of the limits for the exponent.
3911              
3912 10         43 my $mant = $x_orig -> copy() -> babs();
3913 10         46 my $expo;
3914              
3915 10         80 my $one = $class -> bone();
3916 10         42 my $two = $class -> new("2");
3917 10         41 my $half = $class -> new("0.5");
3918              
3919 10         107 my $expo_est = (log(abs($ms))/log(10) + $es) * log(10)/log(2);
3920 10         26 $expo_est = int($expo_est);
3921              
3922             # Don't multiply by a number raised to a negative exponent. This will
3923             # cause a division, whose result is truncated to some fixed number of
3924             # digits. Instead, multiply by the inverse number raised to a positive
3925             # exponent.
3926              
3927 10         42 $expo = $class -> new($expo_est);
3928 10 50       58 if ($expo_est > 0) {
    0          
3929 10         43 $mant -> bmul($half -> copy() -> bpow($expo));
3930             } elsif ($expo_est < 0) {
3931 0         0 my $expo_abs = $expo -> copy() -> bneg();
3932 0         0 $mant -> bmul($two -> copy() -> bpow($expo_abs));
3933             }
3934              
3935             # Final adjustment of the estimate above.
3936              
3937 10         108 while ($mant -> bcmp($two) >= 0) { # $mant <= $two
3938 0         0 $mant -> bmul($half);
3939 0         0 $expo -> binc();
3940             }
3941              
3942 10         42 while ($mant -> bcmp($one) < 0) { # $mant > $one
3943 0         0 $mant -> bmul($two);
3944 0         0 $expo -> bdec();
3945             }
3946              
3947             # Because of the upscaling, we need some additional digits.
3948              
3949 10         56 my $rescale = int($scale + abs($expo) * log(2) / log(10) + 1);
3950 10 50       157 $rescale = 4 if $rescale < 4;
3951              
3952 10         61 $x -> bpow($mant, $rescale);
3953 10         47 my $pow2 = $two -> bpow($expo, $rescale);
3954 10 100       48 $pow2 -> bneg() if $x_orig -> is_negative();
3955              
3956             # The bpow() below fails with the GMP and GMPz libraries if abs($pow2)
3957             # >= 2**30 = 1073741824. With the Pari library, it fails already when
3958             # abs($pow) >= 2**13 = 8192. With the Calc library, it is rediculously
3959             # slow when abs($pow2) is large. Fixme?
3960              
3961 10 50       39 croak "cannot compute bexp(); input value is too large"
3962             if $pow2 -> copy() -> babs() -> bcmp("1073741824") >= 0;
3963              
3964 10         60 $x -> bpow($pow2, $rescale);
3965              
3966             # Rounding parameters given as arguments currently don't override
3967             # instance variables, so accuracy (which is set in the computations
3968             # above) must be undefined before rounding. Fixme.
3969              
3970 10         37 $x->{accuracy} = undef;
3971 10         47 $x -> round(@params);
3972             }
3973              
3974 20 100       76 if ($fallback) {
3975             # clear a/p after round, since user did not request it
3976 11         33 $x->{accuracy} = undef;
3977 11         46 $x->{precision} = undef;
3978             }
3979              
3980             # Restore globals. We need to do it like this, because setting one
3981             # undefines the other.
3982              
3983 20 50       67 if (defined $ab) {
3984 0         0 $class -> accuracy($ab);
3985             } else {
3986 20         103 $class -> precision($pb);
3987             }
3988              
3989 20         98 $class -> upgrade($upg);
3990 20         80 $class -> downgrade($dng);
3991              
3992             # If downgrading, remember to preserve the relevant instance parameters.
3993             # There should be a more elegant way to do this. Fixme.
3994              
3995 20         98 $x -> round(@r);
3996 20 50       59 $x -> _dng() if $x -> is_int();
3997 20         238 $x;
3998             }
3999              
4000             sub bilog2 {
4001 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4002              
4003             # Don't modify constant (read-only) objects.
4004              
4005 0 0       0 return $x if $x -> modify('bilog2');
4006              
4007 0 0       0 return $x -> bnan(@r) if $x -> is_nan();
4008 0 0       0 return $x -> binf("+", @r) if $x -> is_inf("+");
4009 0 0       0 return $x -> binf("-", @r) if $x -> is_zero();
4010              
4011 0 0       0 if ($x -> is_neg()) {
4012 0 0       0 return $x -> _upg() -> bilog2(@r) if $class -> upgrade();
4013 0         0 return $x -> bnan(@r);
4014             }
4015              
4016 0 0       0 if ($x->{_es} eq '-') { # exponent < 0
    0          
4017 0         0 $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
4018             } elsif (! $LIB->_is_zero($x->{_e})) { # exponent > 0
4019 0         0 $x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10);
4020             }
4021              
4022 0         0 $x->{_m} = $LIB -> _ilog2($x->{_m});
4023 0         0 $x->{_e} = $LIB -> _zero();
4024 0         0 $x -> bnorm() -> round(@r);
4025 0         0 $x -> _dng();
4026 0         0 return $x;
4027             }
4028              
4029             sub bilog10 {
4030 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4031              
4032             # Don't modify constant (read-only) objects.
4033              
4034 0 0       0 return $x if $x -> modify('bilog10');
4035              
4036 0 0       0 return $x -> bnan(@r) if $x -> is_nan();
4037 0 0       0 return $x -> binf("+", @r) if $x -> is_inf("+");
4038 0 0       0 return $x -> binf("-", @r) if $x -> is_zero();
4039              
4040 0 0       0 if ($x -> is_neg()) {
4041 0 0       0 return $x -> _upg() -> bilog10(@r) if $class -> upgrade();
4042 0         0 return $x -> bnan(@r);
4043             }
4044              
4045 0 0       0 if ($x->{_es} eq '-') { # exponent < 0
    0          
4046 0         0 $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
4047             } elsif (! $LIB->_is_zero($x->{_e})) { # exponent > 0
4048 0         0 $x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10);
4049             }
4050              
4051 0         0 $x->{_m} = $LIB -> _ilog10($x->{_m});
4052 0         0 $x->{_e} = $LIB -> _zero();
4053 0         0 $x -> bnorm() -> round(@r);
4054 0         0 $x -> _dng();
4055 0         0 return $x;
4056             }
4057              
4058             sub bclog2 {
4059 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4060              
4061             # Don't modify constant (read-only) objects.
4062              
4063 0 0       0 return $x if $x -> modify('bclog2');
4064              
4065 0 0       0 return $x -> bnan(@r) if $x -> is_nan();
4066 0 0       0 return $x -> binf("+", @r) if $x -> is_inf("+");
4067 0 0       0 return $x -> binf("-", @r) if $x -> is_zero();
4068              
4069 0 0       0 if ($x -> is_neg()) {
4070 0 0       0 return $x -> _upg() -> bclog2(@r) if $class -> upgrade();
4071 0         0 return $x -> bnan(@r);
4072             }
4073              
4074 0 0       0 if ($x->{_es} eq '-') { # exponent < 0
    0          
4075 0         0 $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
4076             } elsif (! $LIB->_is_zero($x->{_e})) { # exponent > 0
4077 0         0 $x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10);
4078             }
4079              
4080 0         0 $x->{_m} = $LIB -> _clog2($x->{_m});
4081 0         0 $x->{_e} = $LIB -> _zero();
4082 0         0 $x -> bnorm() -> round(@r);
4083 0         0 $x -> _dng();
4084 0         0 return $x;
4085             }
4086              
4087             sub bclog10 {
4088 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4089              
4090             # Don't modify constant (read-only) objects.
4091              
4092 0 0       0 return $x if $x -> modify('bclog10');
4093              
4094 0 0       0 return $x -> bnan(@r) if $x -> is_nan();
4095 0 0       0 return $x -> binf("+", @r) if $x -> is_inf("+");
4096 0 0       0 return $x -> binf("-", @r) if $x -> is_zero();
4097              
4098 0 0       0 if ($x -> is_neg()) {
4099 0 0       0 return $x -> _upg() -> bclog10(@r) if $class -> upgrade();
4100 0         0 return $x -> bnan(@r);
4101             }
4102              
4103 0 0       0 if ($x->{_es} eq '-') { # exponent < 0
    0          
4104 0         0 $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
4105             } elsif (! $LIB->_is_zero($x->{_e})) { # exponent > 0
4106 0         0 $x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10);
4107             }
4108              
4109 0         0 $x->{_m} = $LIB -> _clog10($x->{_m});
4110 0         0 $x->{_e} = $LIB -> _zero();
4111 0         0 $x -> bnorm() -> round(@r);
4112 0         0 $x -> _dng();
4113 0         0 return $x;
4114             }
4115              
4116             sub bnok {
4117             # Calculate n over k (binomial coefficient or "choose" function) as
4118             # integer. set up parameters
4119 60 50 33 60 1 1393 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
4120             ? (ref($_[0]), @_)
4121             : objectify(2, @_);
4122              
4123 60 50       213 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
4124              
4125             # Don't modify constant (read-only) objects.
4126              
4127 60 50       249 return $x if $x -> modify('bnok');
4128              
4129 60 100 100     245 return $x -> bnan() if $x -> is_nan() || $y -> is_nan();
4130 48 50 66     154 return $x -> bnan() if (($x -> is_finite() && !$x -> is_int()) ||
      33        
      33        
4131             ($y -> is_finite() && !$y -> is_int()));
4132              
4133             # This should be implemented without converting to Math::BigInt. XXX
4134              
4135 48         172 my $xint = $x -> as_int(); # to Math::BigInt
4136 48         131 my $yint = $y -> as_int(); # to Math::BigInt
4137              
4138 48         231 $xint -> bnok($yint);
4139 48         173 $xint -> round(@r);
4140              
4141 48         220 my $xflt = $xint -> as_float();
4142 48         146 $x -> {sign} = $xflt -> {sign};
4143 48         144 $x -> {_m} = $xflt -> {_m};
4144 48         100 $x -> {_es} = $xflt -> {_es};
4145 48         162 $x -> {_e} = $xflt -> {_e};
4146              
4147 48         143 return $x -> _dng();
4148 0         0 return $x;
4149             }
4150              
4151             sub bperm {
4152             # Calculate n over k (binomial coefficient or "choose" function) as
4153             # integer. set up parameters
4154 0 0 0 0 1 0 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
4155             ? (ref($_[0]), @_)
4156             : objectify(2, @_);
4157              
4158 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
4159              
4160             # Don't modify constant (read-only) objects.
4161              
4162 0 0       0 return $x if $x -> modify('bperm');
4163              
4164 0 0 0     0 return $x -> bnan() if $x -> is_nan() || $y -> is_nan();
4165 0 0 0     0 return $x -> bnan() if (($x -> is_finite() && !$x -> is_int()) ||
      0        
      0        
4166             ($y -> is_finite() && !$y -> is_int()));
4167              
4168             # This should be implemented without converting to Math::BigInt. XXX
4169              
4170 0         0 my $xint = $x -> as_int(); # to Math::BigInt
4171 0         0 my $yint = $y -> as_int(); # to Math::BigInt
4172              
4173 0         0 $xint -> bperm($yint);
4174 0         0 $xint -> round(@r);
4175              
4176 0         0 my $xflt = $xint -> as_float();
4177 0         0 $x -> {sign} = $xflt -> {sign};
4178 0         0 $x -> {_m} = $xflt -> {_m};
4179 0         0 $x -> {_es} = $xflt -> {_es};
4180 0         0 $x -> {_e} = $xflt -> {_e};
4181              
4182 0         0 return $x -> _dng();
4183 0         0 return $x;
4184             }
4185              
4186             sub bsin {
4187             # Calculate a sinus of x.
4188 40 50   40 1 735 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4189              
4190             # First we apply range reduction to x. This is because if x is large, the
4191             # Taylor series converges slowly and requires higher accuracy in the
4192             # intermediate computation. The Taylor series is:
4193             #
4194             # x^3 x^5 x^7 x^9
4195             # sin(x) = x - --- + --- - --- + --- ...
4196             # 3! 5! 7! 9!
4197              
4198             # Don't modify constant (read-only) objects.
4199              
4200 40 50       185 return $x if $x -> modify('bsin');
4201              
4202 40 100       146 return $x -> bzero(@r) if $x -> is_zero();
4203 32 100 100     113 return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf();
4204              
4205             # Get the rounding parameters, if any.
4206              
4207 20         44 my $fallback = 0;
4208 20         89 my ($scale, @params);
4209 20         99 ($x, @params) = $x -> _find_round_parameters(@r);
4210              
4211             # Error in _find_round_parameters?
4212              
4213 20 50       85 return $x -> bnan(@r) if $x -> is_nan();
4214              
4215             # If no rounding parameters are given, use fallback.
4216              
4217 20 50       75 if (!@params) {
4218 0         0 $params[0] = $class -> div_scale(); # fallback accuracy
4219 0         0 $params[1] = undef; # no precision
4220 0         0 $params[2] = $r[2]; # rounding mode
4221 0         0 $scale = $params[0];
4222 0         0 $fallback = 1; # to clear a/p afterwards
4223             } else {
4224 20 50       68 if (defined($params[0])) {
4225 20         45 $scale = $params[0];
4226             } else {
4227             # We perform the computations below using accuracy only, not
4228             # precision, so when precision is given, we need to "convert" this
4229             # to accuracy.
4230 0         0 $scale = 1 - $params[1];
4231             }
4232             }
4233              
4234             # Add more digits to the scale if the magnitude of $x is large.
4235              
4236 20         113 my ($m, $e) = $x -> nparts();
4237 20 50       112 $scale += $e if $x >= 10;
4238 20 50       70 $scale = 4 if $scale < 4;
4239              
4240             # When user set globals, they would interfere with our calculation, so
4241             # disable them and later re-enable them
4242              
4243 20         192 my $ab = $class -> accuracy();
4244 20         65 my $pb = $class -> precision();
4245 20         262 $class -> accuracy(undef);
4246 20         66 $class -> precision(undef);
4247              
4248             # Disabling upgrading and downgrading is no longer necessary to avoid an
4249             # infinite recursion, but it avoids unnecessary upgrading and downgrading
4250             # in the intermediate computations.
4251              
4252 20         62 my $upg = $class -> upgrade();
4253 20         181 my $dng = $class -> downgrade();
4254 20         96 $class -> upgrade(undef);
4255 20         66 $class -> downgrade(undef);
4256              
4257             # We also need to disable any set A or P on $x (_find_round_parameters took
4258             # them already into account), since these would interfere, too.
4259              
4260 20         76 $x->{accuracy} = undef;
4261 20         88 $x->{precision} = undef;
4262              
4263 20         52 my $sin_prev; # the previous approximation of sin(x)
4264             my $sin; # the current approximation of sin(x)
4265              
4266 20         49 while (1) {
4267              
4268             # Compute constants to the current scale.
4269              
4270 52         270 my $pi = $class -> bpi($scale); # 𝜋
4271 52         163 my $twopi = $pi -> copy() -> bmul("2"); # 2𝜋
4272 52         178 my $halfpi = $pi -> copy() -> bmul("0.5"); # 𝜋/2
4273              
4274             # Use the fact that sin(-x) = -sin(x) to reduce the range to the
4275             # interval to [0,∞).
4276              
4277 52 50       308 my $xsgn = $x < 0 ? -1 : 1;
4278 52         184 my $x = $x -> copy() -> babs();
4279              
4280             # Use the fact that sin(2𝜋x) = sin(x) to reduce the range to the
4281             # interval to [0, 2𝜋).
4282              
4283 52         307 $x -> bmod($twopi, $scale);
4284              
4285             # Use the fact that sin(x+𝜋) = -sin(x) to reduce the range to the
4286             # interval to [0,𝜋).
4287              
4288 52 100       171 if ($x -> bcmp($pi) > 0) {
4289 12         27 $xsgn = -$xsgn;
4290 12         87 $x -> bsub($pi);
4291             }
4292              
4293             # Use the fact that sin(𝜋-x) = sin(x) to reduce the range to the
4294             # interval [0,𝜋/2).
4295              
4296 52 100       176 if ($x -> bcmp($halfpi) > 0) {
4297 12         63 $x -> bsub($pi) -> bneg(); # 𝜋 - x
4298             }
4299              
4300 52         309 my $tol = $class -> new("1E-". ($scale-1));
4301              
4302 52         265 my $xsq = $x -> copy() -> bmul($x, $scale) -> bneg();
4303 52         179 my $term = $x -> copy();
4304 52         269 my $fac = $class -> bone();
4305 52         137 my $n = $class -> bone();
4306              
4307 52         190 $sin = $x -> copy(); # initialize sin(x) to the first term
4308              
4309 52         94 while (1) {
4310 504         2159 $n -> binc();
4311 504         1505 $fac = $n -> copy();
4312 504         2981 $n -> binc();
4313 504         2082 $fac -> bmul($n);
4314              
4315 504         1416 $term -> bmul($xsq, $scale) -> bdiv($fac, $scale);
4316              
4317 504         2156 $sin -> badd($term, $scale);
4318 504 100       1832 last if $term -> copy() -> babs() -> bcmp($tol) < 0;
4319             }
4320              
4321 52 100       361 $sin -> bneg() if $xsgn < 0;
4322              
4323             # Rounding parameters given as arguments currently don't override
4324             # instance variables, so accuracy (which is set in the computations
4325             # above) must be undefined before rounding. Fixme.
4326              
4327 52         137 $sin->{accuracy} = undef;
4328 52         250 $sin -> round(@params);
4329              
4330             # Compare the current approximation of sin(x) with the previous one,
4331             # and if they are identical, we're done.
4332              
4333 52 100       262 if (defined $sin_prev) {
4334 32 100       111 last if $sin -> bcmp($sin_prev) == 0;
4335             }
4336              
4337             # If the current approximation of sin(x) is different from the previous
4338             # approximation, double the scale (accuracy) and retry.
4339              
4340 32         100 $sin_prev = $sin;
4341 32         743 $scale *= 2;
4342             }
4343              
4344             # Assign the result to the invocand.
4345              
4346 20         270 %$x = %$sin;
4347              
4348 20 50       88 if ($fallback) {
4349             # clear a/p after round, since user did not request it
4350 0         0 $x->{accuracy} = undef;
4351 0         0 $x->{precision} = undef;
4352             }
4353              
4354             # Restore globals. We need to do it like this, because setting one
4355             # undefines the other.
4356              
4357 20 50       111 if (defined $ab) {
4358 0         0 $class -> accuracy($ab);
4359             } else {
4360 20         121 $class -> precision($pb);
4361             }
4362              
4363 20         99 $class -> upgrade($upg);
4364 20         76 $class -> downgrade($dng);
4365              
4366             # rounding has already been done
4367 20 50       64 $x -> _dng() if $x -> is_int();
4368 20         648 $x;
4369             }
4370              
4371             sub bcos {
4372             # Calculate a cosinus of x.
4373 36 50   36 1 687 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4374              
4375             # Taylor: x^2 x^4 x^6 x^8
4376             # cos = 1 - --- + --- - --- + --- ...
4377             # 2! 4! 6! 8!
4378              
4379             # Don't modify constant (read-only) objects.
4380              
4381 36 50       147 return $x if $x -> modify('bcos');
4382              
4383             # we need to limit the accuracy to protect against overflow
4384 36         73 my $fallback = 0;
4385 36         72 my ($scale, @params);
4386 36         160 ($x, @params) = $x->_find_round_parameters(@r);
4387              
4388             # error in _find_round_parameters?
4389 36 100       131 return $x if $x -> is_nan();
4390 32 100       194 return $x -> bnan() if $x -> is_inf();
4391 24 100       112 return $x -> bone(@r) if $x -> is_zero();
4392              
4393             # no rounding at all, so must use fallback
4394 16 50       52 if (scalar @params == 0) {
4395             # simulate old behaviour
4396 0         0 $params[0] = $class -> div_scale(); # and round to it as accuracy
4397 0         0 $params[1] = undef; # disable P
4398 0         0 $scale = $params[0] + 4; # at least four more for proper round
4399 0         0 $params[2] = $r[2]; # round mode by caller or undef
4400 0         0 $fallback = 1; # to clear a/p afterwards
4401             } else {
4402             # the 4 below is empirical, and there might be cases where it is not
4403             # enough...
4404 16   33     57 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
4405             }
4406              
4407             # When user set globals, they would interfere with our calculation, so
4408             # disable them and later re-enable them.
4409              
4410 16         81 my $ab = $class -> accuracy();
4411 16         47 my $pb = $class -> precision();
4412 16         51 $class -> accuracy(undef);
4413 16         54 $class -> precision(undef);
4414              
4415             # Disabling upgrading and downgrading is no longer necessary to avoid an
4416             # infinite recursion, but it avoids unnecessary upgrading and downgrading
4417             # in the intermediate computations.
4418              
4419 16         46 my $upg = $class -> upgrade();
4420 16         48 my $dng = $class -> downgrade();
4421 16         51 $class -> upgrade(undef);
4422 16         47 $class -> downgrade(undef);
4423              
4424             # We also need to disable any set A or P on $x (_find_round_parameters took
4425             # them already into account), since these would interfere, too.
4426              
4427 16         64 $x->{accuracy} = undef;
4428 16         58 $x->{precision} = undef;
4429              
4430 16         111 my $over = $x * $x; # X ^ 2
4431 16         64 my $x2 = $over -> copy(); # X ^ 2; difference between terms
4432 16         29 my $sign = 1; # start with -=
4433 16         51 my $below = $class -> new(2);
4434 16         69 my $factorial = $class -> new(3);
4435 16         108 $x -> bone();
4436 16         35 $x->{accuracy} = undef;
4437 16         31 $x->{precision} = undef;
4438              
4439 16         70 my $limit = $class -> new("1E-". ($scale-1));
4440             #my $steps = 0;
4441 16         80 while (3 < 5) {
4442             # we calculate the next term, and add it to the last
4443             # when the next term is below our limit, it won't affect the outcome
4444             # anymore, so we stop:
4445 156         532 my $next = $over -> copy() -> bdiv($below, $scale);
4446 156 100       499 last if $next -> bacmp($limit) <= 0;
4447              
4448 140 100       345 if ($sign == 0) {
4449 68         217 $x -> badd($next);
4450             } else {
4451 72         263 $x -> bsub($next);
4452             }
4453 140         229 $sign = 1-$sign; # alternate
4454             # calculate things for the next term
4455 140         428 $over -> bmul($x2); # $x*$x
4456 140         448 $below -> bmul($factorial); # n*(n+1)
4457 140         510 $factorial -> binc();
4458 140         497 $below -> bmul($factorial); # n*(n+1)
4459 140         344 $factorial -> binc();
4460             }
4461              
4462             # shortcut to not run through _find_round_parameters again
4463 16 50       59 if (defined $params[0]) {
4464 16         157 $x -> bround($params[0], $params[2]); # then round accordingly
4465             } else {
4466 0         0 $x -> bfround($params[1], $params[2]); # then round accordingly
4467             }
4468 16 50       57 if ($fallback) {
4469             # clear a/p after round, since user did not request it
4470 0         0 $x->{accuracy} = undef;
4471 0         0 $x->{precision} = undef;
4472             }
4473              
4474             # Restore globals. We need to do it like this, because setting one
4475             # undefines the other.
4476              
4477 16 50       42 if (defined $ab) {
4478 0         0 $class -> accuracy($ab);
4479             } else {
4480 16         66 $class -> precision($pb);
4481             }
4482              
4483 16         69 $class -> upgrade($upg);
4484 16         58 $class -> downgrade($dng);
4485              
4486 16         93 $x -> round(@r);
4487 16 50       47 $x -> _dng() if $x -> is_int();
4488 16         485 $x;
4489             }
4490              
4491             sub batan {
4492             # Calculate a arcus tangens of x.
4493 175 50   175 1 2127 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4494              
4495             # taylor: x^3 x^5 x^7 x^9
4496             # atan = x - --- + --- - --- + --- ...
4497             # 3 5 7 9
4498              
4499             # Don't modify constant (read-only) objects.
4500              
4501 175 50       939 return $x if $x -> modify('batan');
4502              
4503 175 100       659 return $x -> bnan(@r) if $x -> is_nan();
4504              
4505             # We need to limit the accuracy to protect against overflow.
4506              
4507 171         390 my $fallback = 0;
4508 171         439 my ($scale, @params);
4509 171         691 ($x, @params) = $x->_find_round_parameters(@r);
4510              
4511             # Error in _find_round_parameters?
4512              
4513 171 50       709 return $x -> bnan(@r) if $x -> is_nan();
4514              
4515 171 100       834 if ($x->{sign} =~ /^[+-]inf\z/) {
4516             # +inf result is PI/2
4517             # -inf result is -PI/2
4518             # calculate PI/2
4519 16         88 my $pi = $class -> bpi(@r);
4520             # modify $x in place
4521 16         65 $x->{_m} = $pi->{_m};
4522 16         47 $x->{_e} = $pi->{_e};
4523 16         38 $x->{_es} = $pi->{_es};
4524             # -y => -PI/2, +y => PI/2
4525 16         57 $x->{sign} = substr($x->{sign}, 0, 1); # "+inf" => "+"
4526 16         64 $x -> {_m} = $LIB->_div($x->{_m}, $LIB->_new(2));
4527 16         213 return $x;
4528             }
4529              
4530 155 100       702 return $x -> bzero(@r) if $x -> is_zero();
4531              
4532             # no rounding at all, so must use fallback
4533 129 50       493 if (scalar @params == 0) {
4534             # simulate old behaviour
4535 0         0 $params[0] = $class -> div_scale(); # and round to it as accuracy
4536 0         0 $params[1] = undef; # disable P
4537 0         0 $scale = $params[0]+4; # at least four more for proper round
4538 0         0 $params[2] = $r[2]; # round mode by caller or undef
4539 0         0 $fallback = 1; # to clear a/p afterwards
4540             } else {
4541             # the 4 below is empirical, and there might be cases where it is not
4542             # enough...
4543 129   33     602 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
4544             }
4545              
4546             # 1 or -1 => PI/4
4547             # inlined is_one() && is_one('-')
4548 129 100 100     872 if ($LIB->_is_one($x->{_m}) && $LIB->_is_zero($x->{_e})) {
4549 27         552 my $pi = $class -> bpi($scale - 3);
4550             # modify $x in place
4551 27         119 $x->{_m} = $pi->{_m};
4552 27         95 $x->{_e} = $pi->{_e};
4553 27         87 $x->{_es} = $pi->{_es};
4554             # leave the sign of $x alone (+1 => +PI/4, -1 => -PI/4)
4555 27         175 $x->{_m} = $LIB->_div($x->{_m}, $LIB->_new(4));
4556 27         370 return $x;
4557             }
4558              
4559             # When user set globals, they would interfere with our calculation, so
4560             # disable them and later re-enable them.
4561              
4562 102         485 my $ab = $class -> accuracy();
4563 102         396 my $pb = $class -> precision();
4564 102         377 $class -> accuracy(undef);
4565 102         346 $class -> precision(undef);
4566              
4567             # Disable upgrading and downgrading.
4568              
4569 102         335 my $upg = $class -> upgrade();
4570 102         337 my $dng = $class -> downgrade();
4571 102         426 $class -> upgrade(undef);
4572 102         453 $class -> downgrade(undef);
4573              
4574             # We also need to disable any set A or P on $x (_find_round_parameters took
4575             # them already into account), since these would interfere, too.
4576              
4577 102         310 $x->{accuracy} = undef;
4578 102         414 $x->{precision} = undef;
4579              
4580             # This series is only valid if -1 < x < 1, so for other x we need to
4581             # calculate PI/2 - atan(1/x):
4582 102         262 my $pi = undef;
4583 102 100       373 if ($x -> bacmp($x -> copy() -> bone) >= 0) {
4584             # calculate PI/2
4585 40         242 $pi = $class -> bpi($scale - 3);
4586 40         217 $pi->{_m} = $LIB->_div($pi->{_m}, $LIB->_new(2));
4587             # calculate 1/$x:
4588 40         181 my $x_copy = $x -> copy();
4589             # modify $x in place
4590 40         171 $x -> bone();
4591 40         221 $x -> bdiv($x_copy, $scale);
4592             }
4593              
4594 102         512 my $fmul = 1;
4595 102         506 foreach (0 .. int($scale / 20)) {
4596 174         414 $fmul *= 2;
4597 174         684 $x -> bdiv($x -> copy() -> bmul($x) -> binc() -> bsqrt($scale + 4) -> binc(),
4598             $scale + 4);
4599             }
4600              
4601 102         638 my $over = $x * $x; # X ^ 2
4602 102         435 my $x2 = $over -> copy(); # X ^ 2; difference between terms
4603 102         428 $over -> bmul($x); # X ^ 3 as starting value
4604 102         231 my $sign = 1; # start with -=
4605 102         596 my $below = $class -> new(3);
4606 102         488 my $two = $class -> new(2);
4607 102         420 $x->{accuracy} = undef;
4608 102         240 $x->{precision} = undef;
4609              
4610 102         553 my $limit = $class -> new("1E-". ($scale-1));
4611             #my $steps = 0;
4612 102         379 while (1) {
4613             # We calculate the next term, and add it to the last. When the next
4614             # term is below our limit, it won't affect the outcome anymore, so we
4615             # stop:
4616 990         3382 my $next = $over -> copy() -> bdiv($below, $scale);
4617 990 100       3546 last if $next -> bacmp($limit) <= 0;
4618              
4619 888 100       2358 if ($sign == 0) {
4620 416         1636 $x -> badd($next);
4621             } else {
4622 472         1916 $x -> bsub($next);
4623             }
4624 888         1942 $sign = 1 - $sign; # alternatex
4625             # calculate things for the next term
4626 888         3434 $over -> bmul($x2); # $x*$x
4627 888         3270 $below -> badd($two); # n += 2
4628             }
4629 102         517 $x -> bmul($fmul);
4630              
4631 102 100       406 if (defined $pi) {
4632 40         157 my $x_copy = $x -> copy();
4633             # modify $x in place
4634 40         182 $x->{_m} = $pi->{_m};
4635 40         109 $x->{_e} = $pi->{_e};
4636 40         104 $x->{_es} = $pi->{_es};
4637             # PI/2 - $x
4638 40         155 $x -> bsub($x_copy);
4639             }
4640              
4641             # Shortcut to not run through _find_round_parameters again.
4642 102 50       383 if (defined $params[0]) {
4643 102         433 $x -> bround($params[0], $params[2]); # then round accordingly
4644             } else {
4645 0         0 $x -> bfround($params[1], $params[2]); # then round accordingly
4646             }
4647 102 50       357 if ($fallback) {
4648             # Clear a/p after round, since user did not request it.
4649 0         0 $x->{accuracy} = undef;
4650 0         0 $x->{precision} = undef;
4651             }
4652              
4653             # Restore globals. We need to do it like this, because setting one
4654             # undefines the other.
4655              
4656 102 50       333 if (defined $ab) {
4657 0         0 $class -> accuracy($ab);
4658             } else {
4659 102         525 $class -> precision($pb);
4660             }
4661              
4662 102         454 $class -> upgrade($upg);
4663 102         353 $class -> downgrade($dng);
4664              
4665 102 50 33     423 return $x -> _dng() if ($x -> is_int() ||
4666             $x -> is_inf());
4667 102         2495 $x;
4668             }
4669              
4670             sub batan2 {
4671             # $y -> batan2($x) returns the arcus tangens of $y / $x.
4672              
4673             # Set up parameters.
4674 213 50 33 213 1 4490 my ($class, $y, $x, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
4675             ? (ref($_[0]), @_)
4676             : objectify(2, @_);
4677              
4678             # Don't modify constant (read-only) objects.
4679              
4680 213 50       1184 return $y if $y -> modify('batan2');
4681              
4682             # Handle all NaN cases.
4683 213 100 100     828 return $y -> bnan() if $x -> is_nan() || $y -> is_nan();
4684              
4685             # We need to limit the accuracy to protect against overflow.
4686 201         525 my $fallback = 0;
4687 201         406 my ($scale, @params);
4688 201         966 ($y, @params) = $y -> _find_round_parameters(@r);
4689              
4690             # Error in _find_round_parameters?
4691 201 50       851 return $y if $y -> is_nan();
4692              
4693             # No rounding at all, so must use fallback.
4694 201 100       696 if (scalar @params == 0) {
4695             # Simulate old behaviour
4696 45         207 $params[0] = $class -> div_scale(); # and round to it as accuracy
4697 45         79 $params[1] = undef; # disable P
4698 45         121 $scale = $params[0] + 4; # at least four more for proper round
4699 45         87 $params[2] = $r[2]; # round mode by caller or undef
4700 45         94 $fallback = 1; # to clear a/p afterwards
4701             } else {
4702             # The 4 below is empirical, and there might be cases where it is not
4703             # enough ...
4704 156   33     634 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
4705             }
4706              
4707 201 100       640 if ($x -> is_inf("+")) { # x = inf
    100          
    100          
    100          
4708 20 100       87 if ($y -> is_inf("+")) { # y = inf
    100          
4709 4         21 $y -> bpi($scale) -> bmul("0.25"); # pi/4
4710             } elsif ($y -> is_inf("-")) { # y = -inf
4711 4         57 $y -> bpi($scale) -> bmul("-0.25"); # -pi/4
4712             } else { # -inf < y < inf
4713 12         84 return $y -> bzero(@r); # 0
4714             }
4715             } elsif ($x -> is_inf("-")) { # x = -inf
4716 20 100       70 if ($y -> is_inf("+")) { # y = inf
    100          
    100          
4717 4         43 $y -> bpi($scale) -> bmul("0.75"); # 3/4 pi
4718             } elsif ($y -> is_inf("-")) { # y = -inf
4719 4         25 $y -> bpi($scale) -> bmul("-0.75"); # -3/4 pi
4720             } elsif ($y >= 0) { # y >= 0
4721 8         44 $y -> bpi($scale); # pi
4722             } else { # y < 0
4723 4         24 $y -> bpi($scale) -> bneg(); # -pi
4724             }
4725             } elsif ($x > 0) { # 0 < x < inf
4726 87 100       334 if ($y -> is_inf("+")) { # y = inf
    100          
4727 4         23 $y -> bpi($scale) -> bmul("0.5"); # pi/2
4728             } elsif ($y -> is_inf("-")) { # y = -inf
4729 4         21 $y -> bpi($scale) -> bmul("-0.5"); # -pi/2
4730             } else { # -inf < y < inf
4731 79         512 $y -> bdiv($x, $scale) -> batan($scale); # atan(y/x)
4732             }
4733             } elsif ($x < 0) { # -inf < x < 0
4734 20         155 my $pi = $class -> bpi($scale);
4735 20 100       94 if ($y >= 0) { # y >= 0
4736 12         83 $y -> bdiv($x, $scale) -> batan() # atan(y/x) + pi
4737             -> badd($pi);
4738             } else { # y < 0
4739 8         61 $y -> bdiv($x, $scale) -> batan() # atan(y/x) - pi
4740             -> bsub($pi);
4741             }
4742             } else { # x = 0
4743 54 100       191 if ($y > 0) { # y > 0
    100          
4744 25         130 $y -> bpi($scale) -> bmul("0.5"); # pi/2
4745             } elsif ($y < 0) { # y < 0
4746 22         125 $y -> bpi($scale) -> bmul("-0.5"); # -pi/2
4747             } else { # y = 0
4748 7         48 return $y -> bzero(@r); # 0
4749             }
4750             }
4751              
4752 182         971 $y -> round(@r);
4753              
4754 182 100       607 if ($fallback) {
4755 42         139 $y->{accuracy} = undef;
4756 42         130 $y->{precision} = undef;
4757             }
4758              
4759 182         3448 return $y;
4760             }
4761              
4762             sub bfac {
4763             # (BFLOAT or num_str, BFLOAT or num_str) return BFLOAT
4764             # compute factorial number, modifies first argument
4765              
4766             # set up parameters
4767 80 50   80 1 1217 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4768              
4769             # Don't modify constant (read-only) objects.
4770              
4771 80 50       397 return $x if $x -> modify('bfac');
4772              
4773 80 100 100     349 return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf("-");
4774 72 100       871 return $x -> binf("+", @r) if $x -> is_inf("+");
4775 68 100 66     478 return $x -> bnan(@r) if $x -> is_neg() || !$x -> is_int();
4776 64 100 100     241 return $x -> bone(@r) if $x -> is_zero() || $x -> is_one();
4777              
4778 56 50 33     196 if ($x -> is_neg() || !$x -> is_int()) {
4779 0 0       0 return $x -> _upg() -> bfac(@r) if $class -> upgrade();
4780 0         0 return $x -> bnan(@r);
4781             }
4782              
4783 56 100       221 if (! $LIB->_is_zero($x->{_e})) {
4784 8         56 $x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10); # change 12e1 to 120e0
4785 8         62 $x->{_e} = $LIB->_zero(); # normalize
4786 8         24 $x->{_es} = '+';
4787             }
4788 56         292 $x->{_m} = $LIB->_fac($x->{_m}); # calculate factorial
4789              
4790 56         239 $x -> bnorm(); # norm again
4791 56         216 $x -> round(@r);
4792 56         185 $x -> _dng();
4793 56         817 return $x;
4794             }
4795              
4796             sub bdfac {
4797             # compute double factorial, modify $x in place
4798 72 50   72 1 1061 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4799              
4800             # Don't modify constant (read-only) objects.
4801              
4802 72 50       343 return $x if $x -> modify('bdfac');
4803              
4804 72 100 100     292 return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf("-");
4805 64 100       200 return $x -> binf("+", @r) if $x -> is_inf("+");
4806 60 100 66     307 return $x -> bnan(@r) if $x <= -2 || !$x -> is_int();
4807 56 100       173 return $x -> bone(@r) if $x <= 1;
4808              
4809 44 50       440 croak("bdfac() requires a newer version of the $LIB library.")
4810             unless $LIB -> can('_dfac');
4811              
4812 44 100       180 if (! $LIB->_is_zero($x->{_e})) {
4813 4         34 $x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10); # change 12e1 to 120e0
4814 4         20 $x->{_e} = $LIB->_zero(); # normalize
4815 4         10 $x->{_es} = '+';
4816             }
4817 44         228 $x->{_m} = $LIB->_dfac($x->{_m}); # calculate factorial
4818              
4819 44         219 $x -> bnorm(); # norm again
4820 44         198 $x -> round(@r);
4821 44         136 $x -> _dng();
4822 44         684 return $x;
4823             }
4824              
4825             sub btfac {
4826             # compute triple factorial
4827              
4828             # set up parameters
4829 76 50   76 1 1094 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4830              
4831             # Don't modify constant (read-only) objects.
4832              
4833 76 50       359 return $x if $x -> modify('btfac');
4834              
4835 76 100 100     365 return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf("-");
4836 68 100       209 return $x -> binf("+", @r) if $x -> is_inf("+");
4837              
4838 64 100 66     288 if ($x <= -3 || !$x -> is_int()) {
4839 4 50       28 return $x -> _upg() -> btfac(@r) if $class -> upgrade();
4840 4         22 return $x -> bnan(@r);
4841             }
4842              
4843 60         206 my $k = $class -> new("3");
4844 60 50       254 return $x -> bnan(@r) if $x <= -$k;
4845              
4846 60         429 my $one = $class -> bone();
4847 60 100       233 return $x -> bone(@r) if $x <= $one;
4848              
4849 44         142 my $f = $x -> copy();
4850 44         179 while ($f -> bsub($k) > $one) {
4851 60         219 $x = $x -> bmul($f);
4852             }
4853              
4854 44         189 $x -> round(@r);
4855 44         139 $x -> _dng();
4856 44         816 return $x;
4857             }
4858              
4859             sub bmfac {
4860 364 50 33 364 1 7509 my ($class, $x, $k, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
4861             ? (ref($_[0]), @_)
4862             : objectify(2, @_);
4863              
4864             # Don't modify constant (read-only) objects.
4865              
4866 364 50       1695 return $x if $x -> modify('bmfac');
4867              
4868 364 100 100     1402 return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf("-") ||
      100        
4869             !$k -> is_pos();
4870 308 100       942 return $x -> binf("+", @r) if $x -> is_inf("+");
4871 288 100       814 return $x -> bround(@r) if $k -> is_inf("+");
4872 284 100 66     952 return $x -> bnan(@r) if !$x -> is_int() || !$k -> is_int();
4873 280 100 66     1203 return $x -> bnan(@r) if $k < 1 || $x <= -$k;
4874              
4875 260         2012 my $one = $class -> bone();
4876 260 100       899 return $x -> bone(@r) if $x <= $one;
4877              
4878 180         632 my $f = $x -> copy();
4879 180         737 while ($f -> bsub($k) > $one) {
4880 284         1177 $x -> bmul($f);
4881             }
4882              
4883 180         819 $x -> round(@r);
4884 180         654 $x -> _dng();
4885 180         3749 return $x;
4886             }
4887              
4888             sub bfib {
4889             # compute Fibonacci number(s)
4890 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4891              
4892 0 0       0 croak("bfib() requires a newer version of the $LIB library.")
4893             unless $LIB -> can('_fib');
4894              
4895             # Don't modify constant (read-only) objects.
4896              
4897 0 0       0 return $x if $x -> modify('bfib');
4898              
4899             # List context.
4900              
4901 0 0       0 if (wantarray) {
4902 0 0       0 croak("bfib() can't return an infinitely long list of numbers")
4903             if $x -> is_inf();
4904              
4905 0 0 0     0 return if $x -> is_nan() || !$x -> is_int();
4906              
4907             # The following places a limit on how large $x can be. Should this
4908             # limit be removed? XXX
4909              
4910 0         0 my $n = $x -> numify();
4911              
4912 0         0 my @y;
4913             {
4914 0         0 $y[0] = $x -> copy() -> babs();
  0         0  
4915 0         0 $y[0]{_m} = $LIB -> _zero();
4916 0         0 $y[0]{_e} = $LIB -> _zero();
4917 0 0       0 last if $n == 0;
4918              
4919 0         0 $y[1] = $y[0] -> copy();
4920 0         0 $y[1]{_m} = $LIB -> _one();
4921 0         0 $y[1]{_e} = $LIB -> _zero();
4922 0 0       0 last if $n == 1;
4923              
4924 0         0 for (my $i = 2 ; $i <= abs($n) ; $i++) {
4925 0         0 $y[$i] = $y[$i - 1] -> copy();
4926             $y[$i]{_m} = $LIB -> _add($LIB -> _copy($y[$i - 1]{_m}),
4927 0         0 $y[$i - 2]{_m});
4928             }
4929              
4930             # If negative, insert sign as appropriate.
4931              
4932 0 0       0 if ($x -> is_neg()) {
4933 0         0 for (my $i = 2 ; $i <= $#y ; $i += 2) {
4934 0         0 $y[$i]{sign} = '-';
4935             }
4936             }
4937              
4938             # The last element in the array is the invocand.
4939              
4940 0         0 $x->{sign} = $y[-1]{sign};
4941 0         0 $x->{_m} = $y[-1]{_m};
4942 0         0 $x->{_es} = $y[-1]{_es};
4943 0         0 $x->{_e} = $y[-1]{_e};
4944 0         0 $y[-1] = $x;
4945             }
4946              
4947 0         0 for (@y) {
4948 0         0 $_ -> bnorm();
4949 0         0 $_ -> round(@r);
4950             }
4951              
4952 0         0 return @y;
4953             }
4954              
4955             # Scalar context.
4956              
4957             else {
4958 0 0       0 return $x if $x -> is_inf('+');
4959 0 0 0     0 return $x -> bnan() if $x -> is_nan() || $x -> is_inf('-');
4960              
4961 0 0       0 if ($x -> is_int()) {
4962              
4963 0 0 0     0 $x->{sign} = $x -> is_neg() && $x -> is_even() ? '-' : '+';
4964 0         0 $x->{_m} = $LIB -> _lsft($x->{_m}, $x -> {_e}, 10);
4965 0         0 $x->{_e} = $LIB -> _zero();
4966 0         0 $x->{_m} = $LIB -> _fib($x->{_m});
4967 0         0 $x -> bnorm();
4968             }
4969              
4970 0         0 return $x -> round(@r);
4971             }
4972             }
4973              
4974             sub blucas {
4975             # compute Lucas number(s)
4976 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
4977              
4978 0 0       0 croak("blucas() requires a newer version of the $LIB library.")
4979             unless $LIB -> can('_lucas');
4980              
4981             # Don't modify constant (read-only) objects.
4982              
4983 0 0       0 return $x if $x -> modify('blucas');
4984              
4985             # List context.
4986              
4987 0 0       0 if (wantarray) {
4988 0 0       0 croak("blucas() can't return an infinitely long list of numbers")
4989             if $x -> is_inf();
4990              
4991 0 0 0     0 return if $x -> is_nan() || !$x -> is_int();
4992              
4993             # The following places a limit on how large $x can be. Should this
4994             # limit be removed? XXX
4995              
4996 0         0 my $n = $x -> numify();
4997              
4998 0         0 my @y;
4999             {
5000 0         0 $y[0] = $x -> copy() -> babs();
  0         0  
5001 0         0 $y[0]{_m} = $LIB -> _two();
5002 0         0 $y[0]{_e} = $LIB -> _zero();
5003 0 0       0 last if $n == 0;
5004              
5005 0         0 $y[1] = $y[0] -> copy();
5006 0         0 $y[1]{_m} = $LIB -> _one();
5007 0         0 $y[1]{_e} = $LIB -> _zero();
5008 0 0       0 last if $n == 1;
5009              
5010 0         0 for (my $i = 2 ; $i <= abs($n) ; $i++) {
5011 0         0 $y[$i] = $y[$i - 1] -> copy();
5012             $y[$i]{_m} = $LIB -> _add($LIB -> _copy($y[$i - 1]{_m}),
5013 0         0 $y[$i - 2]{_m});
5014             }
5015              
5016             # If negative, insert sign as appropriate.
5017              
5018 0 0       0 if ($x -> is_neg()) {
5019 0         0 for (my $i = 2 ; $i <= $#y ; $i += 2) {
5020 0         0 $y[$i]{sign} = '-';
5021             }
5022             }
5023              
5024             # The last element in the array is the invocand.
5025              
5026 0         0 $x->{sign} = $y[-1]{sign};
5027 0         0 $x->{_m} = $y[-1]{_m};
5028 0         0 $x->{_es} = $y[-1]{_es};
5029 0         0 $x->{_e} = $y[-1]{_e};
5030 0         0 $y[-1] = $x;
5031             }
5032              
5033 0         0 for (@y) {
5034 0         0 $_ -> bnorm();
5035 0         0 $_ -> round(@r);
5036             }
5037              
5038 0         0 return @y;
5039             }
5040              
5041             # Scalar context.
5042              
5043             else {
5044 0 0       0 return $x if $x -> is_inf('+');
5045 0 0 0     0 return $x -> bnan() if $x -> is_nan() || $x -> is_inf('-');
5046              
5047 0 0       0 if ($x -> is_int()) {
5048              
5049 0 0 0     0 $x->{sign} = $x -> is_neg() && $x -> is_even() ? '-' : '+';
5050 0         0 $x->{_m} = $LIB -> _lsft($x->{_m}, $x -> {_e}, 10);
5051 0         0 $x->{_e} = $LIB -> _zero();
5052 0         0 $x->{_m} = $LIB -> _lucas($x->{_m});
5053 0         0 $x -> bnorm();
5054             }
5055              
5056 0         0 return $x -> round(@r);
5057             }
5058             }
5059              
5060             sub blsft {
5061             # shift left by $y in base $b, i.e., multiply by $b ** $y
5062              
5063             # set up parameters
5064 33 50 66 33 1 742 my ($class, $x, $y, $b, @r)
5065             = ref($_[0]) && ref($_[0]) eq ref($_[1]) && ref($_[1]) eq ref($_[2])
5066             ? (ref($_[0]), @_)
5067             : objectify(2, @_);
5068              
5069             # Don't modify constant (read-only) objects.
5070              
5071 33 50       182 return $x if $x -> modify('blsft');
5072              
5073 33 100 66     117 return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
5074              
5075 29 50       93 $b = 2 if !defined $b;
5076 29 50 33     164 $b = $class -> new($b)
5077             unless defined(blessed($b)) && $b -> isa(__PACKAGE__);
5078 29 50       142 return $x -> bnan(@r) if $b -> is_nan();
5079              
5080             # There needs to be more checking for special cases here. Fixme!
5081              
5082             # shift by a negative amount?
5083 29 50       217 return $x -> brsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
5084              
5085 29         177 $x = $x -> bmul($b -> bpow($y), $r[0], $r[1], $r[2], $y);
5086              
5087 29         173 $x -> round(@r);
5088 29 0 33     77 $x -> _dng() if ($x -> is_int() ||
      33        
5089             $x -> is_inf() ||
5090             $x -> is_nan());
5091 29         462 return $x;
5092             }
5093              
5094             sub brsft {
5095             # shift right by $y in base $b, i.e., divide by $b ** $y
5096              
5097             # set up parameters
5098 64 50 66 64 1 1249 my ($class, $x, $y, $b, @r)
5099             = ref($_[0]) && ref($_[0]) eq ref($_[1]) && ref($_[1]) eq ref($_[2])
5100             ? (ref($_[0]), @_)
5101             : objectify(2, @_);
5102              
5103             # Don't modify constant (read-only) objects.
5104              
5105 64 50       345 return $x if $x -> modify('brsft');
5106              
5107 64 100 66     251 return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
5108              
5109             # There needs to be more checking for special cases here. Fixme!
5110              
5111 60 100       239 $b = 2 if !defined $b;
5112 60 50 66     366 $b = $class -> new($b)
5113             unless defined(blessed($b)) && $b -> isa(__PACKAGE__);
5114 60 50       273 return $x -> bnan(@r) if $b -> is_nan();
5115              
5116             # shift by a negative amount?
5117 60 50       288 return $x -> blsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
5118              
5119             # call bdiv()
5120 60         296 $x = $x -> bdiv($b -> bpow($y), $r[0], $r[1], $r[2], $y);
5121              
5122 60         364 $x -> round(@r);
5123 60 50 66     197 $x -> _dng() if ($x -> is_int() ||
      66        
5124             $x -> is_inf() ||
5125             $x -> is_nan());
5126 60         959 return $x;
5127             }
5128              
5129             ###############################################################################
5130             # Bitwise methods
5131             ###############################################################################
5132              
5133             # Bitwise left shift.
5134              
5135             sub bblsft {
5136             # We don't call objectify(), because the bitwise methods should not
5137             # upgrade, even when upgrading is enabled.
5138              
5139 8 50   8 1 48 my ($class, $x, $y, @r) = ref($_[0]) ? (ref($_[0]), @_) : @_;
5140              
5141             # Don't modify constant (read-only) objects.
5142              
5143 8 50 33     258 return $x if ref($x) && $x -> modify('bblsft');
5144              
5145             # Let Math::BigInt do the job.
5146              
5147 8         82 my $xint = Math::BigInt -> bblsft($x, $y, @r);
5148              
5149             # Temporarily disable downgrading.
5150              
5151 8         33 my $dng = $class -> downgrade();
5152 8         30 $class -> downgrade(undef);
5153              
5154             # convert to our class without downgrading.
5155              
5156 8         26 my $xflt = $class -> new($xint);
5157              
5158             # Reset downgrading.
5159              
5160 8         49 $class -> downgrade($dng);
5161              
5162             # If we are called as a class method, the first operand might not be an
5163             # object of this class, so check.
5164              
5165 8 50 33     41 if (defined(blessed($x)) && $x -> isa(__PACKAGE__)) {
5166 8         39 $x -> {sign} = $xflt -> {sign};
5167 8         29 $x -> {_m} = $xflt -> {_m};
5168 8         19 $x -> {_es} = $xflt -> {_es};
5169 8         60 $x -> {_e} = $xflt -> {_e};
5170             } else {
5171 0         0 $x = $xflt;
5172             }
5173              
5174             # Now we might downgrade.
5175              
5176 8         37 $x -> round(@r);
5177 8         30 $x -> _dng();
5178 8         76 return $x;
5179             }
5180              
5181             # Bitwise right shift.
5182              
5183             sub bbrsft {
5184             # We don't call objectify(), because the bitwise methods should not
5185             # upgrade, even when upgrading is enabled.
5186              
5187 8 50   8 1 47 my ($class, $x, $y, @r) = ref($_[0]) ? (ref($_[0]), @_) : @_;
5188              
5189             # Don't modify constant (read-only) objects.
5190              
5191 8 50 33     69 return $x if ref($x) && $x -> modify('bbrsft');
5192              
5193             # Let Math::BigInt do the job.
5194              
5195 8         53 my $xint = Math::BigInt -> bbrsft($x, $y, @r);
5196              
5197             # Temporarily disable downgrading.
5198              
5199 8         47 my $dng = $class -> downgrade();
5200 8         25 $class -> downgrade(undef);
5201              
5202             # Convert to our class without downgrading.
5203              
5204 8         28 my $xflt = $class -> new($xint);
5205              
5206             # Reset downgrading.
5207              
5208 8         48 $class -> downgrade($dng);
5209              
5210             # If we are called as a class method, the first operand might not be an
5211             # object of this class, so check.
5212              
5213 8 50 33     42 if (defined(blessed($x)) && $x -> isa(__PACKAGE__)) {
5214 8         29 $x -> {sign} = $xflt -> {sign};
5215 8         29 $x -> {_m} = $xflt -> {_m};
5216 8         22 $x -> {_es} = $xflt -> {_es};
5217 8         24 $x -> {_e} = $xflt -> {_e};
5218             } else {
5219 0         0 $x = $xflt;
5220             }
5221              
5222             # Now we might downgrade.
5223              
5224 8         33 $x -> round(@r);
5225 8         31 $x -> _dng();
5226 8         103 return $x;
5227             }
5228              
5229             sub band {
5230 1 50 33 1 1 29 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
5231             ? (ref($_[0]), @_)
5232             : objectify(2, @_);
5233              
5234             # Don't modify constant (read-only) objects.
5235              
5236 1 50       7 return if $x -> modify('band');
5237              
5238             # If $x and/or $y is Inf or NaN, return NaN.
5239              
5240 1 50 33     5 return $x -> bnan(@r) if ($x -> is_nan() || $x -> is_inf() ||
      33        
      33        
5241             $y -> is_nan() || $y -> is_inf());
5242              
5243             # This should be implemented without converting to Math::BigInt. XXX
5244              
5245 1         6 my $xint = $x -> as_int(); # to Math::BigInt
5246 1         4 my $yint = $y -> as_int(); # to Math::BigInt
5247              
5248 1         27 $xint -> band($yint);
5249 1         5 $xint -> round(@r);
5250              
5251 1         4 my $xflt = $xint -> as_float();
5252 1         5 $x -> {sign} = $xflt -> {sign};
5253 1         5 $x -> {_m} = $xflt -> {_m};
5254 1         3 $x -> {_es} = $xflt -> {_es};
5255 1         2 $x -> {_e} = $xflt -> {_e};
5256              
5257 1         4 return $x -> _dng();
5258 0         0 return $x;
5259             }
5260              
5261             sub bior {
5262 1 50 33 1 1 19 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
5263             ? (ref($_[0]), @_)
5264             : objectify(2, @_);
5265              
5266             # Don't modify constant (read-only) objects.
5267              
5268 1 50       10 return if $x -> modify('bior');
5269              
5270             # If $x and/or $y is Inf or NaN, return NaN.
5271              
5272 1 50 33     6 return $x -> bnan(@r) if ($x -> is_nan() || $x -> is_inf() ||
      33        
      33        
5273             $y -> is_nan() || $y -> is_inf());
5274              
5275             # This should be implemented without converting to Math::BigInt. XXX
5276              
5277 1         6 my $xint = $x -> as_int(); # to Math::BigInt
5278 1         4 my $yint = $y -> as_int(); # to Math::BigInt
5279              
5280 1         7 $xint -> bior($yint);
5281 1         3 $xint -> round(@r);
5282              
5283 1         3 my $xflt = $xint -> as_float();
5284 1         3 $x -> {sign} = $xflt -> {sign};
5285 1         5 $x -> {_m} = $xflt -> {_m};
5286 1         2 $x -> {_es} = $xflt -> {_es};
5287 1         2 $x -> {_e} = $xflt -> {_e};
5288              
5289 1         4 return $x -> _dng();
5290 0         0 return $x;
5291             }
5292              
5293             sub bxor {
5294 1 50 33 1 1 20 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
5295             ? (ref($_[0]), @_)
5296             : objectify(2, @_);
5297              
5298             # Don't modify constant (read-only) objects.
5299              
5300 1 50       8 return if $x -> modify('bxor');
5301              
5302             # If $x and/or $y is Inf or NaN, return NaN.
5303              
5304 1 50 33     7 return $x -> bnan(@r) if ($x -> is_nan() || $x -> is_inf() ||
      33        
      33        
5305             $y -> is_nan() || $y -> is_inf());
5306              
5307             # This should be implemented without converting to Math::BigInt. XXX
5308              
5309 1         8 my $xint = $x -> as_int(); # to Math::BigInt
5310 1         7 my $yint = $y -> as_int(); # to Math::BigInt
5311              
5312 1         39 $xint -> bxor($yint);
5313 1         6 $xint -> round(@r);
5314              
5315 1         6 my $xflt = $xint -> as_float();
5316 1         7 $x -> {sign} = $xflt -> {sign};
5317 1         7 $x -> {_m} = $xflt -> {_m};
5318 1         4 $x -> {_es} = $xflt -> {_es};
5319 1         5 $x -> {_e} = $xflt -> {_e};
5320              
5321 1         5 return $x -> _dng();
5322 0         0 return $x;
5323             }
5324              
5325             sub bnot {
5326 4 50   4 1 17 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5327              
5328             # Don't modify constant (read-only) objects.
5329              
5330 4 50       18 return if $x -> modify('bnot');
5331              
5332 4 50       16 return $x -> bnan(@r) if $x -> is_nan();
5333              
5334             # This should be implemented without converting to Math::BigInt. XXX
5335              
5336 4         17 my $xint = $x -> as_int(); # to Math::BigInt
5337              
5338 4         9 $xint -> bnot();
5339 4         12 $xint -> round(@r);
5340              
5341 4         9 my $xflt = $xint -> as_float();
5342 4         10 $x -> {sign} = $xflt -> {sign};
5343 4         9 $x -> {_m} = $xflt -> {_m};
5344 4         9 $x -> {_es} = $xflt -> {_es};
5345 4         6 $x -> {_e} = $xflt -> {_e};
5346              
5347 4         12 return $x -> _dng();
5348 0         0 return $x;
5349             }
5350              
5351             ###############################################################################
5352             # Rounding methods
5353             ###############################################################################
5354              
5355             sub bround {
5356             # accuracy: preserve $N digits, and overwrite the rest with 0's
5357              
5358 47907 50   47907 1 174155 my ($class, $x, @a) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5359              
5360 47907 100 100     141377 if (($a[0] || 0) < 0) {
5361 3         907 croak('bround() needs positive accuracy');
5362             }
5363              
5364             # Don't modify constant (read-only) objects.
5365              
5366 47904 50       152029 return $x if $x -> modify('bround');
5367              
5368 47904         139386 my ($scale, $mode) = $x->_scale_a(@a);
5369 47904 100       115314 if (!defined $scale) { # no-op
5370 4569 100 100     10366 $x -> _dng() if ($x -> is_int() ||
      100        
5371             $x -> is_inf() ||
5372             $x -> is_nan());
5373 4569         15933 return $x;
5374             }
5375              
5376             # Scale is now either $x->{accuracy}, $accuracy, or the input argument.
5377             # Test whether $x already has lower accuracy, do nothing in this case but
5378             # do round if the accuracy is the same, since a math operation might want
5379             # to round a number with A=5 to 5 digits afterwards again
5380              
5381 43335 100 100     156990 if (defined $x->{accuracy} && $x->{accuracy} < $scale) {
5382 44 50 66     150 $x -> _dng() if ($x -> is_int() ||
      66        
5383             $x -> is_inf() ||
5384             $x -> is_nan());
5385 44         167 return $x;
5386             }
5387              
5388             # scale < 0 makes no sense
5389             # scale == 0 => keep all digits
5390             # never round a +-inf, NaN
5391              
5392 43291 100 66     219851 if ($scale <= 0 || $x->{sign} !~ /^[+-]$/) {
5393 12 50 66     39 $x -> _dng() if ($x -> is_int() ||
      66        
5394             $x -> is_inf() ||
5395             $x -> is_nan());
5396 12         139 return $x;
5397             }
5398              
5399             # 1: never round a 0
5400             # 2: if we should keep more digits than the mantissa has, do nothing
5401 43279 100 100     152398 if ($x -> is_zero() || $LIB->_len($x->{_m}) <= $scale) {
5402 15285 100 100     61172 $x->{accuracy} = $scale if !defined $x->{accuracy} || $x->{accuracy} > $scale;
5403 15285 100       36462 $x -> _dng() if $x -> is_int();
5404 15285         53989 return $x;
5405             }
5406              
5407             # pass sign to bround for '+inf' and '-inf' rounding modes
5408 27994         143445 my $m = bless { sign => $x->{sign}, value => $x->{_m} }, 'Math::BigInt';
5409              
5410 27994         98746 $m = $m -> bround($scale, $mode); # round mantissa
5411 27994         105964 $x->{_m} = $m->{value}; # get our mantissa back
5412 27994         59304 $x->{accuracy} = $scale; # remember rounding
5413 27994         53180 $x->{precision} = undef; # and clear P
5414              
5415             # bnorm() downgrades if necessary, so no need to check whether to
5416             # downgrade.
5417 27994         82396 $x -> bnorm(); # del trailing zeros gen. by bround()
5418             }
5419              
5420             sub bfround {
5421             # precision: round to the $Nth digit left (+$n) or right (-$n) from the '.'
5422             # $n == 0 means round to integer
5423             # expects and returns normalized numbers!
5424              
5425 756 50   756 1 13868 my ($class, $x, @p) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5426              
5427             # Don't modify constant (read-only) objects.
5428              
5429 756 50       3424 return $x if $x -> modify('bfround'); # no-op
5430              
5431 756         3084 my ($scale, $mode) = $x->_scale_p(@p);
5432 756 100       2361 if (!defined $scale) {
5433 4 50 100     10 $x -> _dng() if ($x -> is_int() ||
      66        
5434             $x -> is_inf() ||
5435             $x -> is_nan());
5436 4         11 return $x;
5437             }
5438              
5439             # never round a 0, +-inf, NaN
5440              
5441 752 100       2677 if ($x -> is_zero()) {
5442 21 50 33     143 $x->{precision} = $scale if !defined $x->{precision} || $x->{precision} < $scale; # -3 < -2
5443 21 0 33     74 $x -> _dng() if ($x -> is_int() ||
      33        
5444             $x -> is_inf() ||
5445             $x -> is_nan());
5446 21         116 return $x;
5447             }
5448              
5449 731 100       3623 if ($x->{sign} !~ /^[+-]$/) {
5450 12 50 66     53 $x -> _dng() if ($x -> is_int() ||
      66        
5451             $x -> is_inf() ||
5452             $x -> is_nan());
5453 12         178 return $x;
5454             }
5455              
5456             # don't round if x already has lower precision
5457 719 50 100     2481 if (defined $x->{precision} && $x->{precision} < 0 && $scale < $x->{precision}) {
      66        
5458 0 0 0     0 $x -> _dng() if ($x -> is_int() ||
      0        
5459             $x -> is_inf() ||
5460             $x -> is_nan());
5461 0         0 return $x;
5462             }
5463              
5464 719         1775 $x->{precision} = $scale; # remember round in any case
5465 719         3051 $x->{accuracy} = undef; # and clear A
5466 719 100       1929 if ($scale < 0) {
5467             # round right from the '.'
5468              
5469 551 100       1696 if ($x->{_es} eq '+') { # e >= 0 => nothing to round
5470 37 0 33     128 $x -> _dng() if ($x -> is_int() ||
      33        
5471             $x -> is_inf() ||
5472             $x -> is_nan());
5473 37         175 return $x;
5474             }
5475              
5476 514         942 $scale = -$scale; # positive for simplicity
5477 514         2410 my $len = $LIB->_len($x->{_m}); # length of mantissa
5478              
5479             # the following poses a restriction on _e, but if _e is bigger than a
5480             # scalar, you got other problems (memory etc) anyway
5481 514         2252 my $dad = -(0+ ($x->{_es}.$LIB->_num($x->{_e}))); # digits after dot
5482 514         1006 my $zad = 0; # zeros after dot
5483 514 100       1334 $zad = $dad - $len if (-$dad < -$len); # for 0.00..00xxx style
5484              
5485             # print "scale $scale dad $dad zad $zad len $len\n";
5486             # number bsstr len zad dad
5487             # 0.123 123e-3 3 0 3
5488             # 0.0123 123e-4 3 1 4
5489             # 0.001 1e-3 1 2 3
5490             # 1.23 123e-2 3 0 2
5491             # 1.2345 12345e-4 5 0 4
5492              
5493             # do not round after/right of the $dad
5494              
5495 514 100       1328 if ($scale > $dad) { # 0.123, scale >= 3 => exit
5496 47 50 33     202 $x -> _dng() if ($x -> is_int() ||
      33        
5497             $x -> is_inf() ||
5498             $x -> is_nan());
5499 47         599 return $x;
5500             }
5501              
5502             # round to zero if rounding inside the $zad, but not for last zero like:
5503             # 0.0065, scale -2, round last '0' with following '65' (scale == zad
5504             # case)
5505 467 100       1483 if ($scale < $zad) {
5506 40 50 33     147 $x -> _dng() if ($x -> is_int() ||
      33        
5507             $x -> is_inf() ||
5508             $x -> is_nan());
5509 40         225 return $x -> bzero();
5510             }
5511              
5512 427 100       1294 if ($scale == $zad) { # for 0.006, scale -3 and trunc
5513 41         140 $scale = -$len;
5514             } else {
5515             # adjust round-point to be inside mantissa
5516 386 100       1040 if ($zad != 0) {
5517 78         208 $scale = $scale-$zad;
5518             } else {
5519 308         557 my $dbd = $len - $dad;
5520 308 50       851 $dbd = 0 if $dbd < 0; # digits before dot
5521 308         657 $scale = $dbd+$scale;
5522             }
5523             }
5524             } else {
5525             # round left from the '.'
5526              
5527             # 123 => 100 means length(123) = 3 - $scale (2) => 1
5528              
5529 168         768 my $dbt = $LIB->_len($x->{_m});
5530             # digits before dot
5531 168         872 my $dbd = $dbt + ($x->{_es} . $LIB->_num($x->{_e}));
5532             # should be the same, so treat it as this
5533 168 100       1264 $scale = 1 if $scale == 0;
5534             # shortcut if already integer
5535 168 100 100     825 if ($scale == 1 && $dbt <= $dbd) {
5536 14 0 33     55 $x -> _dng() if ($x -> is_int() ||
      33        
5537             $x -> is_inf() ||
5538             $x -> is_nan());
5539 14         49 return $x;
5540             }
5541             # maximum digits before dot
5542 154         281 ++$dbd;
5543              
5544 154 100       622 if ($scale > $dbd) {
    100          
5545             # not enough digits before dot, so round to zero
5546 30         494 return $x -> bzero;
5547             } elsif ($scale == $dbd) {
5548             # maximum
5549 72         199 $scale = -$dbt;
5550             } else {
5551 52         116 $scale = $dbd - $scale;
5552             }
5553             }
5554              
5555             # pass sign to bround for rounding modes '+inf' and '-inf'
5556 551         3210 my $m = bless { sign => $x->{sign}, value => $x->{_m} }, 'Math::BigInt';
5557 551         2577 $m = $m -> bround($scale, $mode);
5558 551         1784 $x->{_m} = $m->{value}; # get our mantissa back
5559              
5560             # bnorm() downgrades if necessary, so no need to check whether to
5561             # downgrade.
5562 551         2318 $x -> bnorm();
5563             }
5564              
5565             sub bfloor {
5566             # round towards minus infinity
5567 106 50   106 1 1015 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5568              
5569             # Don't modify constant (read-only) objects.
5570              
5571 106 50       414 return $x if $x -> modify('bfloor');
5572              
5573 106 100       344 return $x -> bnan(@r) if $x -> is_nan();
5574              
5575 101 100       264 if ($x -> is_finite()) {
5576             # if $x has digits after dot, remove them
5577 92 100       320 if ($x->{_es} eq '-') {
5578 56         317 $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
5579 56         198 $x->{_e} = $LIB->_zero();
5580 56         133 $x->{_es} = '+';
5581             # increment if negative
5582 56 100       230 $x->{_m} = $LIB->_inc($x->{_m}) if $x->{sign} eq '-';
5583             }
5584             }
5585              
5586 101         393 $x -> round(@r);
5587 101         330 $x -> _dng();
5588 101         683 return $x;
5589             }
5590              
5591             sub bceil {
5592             # round towards plus infinity
5593 43 50   43 1 592 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5594              
5595             # Don't modify constant (read-only) objects.
5596              
5597 43 50       179 return $x if $x -> modify('bceil');
5598              
5599 43 100       159 return $x -> bnan(@r) if $x -> is_nan();
5600              
5601 38 100       113 if ($x -> is_finite()) {
5602             # if $x has digits after dot, remove them
5603 29 100       91 if ($x->{_es} eq '-') {
5604 17         154 $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
5605 17         67 $x->{_e} = $LIB->_zero();
5606 17         42 $x->{_es} = '+';
5607 17 100       59 if ($x->{sign} eq '+') {
5608 9         55 $x->{_m} = $LIB->_inc($x->{_m}); # increment if positive
5609             } else {
5610 8 100       41 $x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # avoid -0
5611             }
5612             }
5613             }
5614              
5615 38         188 $x -> round(@r);
5616 38         167 $x -> _dng();
5617 38         419 return $x;
5618             }
5619              
5620             sub bint {
5621             # round towards zero
5622 991 50   991 1 4254 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5623              
5624             # Don't modify constant (read-only) objects.
5625              
5626 991 50       3919 return $x if $x -> modify('bint');
5627              
5628 991 100       2915 return $x -> bnan(@r) if $x -> is_nan();
5629              
5630 986 100       2937 if ($x -> is_finite()) {
5631             # if $x has digits after the decimal point
5632 977 100       3173 if ($x->{_es} eq '-') {
5633 206         1122 $x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10); # remove frac part
5634 206         829 $x->{_e} = $LIB->_zero(); # truncate/normalize
5635 206         523 $x->{_es} = '+'; # abs e
5636 206 100       649 $x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # avoid -0
5637             }
5638             }
5639              
5640 986         3999 $x -> round(@r);
5641 986         3726 $x -> _dng();
5642 986         5290 return $x;
5643             }
5644              
5645             ###############################################################################
5646             # Other mathematical methods
5647             ###############################################################################
5648              
5649             sub bgcd {
5650             # GCD -- Euclid's algorithm, variant C (Knuth Vol 3, pg 341 ff)
5651              
5652             # Class::method(...) -> Class->method(...)
5653 121 100 66 121 1 4303 unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
      66        
5654             ($_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i &&
5655             $_[0] !~ /^(inf|nan)/i)))
5656             {
5657             #carp "Using ", (caller(0))[3], "() as a function is deprecated;",
5658             # " use is as a method instead";
5659 1         6 unshift @_, __PACKAGE__;
5660             }
5661              
5662 121         599 my ($class, @args) = objectify(0, @_);
5663              
5664             # Pre-process list of operands.
5665              
5666 121         320 for my $arg (@args) {
5667 225 100       639 return $class -> bnan() unless $arg -> is_finite();
5668             }
5669              
5670             # Temporarily disable downgrading.
5671              
5672 81         244 my $dng = $class -> downgrade();
5673 81         271 $class -> downgrade(undef);
5674              
5675 81         171 my $x = shift @args;
5676 81         390 $x = $x -> copy(); # bgcd() and blcm() never modify any operands
5677              
5678 81         221 while (@args) {
5679 92         256 my $y = shift @args;
5680              
5681             # greatest common divisor
5682 92         311 while (! $y -> is_zero()) {
5683 242         702 ($x, $y) = ($y -> copy(), $x -> copy() -> bmod($y));
5684             }
5685              
5686 92 100       301 last if $x -> is_one();
5687             }
5688 81         437 $x -> babs();
5689              
5690             # Restore downgrading.
5691              
5692 81         321 $class -> downgrade($dng);
5693              
5694 81 50       183 $x -> _dng() if $x -> is_int();
5695 81         1147 return $x;
5696             }
5697              
5698             sub blcm {
5699             # Least Common Multiple
5700              
5701             # Class::method(...) -> Class->method(...)
5702 35 100 66 35 1 3379 unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
      33        
5703             ($_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i &&
5704             $_[0] !~ /^(inf|nan)/i)))
5705             {
5706             #carp "Using ", (caller(0))[3], "() as a function is deprecated;",
5707             # " use is as a method instead";
5708 1         5 unshift @_, __PACKAGE__;
5709             }
5710              
5711 35         153 my ($class, @args) = objectify(0, @_);
5712              
5713             # Pre-process list of operands.
5714              
5715 35         107 for my $arg (@args) {
5716 65 100       205 return $class -> bnan() unless $arg -> is_finite();
5717             }
5718              
5719 23         49 for my $arg (@args) {
5720 41 100       115 return $class -> bzero() if $arg -> is_zero();
5721             }
5722              
5723 11         27 my $x = shift @args;
5724 11         47 $x = $x -> copy(); # bgcd() and blcm() never modify any operands
5725              
5726 11         61 while (@args) {
5727 14         31 my $y = shift @args;
5728 14         38 my $gcd = $x -> copy() -> bgcd($y);
5729 14         141 $x -> bdiv($gcd) -> bmul($y);
5730             }
5731              
5732 11         48 $x -> babs(); # might downgrade
5733 11         218 return $x;
5734             }
5735              
5736             ###############################################################################
5737             # Object property methods
5738             ###############################################################################
5739              
5740             sub length {
5741 54 50   54 1 515 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5742              
5743 54 50       148 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
5744              
5745 54 100       227 return 1 if $LIB->_is_zero($x->{_m});
5746              
5747 50         219 my $len = $LIB->_len($x->{_m});
5748 50 50       370 $len += $LIB->_num($x->{_e}) if $x->{_es} eq '+';
5749 50 100       146 if (wantarray()) {
5750 30         73 my $t = 0;
5751 30 50       131 $t = $LIB->_num($x->{_e}) if $x->{_es} eq '-';
5752 30         109 return $len, $t;
5753             }
5754 20         187 $len;
5755             }
5756              
5757             sub mantissa {
5758             # return a copy of the mantissa
5759 36 50   36 1 538 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5760              
5761             # The following line causes a lot of noise in the test suits for
5762             # the Math-BigRat and bignum distributions. Fixme!
5763             #carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
5764              
5765 36 100       123 return $x -> bnan(@r) if $x -> is_nan();
5766              
5767 32 100       155 if ($x->{sign} !~ /^[+-]$/) {
5768 8         21 my $s = $x->{sign};
5769 8         27 $s =~ s/^\+//;
5770 8         63 return Math::BigInt -> new($s, undef, undef); # -inf, +inf => +inf
5771             }
5772 24         106 my $m = Math::BigInt -> new($LIB->_str($x->{_m}), undef, undef);
5773 24 100       107 $m = $m -> bneg() if $x->{sign} eq '-';
5774 24         122 $m;
5775             }
5776              
5777             sub exponent {
5778             # return a copy of the exponent
5779 36 50   36 1 551 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5780              
5781             # The following line causes a lot of noise in the test suits for
5782             # the Math-BigRat and bignum distributions. Fixme!
5783             #carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
5784              
5785 36 100       134 return $x -> bnan(@r) if $x -> is_nan();
5786              
5787 32 100       146 if ($x->{sign} !~ /^[+-]$/) {
5788 8         21 my $s = $x->{sign};
5789 8         57 $s =~ s/^[+-]//;
5790 8         38 return Math::BigInt -> new($s, undef, undef); # -inf, +inf => +inf
5791             }
5792 24         120 Math::BigInt -> new($x->{_es} . $LIB->_str($x->{_e}), undef, undef);
5793             }
5794              
5795             sub parts {
5796             # return a copy of both the exponent and the mantissa
5797 32 50   32 1 521 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5798              
5799 32 50       113 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
5800              
5801 32 100       150 if ($x->{sign} !~ /^[+-]$/) {
5802 12         44 my $s = $x->{sign};
5803 12         34 $s =~ s/^\+//;
5804 12         21 my $se = $s;
5805 12         26 $se =~ s/^-//;
5806             # +inf => inf and -inf, +inf => inf
5807 12         49 return $class -> new($s), $class -> new($se);
5808             }
5809 20         103 my $m = Math::BigInt -> bzero();
5810 20         88 $m->{value} = $LIB->_copy($x->{_m});
5811 20 100       114 $m = $m -> bneg() if $x->{sign} eq '-';
5812 20         106 ($m, Math::BigInt -> new($x->{_es} . $LIB->_num($x->{_e})));
5813             }
5814              
5815             # Parts used for scientific notation with significand/mantissa and exponent as
5816             # integers. E.g., "12345.6789" is returned as "123456789" (mantissa) and "-4"
5817             # (exponent).
5818              
5819             sub sparts {
5820 30 50   30 1 178 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5821              
5822 30 50       106 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
5823              
5824             # Not-a-number.
5825              
5826 30 50       91 if ($x -> is_nan()) {
5827 0         0 my $mant = $class -> bnan(); # mantissa
5828 0 0       0 return $mant unless wantarray; # scalar context
5829 0         0 my $expo = $class -> bnan(); # exponent
5830 0         0 return $mant, $expo; # list context
5831             }
5832              
5833             # Infinity.
5834              
5835 30 50       93 if ($x -> is_inf()) {
5836 0         0 my $mant = $class -> binf($x->{sign}); # mantissa
5837 0 0       0 return $mant unless wantarray; # scalar context
5838 0         0 my $expo = $class -> binf('+'); # exponent
5839 0         0 return $mant, $expo; # list context
5840             }
5841              
5842             # Finite number.
5843              
5844 30         111 my $mant = $class -> new($x);
5845 30         118 $mant->{_es} = '+';
5846 30         127 $mant->{_e} = $LIB->_zero();
5847 30         154 $mant -> _dng();
5848 30 50       123 return $mant unless wantarray;
5849              
5850 30         174 my $expo = $class -> new($x -> {_es} . $LIB->_str($x -> {_e}));
5851 30         168 $expo -> _dng();
5852 30         162 return $mant, $expo;
5853             }
5854              
5855             # Parts used for normalized notation with significand/mantissa as either 0 or a
5856             # number in the semi-open interval [1,10). E.g., "12345.6789" is returned as
5857             # "1.23456789" and "4".
5858              
5859             sub nparts {
5860 30 50   30 1 208 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5861              
5862 30 50       104 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
5863              
5864             # Not-a-number and Infinity.
5865              
5866 30 50 33     118 return $x -> sparts() if $x -> is_nan() || $x -> is_inf();
5867              
5868             # Finite number.
5869              
5870 30         154 my ($mant, $expo) = $x -> sparts();
5871              
5872 30 50       151 if ($mant -> bcmp(0)) {
5873 30         187 my ($ndigtot, $ndigfrac) = $mant -> length();
5874 30         100 my $expo10adj = $ndigtot - $ndigfrac - 1;
5875              
5876 30 100       105 if ($expo10adj > 0) { # if mantissa is not an integer
5877 16         103 $mant = $mant -> brsft($expo10adj, 10);
5878 16 50       61 return $mant unless wantarray;
5879 16         75 $expo = $expo -> badd($expo10adj);
5880 16         107 return $mant, $expo;
5881             }
5882             }
5883              
5884 14 50       44 return $mant unless wantarray;
5885 14         54 return $mant, $expo;
5886             }
5887              
5888             # Parts used for engineering notation with significand/mantissa as either 0 or
5889             # a number in the semi-open interval [1,1000) and the exponent is a multiple of
5890             # 3. E.g., "12345.6789" is returned as "12.3456789" and "3".
5891              
5892             sub eparts {
5893 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5894              
5895 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
5896              
5897             # Not-a-number and Infinity.
5898              
5899 0 0 0     0 return $x -> sparts() if $x -> is_nan() || $x -> is_inf();
5900              
5901             # Finite number.
5902              
5903 0         0 my ($mant, $expo) = $x -> nparts();
5904              
5905 0         0 my $c = $expo -> copy() -> bmod(3);
5906 0         0 $mant = $mant -> blsft($c, 10);
5907 0 0       0 return $mant unless wantarray;
5908              
5909 0         0 $expo = $expo -> bsub($c);
5910 0         0 return $mant, $expo;
5911             }
5912              
5913             # Parts used for decimal notation, e.g., "12345.6789" is returned as "12345"
5914             # (integer part) and "0.6789" (fraction part).
5915              
5916             sub dparts {
5917 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5918              
5919 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
5920              
5921             # Not-a-number.
5922              
5923 0 0       0 if ($x -> is_nan()) {
5924 0         0 my $int = $class -> bnan();
5925 0 0       0 return $int unless wantarray;
5926 0         0 my $frc = $class -> bzero(); # or NaN?
5927 0         0 return $int, $frc;
5928             }
5929              
5930             # Infinity.
5931              
5932 0 0       0 if ($x -> is_inf()) {
5933 0         0 my $int = $class -> binf($x->{sign});
5934 0 0       0 return $int unless wantarray;
5935 0         0 my $frc = $class -> bzero();
5936 0         0 return $int, $frc;
5937             }
5938              
5939             # Finite number.
5940              
5941 0         0 my $int = $x -> copy();
5942 0         0 my $frc;
5943              
5944             # If the input is an integer.
5945              
5946 0 0       0 if ($int->{_es} eq '+') {
5947 0         0 $frc = $class -> bzero();
5948             }
5949              
5950             # If the input has a fraction part
5951              
5952             else {
5953 0         0 $int->{_m} = $LIB -> _rsft($int->{_m}, $int->{_e}, 10);
5954 0         0 $int->{_e} = $LIB -> _zero();
5955 0         0 $int->{_es} = '+';
5956 0 0       0 $int->{sign} = '+' if $LIB->_is_zero($int->{_m}); # avoid -0
5957 0 0       0 return $int unless wantarray;
5958 0         0 $frc = $x -> copy() -> bsub($int);
5959 0         0 return $int, $frc;
5960             }
5961              
5962 0         0 $int -> _dng();
5963 0 0       0 return $int unless wantarray;
5964 0         0 return $int, $frc;
5965             }
5966              
5967             # Fractional parts with the numerator and denominator as integers. E.g.,
5968             # "123.4375" is returned as "1975" and "16".
5969              
5970             sub fparts {
5971 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
5972              
5973 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
5974              
5975             # NaN => NaN/NaN
5976              
5977 0 0       0 if ($x -> is_nan()) {
5978 0 0       0 return $class -> bnan() unless wantarray;
5979 0         0 return $class -> bnan(), $class -> bnan();
5980             }
5981              
5982             # ±Inf => ±Inf/1
5983              
5984 0 0       0 if ($x -> is_inf()) {
5985 0         0 my $numer = $class -> binf($x->{sign});
5986 0 0       0 return $numer unless wantarray;
5987 0         0 my $denom = $class -> bone();
5988 0         0 return $numer, $denom;
5989             }
5990              
5991             # Finite number.
5992              
5993             # If we get here, we know that the output is an integer.
5994              
5995 0 0       0 $class = $downgrade if $class -> downgrade();
5996              
5997 0         0 my @flt_parts = ($x->{sign}, $x->{_m}, $x->{_es}, $x->{_e});
5998 0         0 my @rat_parts = $class -> _flt_lib_parts_to_rat_lib_parts(@flt_parts);
5999 0         0 my $numer = $class -> new($LIB -> _str($rat_parts[1]));
6000 0 0       0 $numer -> bneg() if $rat_parts[0] eq "-";
6001 0 0       0 return $numer unless wantarray;
6002              
6003 0         0 my $denom = $class -> new($LIB -> _str($rat_parts[2]));
6004 0         0 return $numer, $denom;
6005             }
6006              
6007             # Given "123.4375", returns "1975", since "123.4375" is "1975/16".
6008              
6009             sub numerator {
6010 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
6011              
6012 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6013              
6014 0 0       0 return $class -> bnan() if $x -> is_nan();
6015 0 0       0 return $class -> binf($x -> sign()) if $x -> is_inf();
6016 0 0       0 return $class -> bzero() if $x -> is_zero();
6017              
6018             # If we get here, we know that the output is an integer.
6019              
6020 0 0       0 $class = $downgrade if $class -> downgrade();
6021              
6022 0 0       0 if ($x -> {_es} eq '-') { # exponent < 0
    0          
6023 0         0 my $numer_lib = $LIB -> _copy($x -> {_m});
6024 0         0 my $denom_lib = $LIB -> _1ex($x -> {_e});
6025 0         0 my $gcd_lib = $LIB -> _gcd($LIB -> _copy($numer_lib), $denom_lib);
6026 0         0 $numer_lib = $LIB -> _div($numer_lib, $gcd_lib);
6027 0         0 return $class -> new($x -> {sign} . $LIB -> _str($numer_lib));
6028             }
6029              
6030             elsif (! $LIB -> _is_zero($x -> {_e})) { # exponent > 0
6031 0         0 my $numer_lib = $LIB -> _copy($x -> {_m});
6032 0         0 $numer_lib = $LIB -> _lsft($numer_lib, $x -> {_e}, 10);
6033 0         0 return $class -> new($x -> {sign} . $LIB -> _str($numer_lib));
6034             }
6035              
6036             else { # exponent = 0
6037 0         0 return $class -> new($x -> {sign} . $LIB -> _str($x -> {_m}));
6038             }
6039             }
6040              
6041             # Given "123.4375", returns "16", since "123.4375" is "1975/16".
6042              
6043             sub denominator {
6044 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
6045              
6046 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6047              
6048 0 0       0 return $class -> bnan() if $x -> is_nan();
6049              
6050             # If we get here, we know that the output is an integer.
6051              
6052 0 0       0 $class = $downgrade if $class -> downgrade();
6053              
6054 0 0       0 if ($x -> {_es} eq '-') { # exponent < 0
6055 0         0 my $numer_lib = $LIB -> _copy($x -> {_m});
6056 0         0 my $denom_lib = $LIB -> _1ex($x -> {_e});
6057 0         0 my $gcd_lib = $LIB -> _gcd($LIB -> _copy($numer_lib), $denom_lib);
6058 0         0 $denom_lib = $LIB -> _div($denom_lib, $gcd_lib);
6059 0         0 return $class -> new($LIB -> _str($denom_lib));
6060             }
6061              
6062             else { # exponent >= 0
6063 0         0 return $class -> bone();
6064             }
6065             }
6066              
6067             ###############################################################################
6068             # String conversion methods
6069             ###############################################################################
6070              
6071             sub bstr {
6072             # (ref to BFLOAT or num_str) return num_str
6073             # Convert number from internal format to (non-scientific) string format.
6074             # internal format is always normalized (no leading zeros, "-0" => "+0")
6075 8459 100   8459 1 2677803 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
6076              
6077 8459 50       25752 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6078              
6079             # Inf and NaN
6080              
6081 8459 100 100     42584 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
6082 2483 100       10443 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
6083 555         3694 return 'inf'; # +inf
6084             }
6085              
6086             # Finite number
6087              
6088 5976         13263 my $es = '0';
6089 5976         10295 my $len = 1;
6090 5976         10393 my $cad = 0;
6091 5976         10893 my $dot = '.';
6092              
6093             # $x is zero?
6094 5976   100     39298 my $not_zero = !($x->{sign} eq '+' && $LIB->_is_zero($x->{_m}));
6095 5976 100       16504 if ($not_zero) {
6096 4759         21244 $es = $LIB->_str($x->{_m});
6097 4759         10313 $len = CORE::length($es);
6098 4759         16907 my $e = $LIB->_num($x->{_e});
6099 4759 100       16242 $e = -$e if $x->{_es} eq '-';
6100 4759 100       15763 if ($e < 0) {
    100          
6101 1613         3465 $dot = '';
6102             # if _e is bigger than a scalar, the following will blow your memory
6103 1613 100       4843 if ($e <= -$len) {
6104 602         1623 my $r = abs($e) - $len;
6105 602         2255 $es = '0.'. ('0' x $r) . $es;
6106 602         1407 $cad = -($len+$r);
6107             } else {
6108 1011         3175 substr($es, $e, 0) = '.';
6109 1011         3584 $cad = $LIB->_num($x->{_e});
6110 1011 50       4083 $cad = -$cad if $x->{_es} eq '-';
6111             }
6112             } elsif ($e > 0) {
6113             # expand with zeros
6114 682         2616 $es .= '0' x $e;
6115 682         1522 $len += $e;
6116 682         1407 $cad = 0;
6117             }
6118             } # if not zero
6119              
6120 5976 100       18052 $es = '-'.$es if $x->{sign} eq '-';
6121             # if set accuracy or precision, pad with zeros on the right side
6122 5976 100 100     38236 if ((defined $x->{accuracy}) && ($not_zero)) {
    100 100        
6123             # 123400 => 6, 0.1234 => 4, 0.001234 => 4
6124 695         1701 my $zeros = $x->{accuracy} - $cad; # cad == 0 => 12340
6125 695 50       2112 $zeros = $x->{accuracy} - $len if $cad != $len;
6126 695 100       1978 $es .= $dot.'0' x $zeros if $zeros > 0;
6127             } elsif ((($x->{precision} || 0) < 0)) {
6128             # 123400 => 6, 0.1234 => 4, 0.001234 => 6
6129 502         1145 my $zeros = -$x->{precision} + $cad;
6130 502 100       1512 $es .= $dot.'0' x $zeros if $zeros > 0;
6131             }
6132 5976         42227 $es;
6133             }
6134              
6135             # Scientific notation with significand/mantissa and exponent as integers, e.g.,
6136             # "12345.6789" is written as "123456789e-4".
6137              
6138             sub bsstr {
6139 79 100   79 1 15856 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
6140              
6141             # Inf and NaN
6142              
6143 79 100 100     437 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
6144 24 100       93 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
6145 8         85 return 'inf'; # +inf
6146             }
6147              
6148             # Upgrade?
6149              
6150 55 50 33     240 return $x -> _upg() -> bsstr(@r)
6151             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
6152              
6153             # Round according to arguments or global settings, if any.
6154              
6155 55         229 $x = $x -> copy() -> round(@r);
6156              
6157             # Finite number
6158              
6159             ($x->{sign} eq '-' ? '-' : '') . $LIB->_str($x->{_m})
6160 55 100       418 . 'e' . $x->{_es} . $LIB->_str($x->{_e});
6161             }
6162              
6163             # Normalized notation, e.g., "12345.6789" is written as "1.23456789e+4".
6164              
6165             sub bnstr {
6166 538 50   538 1 2016 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
6167              
6168             # Inf and NaN
6169              
6170 538 50 66     2125 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
6171 0 0       0 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
6172 0         0 return 'inf'; # +inf
6173             }
6174              
6175             # Upgrade?
6176              
6177 538 50 33     1992 return $x -> _upg() -> bnstr(@r)
6178             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
6179              
6180             # Finite number
6181              
6182 538 100       1754 my $str = $x->{sign} eq '-' ? '-' : '';
6183              
6184             # Round according to arguments or global settings, if any.
6185              
6186 538         1810 $x = $x -> copy() -> round(@r);
6187              
6188             # Get the mantissa and the length of the mantissa.
6189              
6190 538         2386 my $mant = $LIB->_str($x->{_m});
6191 538         1332 my $mantlen = CORE::length($mant);
6192              
6193 538 100       1394 if ($mantlen == 1) {
6194              
6195             # Not decimal point when the mantissa has length one, i.e., return the
6196             # number 2 as the string "2", not "2.".
6197              
6198 89         306 $str .= $mant . 'e' . $x->{_es} . $LIB->_str($x->{_e});
6199              
6200             } else {
6201              
6202             # Compute new exponent where the original exponent is adjusted by the
6203             # length of the mantissa minus one (because the decimal point is after
6204             # one digit).
6205              
6206             my ($eabs, $esgn) = $LIB -> _sadd($LIB -> _copy($x->{_e}), $x->{_es},
6207 449         1807 $LIB -> _new($mantlen - 1), "+");
6208 449         1863 substr $mant, 1, 0, ".";
6209 449         1406 $str .= $mant . 'e' . $esgn . $LIB->_str($eabs);
6210              
6211             }
6212              
6213 538         6175 return $str;
6214             }
6215              
6216             # Engineering notation, e.g., "12345.6789" is written as "12.3456789e+3".
6217              
6218             sub bestr {
6219 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
6220              
6221             # Inf and NaN
6222              
6223 0 0 0     0 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
6224 0 0       0 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
6225 0         0 return 'inf'; # +inf
6226             }
6227              
6228             # Upgrade?
6229              
6230 0 0 0     0 return $x -> _upg() -> bestr(@r)
6231             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
6232              
6233             # Round according to arguments or global settings, if any.
6234              
6235 0         0 $x = $x -> copy() -> round(@r);
6236              
6237             # Finite number
6238              
6239 0 0       0 my $str = $x->{sign} eq '-' ? '-' : '';
6240              
6241             # Get the mantissa, the length of the mantissa, and adjust the exponent by
6242             # the length of the mantissa minus 1 (because the dot is after one digit).
6243              
6244 0         0 my $mant = $LIB->_str($x->{_m});
6245 0         0 my $mantlen = CORE::length($mant);
6246             my ($eabs, $esgn) = $LIB -> _sadd($LIB -> _copy($x->{_e}), $x->{_es},
6247 0         0 $LIB -> _new($mantlen - 1), "+");
6248              
6249 0         0 my $dotpos = 1;
6250 0         0 my $mod = $LIB -> _mod($LIB -> _copy($eabs), $LIB -> _new("3"));
6251 0 0       0 unless ($LIB -> _is_zero($mod)) {
6252 0 0       0 if ($esgn eq '+') {
6253 0         0 $eabs = $LIB -> _sub($eabs, $mod);
6254 0         0 $dotpos += $LIB -> _num($mod);
6255             } else {
6256 0         0 my $delta = $LIB -> _sub($LIB -> _new("3"), $mod);
6257 0         0 $eabs = $LIB -> _add($eabs, $delta);
6258 0         0 $dotpos += $LIB -> _num($delta);
6259             }
6260             }
6261              
6262 0 0       0 if ($dotpos < $mantlen) {
    0          
6263 0         0 substr $mant, $dotpos, 0, ".";
6264             } elsif ($dotpos > $mantlen) {
6265 0         0 $mant .= "0" x ($dotpos - $mantlen);
6266             }
6267              
6268 0         0 $str .= $mant . 'e' . $esgn . $LIB->_str($eabs);
6269              
6270 0         0 return $str;
6271             }
6272              
6273             # Decimal notation, e.g., "12345.6789" (no exponent).
6274              
6275             sub bdstr {
6276 786 50   786 1 3303 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
6277              
6278             # Inf and NaN
6279              
6280 786 50 66     3587 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
6281 0 0       0 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
6282 0         0 return 'inf'; # +inf
6283             }
6284              
6285             # Upgrade?
6286              
6287 786 50 33     2444 return $x -> _upg() -> bdstr(@r)
6288             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
6289              
6290             # Round according to arguments or global settings, if any.
6291              
6292 786         2264 $x = $x -> copy() -> round(@r);
6293              
6294             # Finite number
6295              
6296 786         3713 my $mant = $LIB->_str($x->{_m});
6297 786         1997 my $esgn = $x->{_es};
6298 786         2803 my $eabs = $LIB -> _num($x->{_e});
6299              
6300 786         1532 my $uintmax = ~0;
6301              
6302 786         1483 my $str = $mant;
6303 786 100       2081 if ($esgn eq '+') {
6304              
6305 784 50       2062 croak("The absolute value of the exponent is too large")
6306             if $eabs > $uintmax;
6307              
6308 784         2554 $str .= "0" x $eabs;
6309              
6310             } else {
6311 2         5 my $mlen = CORE::length($mant);
6312 2         4 my $c = $mlen - $eabs;
6313              
6314 2         19 my $intmax = ($uintmax - 1) / 2;
6315 2 50       9 croak("The absolute value of the exponent is too large")
6316             if (1 - $c) > $intmax;
6317              
6318 2 50       9 $str = "0" x (1 - $c) . $str if $c <= 0;
6319 2         5 substr($str, -$eabs, 0) = '.';
6320             }
6321              
6322 786 100       7127 return $x->{sign} eq '-' ? '-' . $str : $str;
6323             }
6324              
6325             # Fractional notation, e.g., "123.4375" is written as "1975/16".
6326              
6327             sub bfstr {
6328 1150 50   1150 1 3164 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
6329              
6330 1150 50       2514 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6331              
6332             # Inf and NaN
6333              
6334 1150 50 66     3654 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
6335 0 0       0 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
6336 0         0 return 'inf'; # +inf
6337             }
6338              
6339             # Upgrade?
6340              
6341 1150 50 66     3190 return $x -> _upg() -> bfstr(@r)
6342             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
6343              
6344             # Finite number
6345              
6346 1150 100       3186 my $str = $x->{sign} eq '-' ? '-' : '';
6347              
6348 1150 100       2562 if ($x->{_es} eq '+') {
6349 120         572 $str .= $LIB -> _str($x->{_m}) . ("0" x $LIB -> _num($x->{_e}));
6350             } else {
6351 1030         3532 my @flt_parts = ($x->{sign}, $x->{_m}, $x->{_es}, $x->{_e});
6352 1030         3606 my @rat_parts = $class -> _flt_lib_parts_to_rat_lib_parts(@flt_parts);
6353 1030         3141 $str = $LIB -> _str($rat_parts[1]) . "/" . $LIB -> _str($rat_parts[2]);
6354 1030 100       4297 $str = "-" . $str if $rat_parts[0] eq "-";
6355             }
6356              
6357 1150         5072 return $str;
6358             }
6359              
6360             sub to_hex {
6361             # return number as hexadecimal string (only for integers defined)
6362 36 50   36 1 636 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
6363              
6364 36 50       111 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6365              
6366             # Inf and NaN
6367              
6368 36 100 100     188 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
6369 12 100       60 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
6370 4         57 return 'inf'; # +inf
6371             }
6372              
6373             # Upgrade?
6374              
6375 24 50 33     115 return $x -> _upg() -> to_hex(@r)
6376             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
6377              
6378             # Finite number
6379              
6380 24 100       99 return '0' if $x -> is_zero();
6381              
6382 16 50       57 return $nan if $x->{_es} ne '+'; # how to do 1e-1 in hex?
6383              
6384 16         70 my $z = $LIB->_copy($x->{_m});
6385 16 50       126 if (! $LIB->_is_zero($x->{_e})) { # > 0
6386 0         0 $z = $LIB->_lsft($z, $x->{_e}, 10);
6387             }
6388 16         131 my $str = $LIB->_to_hex($z);
6389 16 100       284 return $x->{sign} eq '-' ? "-$str" : $str;
6390             }
6391              
6392             sub to_oct {
6393             # return number as octal digit string (only for integers defined)
6394 40 50   40 1 654 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
6395              
6396 40 50       128 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6397              
6398             # Inf and NaN
6399              
6400 40 100 100     191 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
6401 12 100       57 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
6402 4         56 return 'inf'; # +inf
6403             }
6404              
6405             # Upgrade?
6406              
6407 28 50 33     113 return $x -> _upg() -> to_oct(@r)
6408             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
6409              
6410             # Finite number
6411              
6412 28 100       98 return '0' if $x -> is_zero();
6413              
6414 20 50       63 return $nan if $x->{_es} ne '+'; # how to do 1e-1 in octal?
6415              
6416 20         84 my $z = $LIB->_copy($x->{_m});
6417 20 50       64 if (! $LIB->_is_zero($x->{_e})) { # > 0
6418 0         0 $z = $LIB->_lsft($z, $x->{_e}, 10);
6419             }
6420 20         129 my $str = $LIB->_to_oct($z);
6421 20 100       347 return $x->{sign} eq '-' ? "-$str" : $str;
6422             }
6423              
6424             sub to_bin {
6425             # return number as binary digit string (only for integers defined)
6426 40 50   40 1 643 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
6427              
6428 40 50       110 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6429              
6430             # Inf and NaN
6431              
6432 40 100 100     214 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
6433 12 100       53 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
6434 4         57 return 'inf'; # +inf
6435             }
6436              
6437             # Upgrade?
6438              
6439 28 50 33     121 return $x -> _upg() -> to_bin(@r)
6440             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
6441              
6442             # Finite number
6443              
6444 28 100       132 return '0' if $x -> is_zero();
6445              
6446 20 50       83 return $nan if $x->{_es} ne '+'; # how to do 1e-1 in binary?
6447              
6448 20         97 my $z = $LIB->_copy($x->{_m});
6449 20 50       68 if (! $LIB->_is_zero($x->{_e})) { # > 0
6450 0         0 $z = $LIB->_lsft($z, $x->{_e}, 10);
6451             }
6452 20         165 my $str = $LIB->_to_bin($z);
6453 20 100       319 return $x->{sign} eq '-' ? "-$str" : $str;
6454             }
6455              
6456             sub to_bytes {
6457             # return a byte string
6458              
6459 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
6460              
6461 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6462              
6463 0 0 0     0 croak("to_bytes() requires a finite, non-negative integer")
6464             if $x -> is_neg() || ! $x -> is_int();
6465              
6466 0 0 0     0 return $x -> _upg() -> to_bytes(@r)
6467             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
6468              
6469 0 0       0 croak("to_bytes() requires a newer version of the $LIB library.")
6470             unless $LIB -> can('_to_bytes');
6471              
6472 0         0 return $LIB->_to_bytes($LIB -> _lsft($x->{_m}, $x->{_e}, 10));
6473             }
6474              
6475             sub to_ieee754 {
6476 0 0   0 1 0 my ($class, $x, $format, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
6477              
6478 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6479              
6480 0         0 my $enc; # significand encoding (applies only to decimal)
6481             my $k; # storage width in bits
6482 0         0 my $b; # base
6483              
6484 0 0       0 if ($format =~ /^binary(\d+)\z/) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
6485 0         0 $k = $1;
6486 0         0 $b = 2;
6487             } elsif ($format =~ /^decimal(\d+)(dpd|bcd)?\z/) {
6488 0         0 $k = $1;
6489 0         0 $b = 10;
6490 0   0     0 $enc = $2 || 'dpd'; # default is dencely-packed decimals (DPD)
6491             } elsif ($format eq 'half') {
6492 0         0 $k = 16;
6493 0         0 $b = 2;
6494             } elsif ($format eq 'single') {
6495 0         0 $k = 32;
6496 0         0 $b = 2;
6497             } elsif ($format eq 'double') {
6498 0         0 $k = 64;
6499 0         0 $b = 2;
6500             } elsif ($format eq 'quadruple') {
6501 0         0 $k = 128;
6502 0         0 $b = 2;
6503             } elsif ($format eq 'octuple') {
6504 0         0 $k = 256;
6505 0         0 $b = 2;
6506             } elsif ($format eq 'sexdecuple') {
6507 0         0 $k = 512;
6508 0         0 $b = 2;
6509             }
6510              
6511 0 0       0 if ($b == 2) {
6512              
6513             # Get the parameters for this format.
6514              
6515 0         0 my $p; # precision (in bits)
6516             my $t; # number of bits in significand
6517 0         0 my $w; # number of bits in exponent
6518              
6519 0 0       0 if ($k == 16) { # binary16 (half-precision)
    0          
    0          
6520 0         0 $p = 11;
6521 0         0 $t = 10;
6522 0         0 $w = 5;
6523             } elsif ($k == 32) { # binary32 (single-precision)
6524 0         0 $p = 24;
6525 0         0 $t = 23;
6526 0         0 $w = 8;
6527             } elsif ($k == 64) { # binary64 (double-precision)
6528 0         0 $p = 53;
6529 0         0 $t = 52;
6530 0         0 $w = 11;
6531             } else { # binaryN (quadruple-precition and above)
6532 0 0 0     0 if ($k < 128 || $k != 32 * sprintf('%.0f', $k / 32)) {
6533 0         0 croak "Number of bits must be 16, 32, 64, or >= 128 and",
6534             " a multiple of 32";
6535             }
6536 0         0 $p = $k - sprintf('%.0f', 4 * log($k) / log(2)) + 13;
6537 0         0 $t = $p - 1;
6538 0         0 $w = $k - $t - 1;
6539             }
6540              
6541             # The maximum exponent, minimum exponent, and exponent bias.
6542              
6543 0         0 my $emax = $class -> new(2) -> bpow($w - 1) -> bdec();
6544 0         0 my $emin = 1 - $emax;
6545 0         0 my $bias = $emax;
6546              
6547             # Get numerical sign, exponent, and mantissa/significand for bit
6548             # string.
6549              
6550 0         0 my $sign = 0;
6551 0         0 my $expo;
6552             my $mant;
6553              
6554 0 0       0 if ($x -> is_nan()) { # nan
    0          
    0          
6555 0         0 $sign = 1;
6556 0         0 $expo = $emax -> copy() -> binc();
6557 0         0 $mant = $class -> new(2) -> bpow($t - 1);
6558             } elsif ($x -> is_inf()) { # inf
6559 0 0       0 $sign = 1 if $x -> is_neg();
6560 0         0 $expo = $emax -> copy() -> binc();
6561 0         0 $mant = $class -> bzero();
6562             } elsif ($x -> is_zero()) { # zero
6563 0         0 $expo = $emin -> copy() -> bdec();
6564 0         0 $mant = $class -> bzero();
6565             } else { # normal and subnormal
6566              
6567 0 0       0 $sign = 1 if $x -> is_neg();
6568              
6569             # Now we need to compute the mantissa and exponent in base $b.
6570              
6571 0         0 my $binv = $class -> new("0.5");
6572 0         0 my $b = $class -> new(2);
6573 0         0 my $one = $class -> bone();
6574              
6575             # We start off by initializing the exponent to zero and the
6576             # mantissa to the input value. Then we increase the mantissa and
6577             # decrease the exponent, or vice versa, until the mantissa is in
6578             # the desired range or we hit one of the limits for the exponent.
6579              
6580 0         0 $mant = $x -> copy() -> babs();
6581              
6582             # We need to find the base 2 exponent. First make an estimate of
6583             # the base 2 exponent, before adjusting it below. We could skip
6584             # this estimation and go straight to the while-loops below, but the
6585             # loops are slow, especially when the final exponent is far from
6586             # zero and even more so if the number of digits is large. This
6587             # initial estimation speeds up the computation dramatically.
6588             #
6589             # log2($m * 10**$e) = log10($m + 10**$e) * log(10)/log(2)
6590             # = (log10($m) + $e) * log(10)/log(2)
6591             # = (log($m)/log(10) + $e) * log(10)/log(2)
6592              
6593 0         0 my ($m, $e) = $x -> nparts();
6594 0         0 my $ms = $m -> numify();
6595 0         0 my $es = $e -> numify();
6596              
6597 0         0 my $expo_est = (log(abs($ms))/log(10) + $es) * log(10)/log(2);
6598 0         0 $expo_est = int($expo_est);
6599              
6600             # Limit the exponent.
6601              
6602 0 0       0 if ($expo_est > $emax) {
    0          
6603 0         0 $expo_est = $emax;
6604             } elsif ($expo_est < $emin) {
6605 0         0 $expo_est = $emin;
6606             }
6607              
6608             # Don't multiply by a number raised to a negative exponent. This
6609             # will cause a division, whose result is truncated to some fixed
6610             # number of digits. Instead, multiply by the inverse number raised
6611             # to a positive exponent.
6612              
6613 0         0 $expo = $class -> new($expo_est);
6614 0 0       0 if ($expo_est > 0) {
    0          
6615 0         0 $mant = $mant -> bmul($binv -> copy() -> bpow($expo));
6616             } elsif ($expo_est < 0) {
6617 0         0 my $expo_abs = $expo -> copy() -> bneg();
6618 0         0 $mant = $mant -> bmul($b -> copy() -> bpow($expo_abs));
6619             }
6620              
6621             # Final adjustment of the estimate above.
6622              
6623 0   0     0 while ($mant >= $b && $expo <= $emax) {
6624 0         0 $mant = $mant -> bmul($binv);
6625 0         0 $expo = $expo -> binc();
6626             }
6627              
6628 0   0     0 while ($mant < $one && $expo >= $emin) {
6629 0         0 $mant = $mant -> bmul($b);
6630 0         0 $expo = $expo -> bdec();
6631             }
6632              
6633             # This is when the magnitude is larger than what can be represented
6634             # in this format. Encode as infinity.
6635              
6636 0 0       0 if ($expo > $emax) {
    0          
6637 0         0 $mant = $class -> bzero();
6638 0         0 $expo = $emax -> copy() -> binc();
6639             }
6640              
6641             # This is when the magnitude is so small that the number is encoded
6642             # as a subnormal number.
6643             #
6644             # If the magnitude is smaller than that of the smallest subnormal
6645             # number, and rounded downwards, it is encoded as zero. This works
6646             # transparently and does not need to be treated as a special case.
6647             #
6648             # If the number is between the largest subnormal number and the
6649             # smallest normal number, and the value is rounded upwards, the
6650             # value must be encoded as a normal number. This must be treated as
6651             # a special case.
6652              
6653             elsif ($expo < $emin) {
6654              
6655             # Scale up the mantissa (significand), and round to integer.
6656              
6657 0         0 my $const = $class -> new($b) -> bpow($t - 1);
6658 0         0 $mant = $mant -> bmul($const);
6659 0         0 $mant = $mant -> bfround(0);
6660              
6661             # If the mantissa overflowed, encode as the smallest normal
6662             # number.
6663              
6664 0 0       0 if ($mant == $const -> bmul($b)) {
6665 0         0 $mant = $mant -> bzero();
6666 0         0 $expo = $expo -> binc();
6667             }
6668             }
6669              
6670             # This is when the magnitude is within the range of what can be
6671             # encoded as a normal number.
6672              
6673             else {
6674              
6675             # Remove implicit leading bit, scale up the mantissa
6676             # (significand) to an integer, and round.
6677              
6678 0         0 $mant = $mant -> bdec();
6679 0         0 my $const = $class -> new($b) -> bpow($t);
6680 0         0 $mant = $mant -> bmul($const) -> bfround(0);
6681              
6682             # If the mantissa overflowed, encode as the next larger value.
6683             # This works correctly also when the next larger value is
6684             # infinity.
6685              
6686 0 0       0 if ($mant == $const) {
6687 0         0 $mant = $mant -> bzero();
6688 0         0 $expo = $expo -> binc();
6689             }
6690             }
6691             }
6692              
6693 0         0 $expo = $expo -> badd($bias); # add bias
6694              
6695 0         0 my $signbit = "$sign";
6696              
6697 0         0 my $mantbits = $mant -> to_bin();
6698 0         0 $mantbits = ("0" x ($t - CORE::length($mantbits))) . $mantbits;
6699              
6700 0         0 my $expobits = $expo -> to_bin();
6701 0         0 $expobits = ("0" x ($w - CORE::length($expobits))) . $expobits;
6702              
6703 0         0 my $bin = $signbit . $expobits . $mantbits;
6704 0         0 return pack "B*", $bin;
6705             }
6706              
6707 0         0 croak("The format '$format' is not yet supported.");
6708             }
6709              
6710             sub to_fp80 {
6711 0 0   0 1 0 my ($class, $x, $format, @r) = ref($_[0]) ? (ref($_[0]), @_)
6712             : objectify(1, @_);
6713              
6714 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6715              
6716             # The maximum exponent, minimum exponent, and exponent bias.
6717              
6718 0         0 my $emax = Math::BigFloat -> new("16383");
6719 0         0 my $emin = 1 - $emax;
6720 0         0 my $bias = $emax;
6721              
6722             # Get numerical sign, exponent, and mantissa/significand for bit string.
6723              
6724 0         0 my $sign = 0;
6725 0         0 my $expo;
6726             my $mant;
6727              
6728 0 0       0 if ($x -> is_nan()) { # nan
    0          
    0          
6729 0         0 $sign = 1;
6730 0         0 $expo = $emax -> copy() -> binc();
6731 0         0 $mant = $class -> new(2) -> bpow(64) -> bdec();
6732              
6733             } elsif ($x -> is_inf()) { # inf
6734 0 0       0 $sign = 1 if $x -> is_neg();
6735 0         0 $expo = $emax -> copy() -> binc();
6736 0         0 $mant = $class -> bzero();
6737              
6738             } elsif ($x -> is_zero()) { # zero
6739 0         0 $expo = $emin -> copy() -> bdec();
6740 0         0 $mant = $class -> bzero();
6741              
6742             } else { # normal and subnormal
6743              
6744 0 0       0 $sign = 1 if $x -> is_neg();
6745              
6746             # Now we need to compute the mantissa and exponent in base $b.
6747              
6748 0         0 my $binv = $class -> new("0.5");
6749 0         0 my $b = $class -> new("2");
6750 0         0 my $one = $class -> bone();
6751              
6752             # We start off by initializing the exponent to zero and the
6753             # mantissa to the input value. Then we increase the mantissa and
6754             # decrease the exponent, or vice versa, until the mantissa is in
6755             # the desired range or we hit one of the limits for the exponent.
6756              
6757 0         0 $mant = $x -> copy() -> babs();
6758              
6759             # We need to find the base 2 exponent. First make an estimate of
6760             # the base 2 exponent, before adjusting it below. We could skip
6761             # this estimation and go straight to the while-loops below, but the
6762             # loops are slow, especially when the final exponent is far from
6763             # zero and even more so if the number of digits is large. This
6764             # initial estimation speeds up the computation dramatically.
6765             #
6766             # log2($m * 10**$e) = log10($m + 10**$e) * log(10)/log(2)
6767             # = (log10($m) + $e) * log(10)/log(2)
6768             # = (log($m)/log(10) + $e) * log(10)/log(2)
6769              
6770 0         0 my ($m, $e) = $x -> nparts();
6771 0         0 my $ms = $m -> numify();
6772 0         0 my $es = $e -> numify();
6773              
6774 0         0 my $expo_est = (log(abs($ms))/log(10) + $es) * log(10)/log(2);
6775 0         0 $expo_est = int($expo_est);
6776              
6777             # Limit the exponent.
6778              
6779 0 0       0 if ($expo_est > $emax) {
    0          
6780 0         0 $expo_est = $emax;
6781             } elsif ($expo_est < $emin) {
6782 0         0 $expo_est = $emin;
6783             }
6784              
6785             # Don't multiply by a number raised to a negative exponent. This
6786             # will cause a division, whose result is truncated to some fixed
6787             # number of digits. Instead, multiply by the inverse number raised
6788             # to a positive exponent.
6789              
6790 0         0 $expo = $class -> new($expo_est);
6791 0 0       0 if ($expo_est > 0) {
    0          
6792 0         0 $mant = $mant -> bmul($binv -> copy() -> bpow($expo));
6793             } elsif ($expo_est < 0) {
6794 0         0 my $expo_abs = $expo -> copy() -> bneg();
6795 0         0 $mant = $mant -> bmul($b -> copy() -> bpow($expo_abs));
6796             }
6797              
6798             # Final adjustment of the estimate above.
6799              
6800 0   0     0 while ($mant >= $b && $expo <= $emax) {
6801 0         0 $mant = $mant -> bmul($binv);
6802 0         0 $expo = $expo -> binc();
6803             }
6804              
6805 0   0     0 while ($mant < $one && $expo >= $emin) {
6806 0         0 $mant = $mant -> bmul($b);
6807 0         0 $expo = $expo -> bdec();
6808             }
6809              
6810             # This is when the magnitude is larger than what can be represented in
6811             # this format. Encode as infinity.
6812              
6813 0 0       0 if ($expo > $emax) {
    0          
6814 0         0 $mant = $class -> bzero();
6815 0         0 $expo = $emax -> copy() -> binc();
6816             }
6817              
6818             # This is when the magnitude is so small that the number is encoded as
6819             # a subnormal number.
6820             #
6821             # If the magnitude is smaller than that of the smallest subnormal
6822             # number, and rounded downwards, it is encoded as zero. This works
6823             # transparently and does not need to be treated as a special case.
6824             #
6825             # If the number is between the largest subnormal number and the
6826             # smallest normal number, and the value is rounded upwards, the value
6827             # must be encoded as a normal number. This must be treated as a special
6828             # case.
6829              
6830             elsif ($expo < $emin) {
6831              
6832             # Scale up the mantissa (significand), and round to integer.
6833              
6834 0         0 my $const = $class -> new($b) -> bpow(62);
6835 0         0 $mant -> bmul($const) -> bfround(0);
6836              
6837             # If the mantissa overflowed, encode as the smallest normal number.
6838              
6839 0 0       0 if ($mant == $const -> bmul($b)) {
6840 0         0 $expo -> binc();
6841             }
6842             }
6843              
6844             # This is when the magnitude is within the range of what can be encoded
6845             # as a normal number.
6846              
6847             else {
6848              
6849             # Remove implicit leading bit, scale up the mantissa (significand)
6850             # to an integer, and round.
6851              
6852 0         0 my $const = $class -> new($b) -> bpow(63);
6853 0         0 $mant -> bmul($const) -> bfround(0);
6854              
6855             # If the mantissa overflowed, encode as the next larger value. If
6856             # this caused the exponent to overflow, encode as infinity.
6857              
6858 0 0       0 if ($mant == $const -> copy() -> bmul($b)) {
6859 0         0 $expo -> binc();
6860 0 0       0 if ($expo > $emax) {
6861 0         0 $mant = $class -> bzero();
6862             } else {
6863 0         0 $mant = $const;
6864             }
6865             }
6866             }
6867             }
6868              
6869 0         0 $expo = $expo -> badd($bias); # add bias
6870              
6871 0         0 my $signbit = "$sign";
6872              
6873 0         0 my $mantbits = $mant -> to_bin();
6874 0         0 $mantbits = ("0" x (64 - CORE::length($mantbits))) . $mantbits;
6875              
6876 0         0 my $expobits = $expo -> to_bin();
6877 0         0 $expobits = ("0" x (15 - CORE::length($expobits))) . $expobits;
6878              
6879 0         0 my $bin = $signbit . $expobits . $mantbits;
6880 0         0 return pack "B*", $bin;
6881             }
6882              
6883             sub as_hex {
6884             # return number as hexadecimal string (only for integers defined)
6885              
6886 36 50   36 1 532 my (undef, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
6887              
6888 36 50       139 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6889              
6890 36 100       312 return $x -> bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
6891 24 100       107 return '0x0' if $x -> is_zero();
6892              
6893 16 50       61 return $nan if $x->{_es} ne '+'; # how to do 1e-1 in hex?
6894              
6895 16         71 my $z = $LIB->_copy($x->{_m});
6896 16 50       75 if (! $LIB->_is_zero($x->{_e})) { # > 0
6897 0         0 $z = $LIB->_lsft($z, $x->{_e}, 10);
6898             }
6899 16         76 my $str = $LIB->_as_hex($z);
6900 16 100       255 return $x->{sign} eq '-' ? "-$str" : $str;
6901             }
6902              
6903             sub as_oct {
6904             # return number as octal digit string (only for integers defined)
6905              
6906 40 50   40 1 687 my (undef, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
6907              
6908 40 50       124 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6909              
6910 40 100       214 return $x -> bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
6911 28 100       107 return '00' if $x -> is_zero();
6912              
6913 20 50       68 return $nan if $x->{_es} ne '+'; # how to do 1e-1 in octal?
6914              
6915 20         123 my $z = $LIB->_copy($x->{_m});
6916 20 50       73 if (! $LIB->_is_zero($x->{_e})) { # > 0
6917 0         0 $z = $LIB->_lsft($z, $x->{_e}, 10);
6918             }
6919 20         100 my $str = $LIB->_as_oct($z);
6920 20 100       298 return $x->{sign} eq '-' ? "-$str" : $str;
6921             }
6922              
6923             sub as_bin {
6924             # return number as binary digit string (only for integers defined)
6925              
6926 40 50   40 1 639 my (undef, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
6927              
6928 40 50       134 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6929              
6930 40 100       215 return $x -> bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
6931 28 100       99 return '0b0' if $x -> is_zero();
6932              
6933 20 50       63 return $nan if $x->{_es} ne '+'; # how to do 1e-1 in binary?
6934              
6935 20         84 my $z = $LIB->_copy($x->{_m});
6936 20 50       67 if (! $LIB->_is_zero($x->{_e})) { # > 0
6937 0         0 $z = $LIB->_lsft($z, $x->{_e}, 10);
6938             }
6939 20         87 my $str = $LIB->_as_bin($z);
6940 20 100       368 return $x->{sign} eq '-' ? "-$str" : $str;
6941             }
6942              
6943             sub numify {
6944             # Make a Perl scalar number from a Math::BigFloat object.
6945              
6946 538 50   538 1 2440 my (undef, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
6947              
6948 538 50       2236 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
6949              
6950 538 50       1555 if ($x -> is_nan()) {
6951 0         0 require Math::Complex;
6952 0         0 my $inf = $Math::Complex::Inf;
6953 0         0 return $inf - $inf;
6954             }
6955              
6956 538 50       1829 if ($x -> is_inf()) {
6957 0         0 require Math::Complex;
6958 0         0 my $inf = $Math::Complex::Inf;
6959 0 0       0 return $x -> is_negative() ? -$inf : $inf;
6960             }
6961              
6962             # Create a string and let Perl's atoi()/atof() handle the rest.
6963              
6964 538         2331 return 0 + $x -> bnstr();
6965             }
6966              
6967             ###############################################################################
6968             # Private methods and functions.
6969             ###############################################################################
6970              
6971             sub import {
6972 61     61   3254 my $class = shift;
6973 61         119 $IMPORT++; # remember we did import()
6974 61         125 my @a; # unrecognized arguments
6975              
6976 61         136 my @import = ();
6977              
6978 61         239 while (@_) {
6979 11         21 my $param = shift;
6980              
6981             # Enable overloading of constants.
6982              
6983 11 50       32 if ($param eq ':constant') {
6984             overload::constant
6985              
6986             integer => sub {
6987 0     0   0 $class -> new(shift);
6988             },
6989              
6990             float => sub {
6991 0     0   0 $class -> new(shift);
6992             },
6993              
6994             binary => sub {
6995             # E.g., a literal 0377 shall result in an object whose
6996             # value is decimal 255, but new("0377") returns decimal
6997             # 377.
6998 0 0   0   0 return $class -> from_oct($_[0]) if $_[0] =~ /^0_*[0-7]/;
6999 0         0 $class -> new(shift);
7000 0         0 };
7001 0         0 next;
7002             }
7003              
7004             # Upgrading.
7005              
7006 11 100       29 if ($param eq 'upgrade') {
7007 2         15 $class -> upgrade(shift);
7008 2         6 next;
7009             }
7010              
7011             # Downgrading.
7012              
7013 9 100       39 if ($param eq 'downgrade') {
7014 1         9 $class -> downgrade(shift);
7015 1         4 next;
7016             }
7017              
7018             # Accuracy.
7019              
7020 8 50       16 if ($param eq 'accuracy') {
7021 0         0 $class -> accuracy(shift);
7022 0         0 next;
7023             }
7024              
7025             # Precision.
7026              
7027 8 50       21 if ($param eq 'precision') {
7028 0         0 $class -> precision(shift);
7029 0         0 next;
7030             }
7031              
7032             # Rounding mode.
7033              
7034 8 50       18 if ($param eq 'round_mode') {
7035 0         0 $class -> round_mode(shift);
7036 0         0 next;
7037             }
7038              
7039             # Fall-back accuracy.
7040              
7041 8 50       17 if ($param eq 'div_scale') {
7042 0         0 $class -> div_scale(shift);
7043 0         0 next;
7044             }
7045              
7046             # Backend library.
7047              
7048 8 100       50 if ($param =~ /^(lib|try|only)\z/) {
7049 6         11 push @import, $param;
7050 6 50       19 push @import, shift() if @_;
7051 6         16 next;
7052             }
7053              
7054 2 50       7 if ($param eq 'with') {
7055             # alternative class for our private parts()
7056             # XXX: no longer supported
7057             # $LIB = shift() || 'Calc';
7058             # carp "'with' is no longer supported, use 'lib', 'try', or 'only'";
7059 2         4 shift;
7060 2         6 next;
7061             }
7062              
7063             # Unrecognized parameter.
7064              
7065 0         0 push @a, $param;
7066             }
7067              
7068 61         484 Math::BigInt -> import(@import);
7069              
7070             # find out which library was actually loaded
7071 61         354 $LIB = Math::BigInt -> config('lib');
7072              
7073 61         523 $class -> SUPER::import(@a); # for subclasses
7074 61 50       59615 $class -> export_to_level(1, $class, @a) if @a; # need this, too
7075             }
7076              
7077             sub _len_to_steps {
7078             # Given D (digits in decimal), compute N so that N! (N factorial) is
7079             # at least D digits long. D should be at least 50.
7080 3     3   8 my $d = shift;
7081              
7082             # two constants for the Ramanujan estimate of ln(N!)
7083 3         5 my $lg2 = log(2 * 3.14159265) / 2;
7084 3         6 my $lg10 = log(10);
7085              
7086             # D = 50 => N => 42, so L = 40 and R = 50
7087 3         8 my $l = 40;
7088 3         4 my $r = $d;
7089              
7090             # Otherwise this does not work under -Mbignum and we do not yet have "no
7091             # bignum;" :(
7092 3 50       14 $l = $l -> numify if ref($l);
7093 3 50       11 $r = $r -> numify if ref($r);
7094 3 50       8 $lg2 = $lg2 -> numify if ref($lg2);
7095 3 50       9 $lg10 = $lg10 -> numify if ref($lg10);
7096              
7097             # binary search for the right value (could this be written as the reverse
7098             # of lg(n!)?)
7099 3         29 while ($r - $l > 1) {
7100 15         35 my $n = int(($r - $l) / 2) + $l;
7101 15         53 my $ramanujan
7102             = int(($n * log($n) - $n + log($n * (1 + 4*$n*(1+2*$n))) / 6 + $lg2)
7103             / $lg10);
7104 15 100       47 $ramanujan > $d ? $r = $n : $l = $n;
7105             }
7106 3         8 $l;
7107             }
7108              
7109             sub _log {
7110             # internal log function to calculate ln() based on Taylor series.
7111             # Modifies $x in place.
7112 137     137   381 my ($x, $scale) = @_;
7113 137         322 my $class = ref $x;
7114              
7115             # in case of $x == 1, result is 0
7116 137 100       573 return $x -> bzero() if $x -> is_one();
7117              
7118             # XXX TODO: rewrite this in a similar manner to bexp()
7119              
7120             # http://www.efunda.com/math/taylor_series/logarithmic.cfm?search_string=log
7121              
7122             # u = x-1, v = x+1
7123             # _ _
7124             # Taylor: | u 1 u^3 1 u^5 |
7125             # ln (x) = 2 | --- + - * --- + - * --- + ... | x > 0
7126             # |_ v 3 v^3 5 v^5 _|
7127              
7128             # This takes much more steps to calculate the result and is thus not used
7129             # u = x-1
7130             # _ _
7131             # Taylor: | u 1 u^2 1 u^3 |
7132             # ln (x) = 2 | --- + - * --- + - * --- + ... | x > 1/2
7133             # |_ x 2 x^2 3 x^3 _|
7134              
7135             # scale used in intermediate computations
7136 114         270 my $scaleup = $scale + 4;
7137              
7138 114         293 my ($v, $u, $numer, $denom, $factor, $f);
7139              
7140 114         354 $v = $x -> copy();
7141 114         513 $v = $v -> binc(); # v = x+1
7142 114         526 $x = $x -> bdec();
7143 114         500 $u = $x -> copy(); # u = x-1; x = x-1
7144              
7145 114         531 $x = $x -> bdiv($v, $scaleup); # first term: u/v
7146              
7147 114         610 $numer = $u -> copy(); # numerator
7148 114         324 $denom = $v -> copy(); # denominator
7149              
7150 114         488 $u = $u -> bmul($u); # u^2
7151 114         419 $v = $v -> bmul($v); # v^2
7152              
7153 114         448 $numer = $numer -> bmul($u); # u^3
7154 114         429 $denom = $denom -> bmul($v); # v^3
7155              
7156 114         579 $factor = $class -> new(3);
7157 114         468 $f = $class -> new(2);
7158              
7159 114         323 while (1) {
7160 3289         11065 my $next = $numer -> copy() -> bround($scaleup)
7161             -> bdiv($denom -> copy() -> bmul($factor) -> bround($scaleup), $scaleup);
7162              
7163 3289         20899 $next->{accuracy} = undef;
7164 3289         7000 $next->{precision} = undef;
7165 3289         10037 my $x_prev = $x -> copy();
7166 3289         11294 $x = $x -> badd($next);
7167              
7168 3289 100       11670 last if $x -> bacmp($x_prev) == 0;
7169              
7170             # calculate things for the next term
7171 3175         11505 $numer = $numer -> bmul($u);
7172 3175         9595 $denom = $denom -> bmul($v);
7173 3175         11127 $factor = $factor -> badd($f);
7174             }
7175              
7176 114         502 $x = $x -> bmul($f); # $x *= 2
7177 114         433 $x = $x -> bround($scale);
7178             }
7179              
7180             sub _log_10 {
7181             # Internal log function based on reducing input to the range of 0.1 .. 9.99
7182             # and then "correcting" the result to the proper one. Modifies $x in place.
7183 177     177   515 my ($x, $scale) = @_;
7184 177         450 my $class = ref $x;
7185              
7186             # Taking blog() from numbers greater than 10 takes a *very long* time, so
7187             # we break the computation down into parts based on the observation that:
7188             # blog(X*Y) = blog(X) + blog(Y)
7189             # We set Y here to multiples of 10 so that $x becomes below 1 - the smaller
7190             # $x is the faster it gets. Since 2*$x takes about 10 times as long, we
7191             # make it faster by about a factor of 100 by dividing $x by 10.
7192              
7193             # The same observation is valid for numbers smaller than 0.1, e.g.
7194             # computing log(1) is fastest, and the further away we get from 1, the
7195             # longer it takes. So we also 'break' this down by multiplying $x with 10
7196             # and subtract the log(10) afterwards to get the correct result.
7197              
7198             # To get $x even closer to 1, we also divide by 2 and then use log(2) to
7199             # correct for this. For instance if $x is 2.4, we use the formula:
7200             # blog(2.4 * 2) == blog(1.2) + blog(2)
7201             # and thus calculate only blog(1.2) and blog(2), which is faster in total
7202             # than calculating blog(2.4).
7203              
7204             # In addition, the values for blog(2) and blog(10) are cached.
7205              
7206             # Calculate the number of digits before the dot, i.e., 1 + floor(log10(x)):
7207             # x = 123 => dbd = 3
7208             # x = 1.23 => dbd = 1
7209             # x = 0.0123 => dbd = -1
7210             # x = 0.000123 => dbd = -3
7211             # etc.
7212              
7213 177         941 my $dbd = $LIB->_num($x->{_e});
7214 177 100       715 $dbd = -$dbd if $x->{_es} eq '-';
7215 177         781 $dbd += $LIB->_len($x->{_m});
7216              
7217             # more than one digit (e.g. at least 10), but *not* exactly 10 to avoid
7218             # infinite recursion
7219              
7220 177         367 my $calc = 1; # do some calculation?
7221              
7222             # No upgrading or downgrading in the intermediate computations.
7223              
7224 177         584 my $upg = $class -> upgrade();
7225 177         784 my $dng = $class -> downgrade();
7226 177         748 $class -> upgrade(undef);
7227 177         564 $class -> downgrade(undef);
7228              
7229             # disable the shortcut for 10, since we need log(10) and this would recurse
7230             # infinitely deep
7231 177 100 66     1159 if ($x->{_es} eq '+' && # $x == 10
      100        
7232             ($LIB->_is_one($x->{_e}) &&
7233             $LIB->_is_one($x->{_m})))
7234             {
7235 7         19 $dbd = 0; # disable shortcut
7236             # we can use the cached value in these cases
7237 7 50       35 if ($scale <= $LOG_10_A) {
7238 7         35 $x = $x -> bzero();
7239 7         833 $x = $x -> badd($LOG_10); # modify $x in place
7240 7         23 $calc = 0; # no need to calc, but round
7241             }
7242             # if we can't use the shortcut, we continue normally
7243             } else {
7244             # disable the shortcut for 2, since we maybe have it cached
7245 170 100 100     652 if (($LIB->_is_zero($x->{_e}) && # $x == 2
7246             $LIB->_is_two($x->{_m})))
7247             {
7248 34         101 $dbd = 0; # disable shortcut
7249             # we can use the cached value in these cases
7250 34 50       186 if ($scale <= $LOG_2_A) {
7251 34         170 $x = $x -> bzero();
7252 34         209 $x = $x -> badd($LOG_2); # modify $x in place
7253 34         165 $calc = 0; # no need to calc, but round
7254             }
7255             # if we can't use the shortcut, we continue normally
7256             }
7257             }
7258              
7259             # if $x = 0.1, we know the result must be 0-log(10)
7260 177 100 100     1310 if ($calc != 0 &&
      100        
      100        
7261             ($x->{_es} eq '-' && # $x == 0.1
7262             ($LIB->_is_one($x->{_e}) &&
7263             $LIB->_is_one($x->{_m}))))
7264             {
7265 2         4 $dbd = 0; # disable shortcut
7266             # we can use the cached value in these cases
7267 2 50       7 if ($scale <= $LOG_10_A) {
7268 2         7 $x = $x -> bzero();
7269 2         10 $x = $x -> bsub($LOG_10);
7270 2         6 $calc = 0; # no need to calc, but round
7271             }
7272             }
7273              
7274 177 100       634 return $x if $calc == 0; # already have the result
7275              
7276             # default: these correction factors are undef and thus not used
7277 134         350 my $l_10; # value of ln(10) to A of $scale
7278             my $l_2; # value of ln(2) to A of $scale
7279              
7280 134         663 my $two = $class -> new(2);
7281              
7282             # $x == 2 => 1, $x == 13 => 2, $x == 0.1 => 0, $x == 0.01 => -1
7283             # so don't do this shortcut for 1 or 0
7284 134 100 100     932 if (($dbd > 1) || ($dbd < 0)) {
7285             # convert our cached value to an object if not already (avoid doing
7286             # this at import() time, since not everybody needs this)
7287 54 100       306 $LOG_10 = $class -> new($LOG_10, undef, undef) unless ref $LOG_10;
7288              
7289             # got more than one digit before the dot, or more than one zero after
7290             # the dot, so do:
7291             # log(123) == log(1.23) + log(10) * 2
7292             # log(0.0123) == log(1.23) - log(10) * 2
7293              
7294 54 100       231 if ($scale <= $LOG_10_A) {
7295             # use cached value
7296 53         269 $l_10 = $LOG_10 -> copy(); # copy for mul
7297             } else {
7298             # else: slower, compute and cache result
7299              
7300             # shorten the time to calculate log(10) based on the following:
7301             # log(1.25 * 8) = log(1.25) + log(8)
7302             # = log(1.25) + log(2) + log(2) + log(2)
7303              
7304             # first get $l_2 (and possible compute and cache log(2))
7305 1 50       6 $LOG_2 = $class -> new($LOG_2, undef, undef) unless ref $LOG_2;
7306 1 50       5 if ($scale <= $LOG_2_A) {
7307             # use cached value
7308 1         5 $l_2 = $LOG_2 -> copy(); # copy() for the mul below
7309             } else {
7310             # else: slower, compute and cache result
7311 0         0 $l_2 = $two -> copy();
7312 0         0 $l_2 = $l_2->_log($scale); # scale+4, actually
7313 0         0 $LOG_2 = $l_2 -> copy(); # cache the result for later
7314             # the copy() is for mul below
7315 0         0 $LOG_2_A = $scale;
7316             }
7317              
7318             # now calculate log(1.25):
7319 1         4 $l_10 = $class -> new('1.25');
7320 1         7 $l_10 = $l_10->_log($scale); # scale+4, actually
7321              
7322             # log(1.25) + log(2) + log(2) + log(2):
7323 1         5 $l_10 = $l_10 -> badd($l_2);
7324 1         5 $l_10 = $l_10 -> badd($l_2);
7325 1         6 $l_10 = $l_10 -> badd($l_2);
7326 1         5 $LOG_10 = $l_10 -> copy(); # cache the result for later
7327             # the copy() is for mul below
7328 1         8 $LOG_10_A = $scale;
7329             }
7330 54 100       197 $dbd-- if ($dbd > 1); # 20 => dbd=2, so make it dbd=1
7331 54         194 $l_10 = $l_10 -> bmul($class -> new($dbd)); # log(10) * (digits_before_dot-1)
7332 54         322 my $dbd_sign = '+';
7333 54 100       188 if ($dbd < 0) {
7334 7         37 $dbd = -$dbd;
7335 7         17 $dbd_sign = '-';
7336             }
7337             ($x->{_e}, $x->{_es}) =
7338 54         299 $LIB -> _ssub($x->{_e}, $x->{_es}, $LIB->_new($dbd), $dbd_sign);
7339             }
7340              
7341             # Now: 0.1 <= $x < 10 (and possible correction in l_10)
7342              
7343             ### Since $x in the range 0.5 .. 1.5 is MUCH faster, we do a repeated div
7344             ### or mul by 2 (maximum times 3, since x < 10 and x > 0.1)
7345              
7346 134 100       596 $HALF = $class -> new($HALF) unless ref($HALF);
7347              
7348 134         291 my $twos = 0; # default: none (0 times)
7349 134         613 while ($x -> bacmp($HALF) <= 0) { # X <= 0.5
7350 42         112 $twos--;
7351 42         163 $x = $x -> bmul($two);
7352             }
7353 134         417 while ($x -> bacmp($two) >= 0) { # X >= 2
7354 58         114 $twos++;
7355 58         309 $x = $x -> bdiv($two, $scale+4); # keep all digits
7356             }
7357 134         638 $x = $x -> bround($scale+4);
7358             # $twos > 0 => did mul 2, < 0 => did div 2 (but we never did both)
7359             # So calculate correction factor based on ln(2):
7360 134 100       497 if ($twos != 0) {
7361 79 100       320 $LOG_2 = $class -> new($LOG_2, undef, undef) unless ref $LOG_2;
7362 79 100       266 if ($scale <= $LOG_2_A) {
7363             # use cached value
7364 77         339 $l_2 = $LOG_2 -> copy(); # copy() for the mul below
7365             } else {
7366             # else: slower, compute and cache result
7367 2         10 $l_2 = $two -> copy();
7368 2         11 $l_2 = $l_2->_log($scale); # scale+4, actually
7369 2         40 $LOG_2 = $l_2 -> copy(); # cache the result for later
7370             # the copy() is for mul below
7371 2         13 $LOG_2_A = $scale;
7372             }
7373 79         358 $l_2 = $l_2 -> bmul($twos); # * -2 => subtract, * 2 => add
7374             } else {
7375 55         141 undef $l_2;
7376             }
7377              
7378 134         691 $x = $x->_log($scale); # need to do the "normal" way
7379 134 100       656 $x = $x -> badd($l_10) if defined $l_10; # correct it by ln(10)
7380 134 100       716 $x = $x -> badd($l_2) if defined $l_2; # and maybe by ln(2)
7381              
7382             # Restore globals
7383              
7384 134         764 $class -> upgrade($upg);
7385 134         571 $class -> downgrade($dng);
7386              
7387             # all done, $x contains now the result
7388 134         1203 $x;
7389             }
7390              
7391             sub _pow {
7392             # Calculate a power where $y is a non-integer, like 2 ** 0.3
7393 115     115   478 my ($x, $y, @r) = @_;
7394 115         303 my $class = ref($x);
7395              
7396             # if $y == 0.5, it is sqrt($x)
7397 115 100       477 $HALF = $class -> new($HALF) unless ref($HALF);
7398 115 100       578 return $x -> bsqrt(@r, $y) if $y -> bcmp($HALF) == 0;
7399              
7400             # Using:
7401             # a ** x == e ** (x * ln a)
7402              
7403             # u = y * ln x
7404             # _ _
7405             # Taylor: | u u^2 u^3 |
7406             # x ** y = 1 + | --- + --- + ----- + ... |
7407             # |_ 1 1*2 1*2*3 _|
7408              
7409             # we need to limit the accuracy to protect against overflow
7410 70         166 my $fallback = 0;
7411 70         183 my ($scale, @params);
7412 70         338 ($x, @params) = $x->_find_round_parameters(@r);
7413              
7414 70 50       278 return $x if $x -> is_nan(); # error in _find_round_parameters?
7415              
7416             # no rounding at all, so must use fallback
7417 70 100       283 if (scalar @params == 0) {
7418             # simulate old behaviour
7419 52         238 $params[0] = $class -> div_scale(); # and round to it as accuracy
7420 52         112 $params[1] = undef; # disable P
7421 52         115 $scale = $params[0]+4; # at least four more for proper round
7422 52         123 $params[2] = $r[2]; # round mode by caller or undef
7423 52         97 $fallback = 1; # to clear a/p afterwards
7424             } else {
7425             # the 4 below is empirical, and there might be cases where it is not
7426             # enough...
7427 18   33     79 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
7428             }
7429              
7430             # When user set globals, they would interfere with our calculation, so
7431             # disable them and later re-enable them.
7432              
7433 70         242 my $ab = $class -> accuracy();
7434 70         244 my $pb = $class -> precision();
7435 70         255 $class -> accuracy(undef);
7436 70         250 $class -> precision(undef);
7437              
7438             # Disabling upgrading and downgrading is no longer necessary to avoid an
7439             # infinite recursion, but it avoids unnecessary upgrading and downgrading
7440             # in the intermediate computations.
7441              
7442 70         300 my $upg = $class -> upgrade();
7443 70         225 my $dng = $class -> downgrade();
7444 70         247 $class -> upgrade(undef);
7445 70         227 $class -> downgrade(undef);
7446              
7447             # We also need to disable any set A or P on $x (_find_round_parameters took
7448             # them already into account), since these would interfere, too.
7449              
7450 70         238 $x->{accuracy} = undef;
7451 70         257 $x->{precision} = undef;
7452              
7453 70         294 my ($limit, $v, $u, $below, $factor, $next, $over);
7454              
7455 70         306 $u = $x -> copy() -> blog(undef, $scale) -> bmul($y);
7456 70         274 my $do_invert = ($u->{sign} eq '-');
7457 70 100       332 $u = $u -> bneg() if $do_invert;
7458 70         374 $v = $class -> bone(); # 1
7459 70         378 $factor = $class -> new(2); # 2
7460 70         370 $x = $x -> bone(); # first term: 1
7461              
7462 70         274 $below = $v -> copy();
7463 70         238 $over = $u -> copy();
7464              
7465 70         454 $limit = $class -> new("1E-". ($scale-1));
7466 70         263 while (3 < 5) {
7467             # we calculate the next term, and add it to the last
7468             # when the next term is below our limit, it won't affect the outcome
7469             # anymore, so we stop:
7470 3302         10849 $next = $over -> copy() -> bdiv($below, $scale);
7471 3302 100       21313 last if $next -> bacmp($limit) <= 0;
7472 3232         10446 $x = $x -> badd($next);
7473             # calculate things for the next term
7474 3232         12966 $over *= $u;
7475 3232         9885 $below *= $factor;
7476 3232         10917 $factor = $factor -> binc();
7477              
7478 3232 50       18642 last if $x->{sign} !~ /^[-+]$/;
7479             }
7480              
7481 70 100       311 if ($do_invert) {
7482 31         115 my $x_copy = $x -> copy();
7483 31         171 $x = $x -> bone -> bdiv($x_copy, $scale);
7484             }
7485              
7486             # shortcut to not run through _find_round_parameters again
7487 70 50       292 if (defined $params[0]) {
7488 70         310 $x = $x -> bround($params[0], $params[2]); # then round accordingly
7489             } else {
7490 0         0 $x = $x -> bfround($params[1], $params[2]); # then round accordingly
7491             }
7492 70 100       274 if ($fallback) {
7493             # clear a/p after round, since user did not request it
7494 52         147 $x->{accuracy} = undef;
7495 52         143 $x->{precision} = undef;
7496             }
7497              
7498             # Restore globals. We need to do it like this, because setting one
7499             # undefines the other.
7500              
7501 70 50       227 if (defined $ab) {
7502 0         0 $class -> accuracy($ab);
7503             } else {
7504 70         321 $class -> precision($pb);
7505             }
7506              
7507 70         311 $class -> upgrade($upg);
7508 70         295 $class -> downgrade($dng);
7509              
7510 70         2718 $x;
7511             }
7512              
7513             # These functions are only provided for backwards compabibility so that old
7514             # version of Math::BigRat etc. don't complain about missing them.
7515              
7516             sub _e_add {
7517 0     0     my ($x, $y, $xs, $ys) = @_;
7518 0           return $LIB -> _sadd($x, $xs, $y, $ys);
7519             }
7520              
7521             sub _e_sub {
7522 0     0     my ($x, $y, $xs, $ys) = @_;
7523 0           return $LIB -> _ssub($x, $xs, $y, $ys);
7524             }
7525              
7526             1;
7527              
7528             __END__