File Coverage

blib/lib/Sidef/Types/Number/Number.pm
Criterion Covered Total %
statement 5 7 71.4
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 8 10 80.0


line stmt bran cond sub pod time code
1             package Sidef::Types::Number::Number {
2              
3 1     1   19 use utf8;
  1         6  
4 1     1   55 use 5.016;
  1         5  
5              
6 1     1   204 use Math::MPFR qw();
  0            
  0            
7             use Math::GMPq qw();
8             use Math::GMPz qw();
9             use Math::MPC qw();
10              
11             use Math::Prime::Util::GMP qw();
12             use POSIX qw(ULONG_MAX LONG_MIN);
13              
14             our ($ROUND, $PREC);
15              
16             BEGIN {
17             $ROUND = Math::MPFR::MPFR_RNDN();
18             $PREC = 192;
19             }
20              
21             state $round_z = Math::MPFR::MPFR_RNDZ();
22              
23             state $ONE = Math::GMPz::Rmpz_init_set_ui(1);
24             state $ZERO = Math::GMPz::Rmpz_init_set_ui(0);
25             state $MONE = Math::GMPz::Rmpz_init_set_si(-1);
26              
27             #<<<
28             use constant {
29             ONE => bless(\$ONE),
30             ZERO => bless(\$ZERO),
31             MONE => bless(\$MONE),
32             };
33             #>>>
34              
35             use parent qw(
36             Sidef::Object::Object
37             Sidef::Convert::Convert
38             );
39              
40             use overload
41             q{bool} => sub { (@_) = (${$_[0]}); goto &__boolify__ },
42             q{0+} => sub { (@_) = (${$_[0]}); goto &__numify__ },
43             q{""} => sub { (@_) = (${$_[0]}); goto &__stringify__ };
44              
45             use Sidef::Types::Bool::Bool;
46              
47             my @cache = (ZERO, ONE);
48              
49             sub new {
50             my (undef, $num, $base) = @_;
51              
52             if (ref($base)) {
53             if (ref($base) eq __PACKAGE__) {
54             $base = _any2ui($$base) // 0;
55             }
56             else {
57             $base = CORE::int($base);
58             }
59             }
60              
61             my $ref = ref($num);
62              
63             # Special string values
64             if (!$ref and (!defined($base) or $base == 10)) {
65             return bless \_str2obj($num);
66             }
67              
68             # Number with base
69             elsif (defined($base) and $base != 10) {
70              
71             my $int_base = CORE::int($base);
72              
73             if ($int_base < 2 or $int_base > 36) {
74             die "[ERROR] Number(): base must be between 2 and 36, got $base";
75             }
76              
77             $num = defined($num) ? "$num" : '0';
78              
79             if (index($num, '/') != -1) {
80             my $r = Math::GMPq::Rmpq_init();
81             eval { Math::GMPq::Rmpq_set_str($r, $num, $int_base); 1 } // goto &nan;
82             if (Math::GMPq::Rmpq_get_str($r, 10) !~ m{^\s*[-+]?[0-9]+\s*/\s*[-+]?[1-9]+[0-9]*\s*\z}) {
83             goto &nan;
84             }
85             Math::GMPq::Rmpq_canonicalize($r);
86             return bless \$r;
87             }
88             elsif (substr($num, 0, 1) eq '(' and substr($num, -1) eq ')') {
89             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
90             if (Math::MPC::Rmpc_set_str($r, $num, $int_base, $ROUND)) {
91             goto &nan;
92             }
93             return bless \$r;
94             }
95             elsif (index($num, '.') != -1) {
96             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
97             if (Math::MPFR::Rmpfr_set_str($r, $num, $int_base, $ROUND)) {
98             goto &nan;
99             }
100             return bless \$r;
101             }
102             else {
103             my $r = eval { Math::GMPz::Rmpz_init_set_str($num, $int_base) } // goto &nan;
104             return bless \$r;
105             }
106             }
107              
108             # Special objects
109             elsif ($ref eq __PACKAGE__) {
110             return $num;
111             }
112              
113             # GMPz
114             elsif ($ref eq 'Math::GMPz') {
115             return bless \Math::GMPz::Rmpz_init_set($num);
116             }
117              
118             # MPFR
119             elsif ($ref eq 'Math::MPFR') {
120             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
121             Math::MPFR::Rmpfr_set($r, $num, $ROUND);
122             return bless \$r;
123             }
124              
125             # MPC
126             elsif ($ref eq 'Math::MPC') {
127             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
128             Math::MPC::Rmpc_set($r, $num, $ROUND);
129             return bless \$r;
130             }
131              
132             # GMPq
133             elsif ($ref eq 'Math::GMPq') {
134             my $r = Math::GMPq::Rmpq_init();
135             Math::GMPq::Rmpq_set($r, $num);
136             return bless \$r;
137             }
138              
139             bless \_str2obj("$num");
140             }
141              
142             *call = \&new;
143              
144             sub _valid {
145             (
146             ref($$_) eq __PACKAGE__
147             or do {
148             my $sub = overload::Method($$_, '0+');
149              
150             my $tmp = (
151             defined($sub)
152             ? __PACKAGE__->new($sub->($$_))
153             : do {
154             my (undef, undef, undef, $caller) = caller(1);
155             die "[ERROR] Value <<$$_>> cannot be implicitly converted to a number, inside <<$caller>>!\n";
156             }
157             );
158              
159             if (ref($tmp) ne __PACKAGE__) { # this should not happen
160             my (undef, undef, undef, $caller) = caller(1);
161             die "[ERROR] Cannot convert <<$$_>> to a number, inside <<$caller>>! (is method \"to_n\" well-defined?)\n";
162             }
163              
164             $$_ = $tmp;
165             }
166             ) for @_;
167             }
168              
169             sub _set_uint {
170             $_[1] <= 8192
171             ? exists($cache[$_[1]])
172             ? $cache[$_[1]]
173             : ($cache[$_[1]] = bless \Math::GMPz::Rmpz_init_set_ui($_[1]))
174             : bless \Math::GMPz::Rmpz_init_set_ui($_[1]);
175             }
176              
177             sub _set_int {
178             $_[1] == -1 && return MONE;
179             $_[1] >= 0 && goto &_set_uint;
180             bless \Math::GMPz::Rmpz_init_set_si($_[1]);
181             }
182              
183             sub _dump {
184             my $x = ${$_[0]};
185              
186             my $ref = ref($x);
187              
188             if ($ref eq 'Math::GMPz') {
189             ('int', Math::GMPz::Rmpz_get_str($x, 10));
190             }
191             elsif ($ref eq 'Math::GMPq') {
192             ('rat', Math::GMPq::Rmpq_get_str($x, 10));
193             }
194             elsif ($ref eq 'Math::MPFR') {
195             ('float', Math::MPFR::Rmpfr_get_str($x, 10, 0, $ROUND));
196             }
197             elsif ($ref eq 'Math::MPC') {
198             ('complex', Math::MPC::Rmpc_get_str(10, 0, $x, $ROUND));
199             }
200             else {
201             die "[ERROR] This shouldn't happen: <<$x>> as <<$ref>>";
202             }
203             }
204              
205             sub _set_str {
206             my (undef, $type, $str) = @_;
207              
208             if ($type eq 'int') {
209             bless \Math::GMPz::Rmpz_init_set_str($str, 10);
210             }
211             elsif ($type eq 'rat') {
212             Math::GMPq::Rmpq_set_str((my $r = Math::GMPq::Rmpq_init()), $str, 10);
213             bless \$r;
214             }
215             elsif ($type eq 'float') {
216             Math::MPFR::Rmpfr_set_str((my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC))), $str, 10, $ROUND);
217             bless \$r;
218             }
219             elsif ($type eq 'complex') {
220             Math::MPC::Rmpc_set_str((my $r = Math::MPC::Rmpc_init2(CORE::int($PREC))), $str, 10, $ROUND);
221             bless \$r;
222             }
223             else {
224             die "[ERROR] Number._set_str(): invalid type <<$type>> with content <<$str>>";
225             }
226             }
227              
228             sub _str2frac {
229             my $str = lc($_[0]);
230              
231             my $sign = substr($str, 0, 1);
232             if ($sign eq '-') {
233             substr($str, 0, 1, '');
234             $sign = '-';
235             }
236             else {
237             substr($str, 0, 1, '') if ($sign eq '+');
238             $sign = '';
239             }
240              
241             my $i;
242             if (($i = index($str, 'e')) != -1) {
243              
244             my $exp = substr($str, $i + 1);
245              
246             # Handle specially numbers with very big exponents
247             # (it's not a very good solution, but I hope it's only temporary)
248             if (CORE::abs($exp) >= 1000000) {
249             Math::MPFR::Rmpfr_set_str((my $mpfr = Math::MPFR::Rmpfr_init2(CORE::int($PREC))), "$sign$str", 10, $ROUND);
250             Math::MPFR::Rmpfr_get_q((my $mpq = Math::GMPq::Rmpq_init()), $mpfr);
251             return Math::GMPq::Rmpq_get_str($mpq, 10);
252             }
253              
254             my ($before, $after) = split(/\./, substr($str, 0, $i));
255              
256             if (!defined($after)) { # return faster for numbers like "13e2"
257             if ($exp >= 0) {
258             return ("$sign$before" . ('0' x $exp));
259             }
260             else {
261             $after = '';
262             }
263             }
264              
265             my $numerator = "$before$after";
266             my $denominator = "1";
267              
268             if ($exp < 1) {
269             $denominator .= '0' x (CORE::abs($exp) + CORE::length($after));
270             }
271             else {
272             my $diff = ($exp - CORE::length($after));
273             if ($diff >= 0) {
274             $numerator .= '0' x $diff;
275             }
276             else {
277             my $s = "$before$after";
278             substr($s, $exp + CORE::length($before), 0, '.');
279             return __SUB__->("$sign$s");
280             }
281             }
282              
283             "$sign$numerator/$denominator";
284             }
285             elsif (($i = index($str, '.')) != -1) {
286             my ($before, $after) = (substr($str, 0, $i), substr($str, $i + 1));
287             if (($after =~ tr/0//) == CORE::length($after)) {
288             return "$sign$before";
289             }
290             $sign . ("$before$after/1" =~ s/^0+//r) . ('0' x CORE::length($after));
291             }
292             else {
293             "$sign$str";
294             }
295             }
296              
297             #
298             ## Misc internal functions
299             #
300              
301             # Converts a string into an mpq object
302             sub _str2obj {
303             my ($s) = @_;
304              
305             $s || return $ZERO;
306              
307             $s = lc($s);
308              
309             if ($s eq 'inf' or $s eq '+inf') {
310             goto &_inf;
311             }
312             elsif ($s eq '-inf') {
313             goto &_ninf;
314             }
315             elsif ($s eq 'nan') {
316             goto &_nan;
317             }
318              
319             # Remove underscores
320             $s =~ tr/_//d;
321              
322             # Performance improvement for Perl integers
323             if (CORE::int($s) eq $s and $s >= LONG_MIN and $s <= ULONG_MAX) {
324             return (
325             $s < 0
326             ? Math::GMPz::Rmpz_init_set_si($s)
327             : Math::GMPz::Rmpz_init_set_ui($s)
328             );
329             }
330              
331             # Floating-point
332             if ($s =~ /^([+-]?+(?=\.?[0-9])[0-9_]*+(?:\.[0-9_]++)?(?:[Ee](?:[+-]?+[0-9_]+))?)\z/) {
333             my $frac = _str2frac($1);
334              
335             if (index($frac, '/') != -1) {
336             my $q = Math::GMPq::Rmpq_init();
337             Math::GMPq::Rmpq_set_str($q, $frac, 10);
338             Math::GMPq::Rmpq_canonicalize($q);
339             return $q;
340             }
341             else {
342             my $z = Math::GMPz::Rmpz_init();
343             Math::GMPz::Rmpz_set_str($z, $frac, 10);
344             return $z;
345             }
346             }
347              
348             # Complex number
349             if (substr($s, -1) eq 'i') {
350              
351             if ($s eq 'i' or $s eq '+i') {
352             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
353             Math::MPC::Rmpc_set_ui_ui($r, 0, 1, $ROUND);
354             return $r;
355             }
356             elsif ($s eq '-i') {
357             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
358             Math::MPC::Rmpc_set_si_si($r, 0, -1, $ROUND);
359             return $r;
360             }
361              
362             my ($re, $im);
363              
364             state $numeric_re = qr/[+-]?+(?=\.?[0-9])[0-9]*+(?:\.[0-9]++)?(?:[Ee](?:[+-]?+[0-9]+))?/;
365             state $unsigned_re = qr/(?=\.?[0-9])[0-9]*+(?:\.[0-9]++)?(?:[Ee](?:[+-]?+[0-9]+))?/;
366              
367             if ($s =~ /^($numeric_re)\s*([-+])\s*($unsigned_re)i\z/o) {
368             ($re, $im) = ($1, $3);
369             $im = "-$im" if $2 eq '-';
370             }
371             elsif ($s =~ /^($numeric_re)i\z/o) {
372             ($re, $im) = (0, $1);
373             }
374             elsif ($s =~ /^($numeric_re)\s*([-+])\s*i\z/o) {
375             ($re, $im) = ($1, 1);
376             $im = -1 if $2 eq '-';
377             }
378              
379             if (defined($re) and defined($im)) {
380              
381             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
382              
383             $re = _str2obj($re);
384             $im = _str2obj($im);
385              
386             my $sig = join(' ', ref($re), ref($im));
387              
388             if ($sig eq q{Math::MPFR Math::MPFR}) {
389             Math::MPC::Rmpc_set_fr_fr($r, $re, $im, $ROUND);
390             }
391             elsif ($sig eq q{Math::GMPz Math::GMPz}) {
392             Math::MPC::Rmpc_set_z_z($r, $re, $im, $ROUND);
393             }
394             elsif ($sig eq q{Math::GMPz Math::MPFR}) {
395             Math::MPC::Rmpc_set_z_fr($r, $re, $im, $ROUND);
396             }
397             elsif ($sig eq q{Math::MPFR Math::GMPz}) {
398             Math::MPC::Rmpc_set_fr_z($r, $re, $im, $ROUND);
399             }
400             else { # this should never happen
401             $re = _any2mpfr($re);
402             $im = _any2mpfr($im);
403             Math::MPC::Rmpc_set_fr_fr($r, $re, $im, $ROUND);
404             }
405              
406             return $r;
407             }
408             }
409              
410             # Floating point value
411             if ($s =~ tr/e.//) {
412             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
413             if (Math::MPFR::Rmpfr_set_str($r, $s, 10, $ROUND)) {
414             Math::MPFR::Rmpfr_set_nan($r);
415             }
416             return $r;
417             }
418              
419             # Fractional value
420             if (index($s, '/') != -1 and $s =~ m{^\s*[-+]?[0-9]+\s*/\s*[-+]?[1-9]+[0-9]*\s*\z}) {
421             my $r = Math::GMPq::Rmpq_init();
422             Math::GMPq::Rmpq_set_str($r, $s, 10);
423             Math::GMPq::Rmpq_canonicalize($r);
424             return $r;
425             }
426              
427             $s =~ s/^\+//;
428              
429             eval { Math::GMPz::Rmpz_init_set_str($s, 10) } // goto &_nan;
430             }
431              
432             #
433             ## MPZ
434             #
435             sub _mpz2mpq {
436             my $r = Math::GMPq::Rmpq_init();
437             Math::GMPq::Rmpq_set_z($r, $_[0]);
438             $r;
439             }
440              
441             sub _mpz2mpfr {
442             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
443             Math::MPFR::Rmpfr_set_z($r, $_[0], $ROUND);
444             $r;
445             }
446              
447             sub _mpz2mpc {
448             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
449             Math::MPC::Rmpc_set_z($r, $_[0], $ROUND);
450             $r;
451             }
452              
453             #
454             ## MPQ
455             #
456             sub _mpq2mpz {
457             my $z = Math::GMPz::Rmpz_init();
458             Math::GMPz::Rmpz_set_q($z, $_[0]);
459             $z;
460             }
461              
462             sub _mpq2mpfr {
463             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
464             Math::MPFR::Rmpfr_set_q($r, $_[0], $ROUND);
465             $r;
466             }
467              
468             sub _mpq2mpc {
469             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
470             Math::MPC::Rmpc_set_q($r, $_[0], $ROUND);
471             $r;
472             }
473              
474             #
475             ## MPFR
476             #
477             sub _mpfr2mpc {
478             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
479             Math::MPC::Rmpc_set_fr($r, $_[0], $ROUND);
480             $r;
481             }
482              
483             #
484             ## Any to MPC (complex)
485             #
486             sub _any2mpc {
487             my ($x) = @_;
488              
489             ref($x) eq 'Math::MPC' && return $x;
490             ref($x) eq 'Math::GMPz' && goto &_mpz2mpc;
491             ref($x) eq 'Math::GMPq' && goto &_mpq2mpc;
492              
493             goto &_mpfr2mpc;
494             }
495              
496             #
497             ## Any to MPFR (floating-point)
498             #
499             sub _any2mpfr {
500             my ($x) = @_;
501              
502             ref($x) eq 'Math::MPFR' && return $x;
503             ref($x) eq 'Math::GMPz' && goto &_mpz2mpfr;
504             ref($x) eq 'Math::GMPq' && goto &_mpq2mpfr;
505              
506             my $fr = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
507             Math::MPC::RMPC_IM($fr, $x);
508              
509             if (Math::MPFR::Rmpfr_zero_p($fr)) {
510             Math::MPC::RMPC_RE($fr, $x);
511             }
512             else {
513             Math::MPFR::Rmpfr_set_nan($fr);
514             }
515              
516             $fr;
517             }
518              
519             #
520             ## Any to MPFR or MPC, in this order
521             #
522             sub _any2mpfr_mpc {
523             my ($x) = @_;
524              
525             if ( ref($x) eq 'Math::MPFR'
526             or ref($x) eq 'Math::MPC') {
527             return $x;
528             }
529              
530             ref($x) eq 'Math::GMPz' && goto &_mpz2mpfr;
531             ref($x) eq 'Math::GMPq' && goto &_mpq2mpfr;
532             goto &_any2mpfr; # this should not happen
533             }
534              
535             #
536             ## Any to GMPz (integer)
537             #
538             sub _any2mpz {
539             my ($x) = @_;
540              
541             ref($x) eq 'Math::GMPz' && return $x;
542             ref($x) eq 'Math::GMPq' && goto &_mpq2mpz;
543              
544             if (ref($x) eq 'Math::MPFR') {
545             if (Math::MPFR::Rmpfr_number_p($x)) {
546             my $z = Math::GMPz::Rmpz_init();
547             Math::MPFR::Rmpfr_get_z($z, $x, $round_z);
548             return $z;
549             }
550             return;
551             }
552              
553             (@_) = _any2mpfr($x);
554             goto &_any2mpz;
555             }
556              
557             #
558             ## Any to GMPq (rational)
559             #
560             sub _any2mpq {
561             my ($x) = @_;
562              
563             ref($x) eq 'Math::GMPq' && return $x;
564             ref($x) eq 'Math::GMPz' && goto &_mpz2mpq;
565              
566             if (ref($x) eq 'Math::MPFR') {
567             if (Math::MPFR::Rmpfr_number_p($x)) {
568             my $q = Math::GMPq::Rmpq_init();
569             Math::MPFR::Rmpfr_get_q($q, $x);
570             return $q;
571             }
572             return;
573             }
574              
575             (@_) = _any2mpfr($x);
576             goto &_any2mpq;
577             }
578              
579             #
580             ## Any to unsigned integer
581             #
582             sub _any2ui {
583             my ($x) = @_;
584              
585             if (ref($x) eq 'Math::GMPz') {
586             my $d = CORE::int(Math::GMPz::Rmpz_get_d($x));
587             ($d < 0 or $d > ULONG_MAX) && return;
588             return $d;
589             }
590              
591             if (ref($x) eq 'Math::GMPq') {
592             my $d = CORE::int(Math::GMPq::Rmpq_get_d($x));
593             ($d < 0 or $d > ULONG_MAX) && return;
594             return $d;
595             }
596              
597             if (ref($x) eq 'Math::MPFR') {
598             if (Math::MPFR::Rmpfr_number_p($x)) {
599             my $d = CORE::int(Math::MPFR::Rmpfr_get_d($x, $ROUND));
600             ($d < 0 or $d > ULONG_MAX) && return;
601             return $d;
602             }
603             return;
604             }
605              
606             (@_) = _any2mpfr($x);
607             goto &_any2ui;
608             }
609              
610             #
611             ## Any to signed integer
612             #
613             sub _any2si {
614             my ($x) = @_;
615              
616             if (ref($x) eq 'Math::GMPz') {
617             my $d = CORE::int(Math::GMPz::Rmpz_get_d($x));
618             ($d < LONG_MIN or $d > ULONG_MAX) && return;
619             return $d;
620             }
621              
622             if (ref($x) eq 'Math::GMPq') {
623             my $d = CORE::int(Math::GMPq::Rmpq_get_d($x));
624             ($d < LONG_MIN or $d > ULONG_MAX) && return;
625             return $d;
626             }
627              
628             if (ref($x) eq 'Math::MPFR') {
629             if (Math::MPFR::Rmpfr_number_p($x)) {
630             my $d = CORE::int(Math::MPFR::Rmpfr_get_d($x, $ROUND));
631             ($d < LONG_MIN or $d > ULONG_MAX) && return;
632             return $d;
633             }
634             return;
635             }
636              
637             (@_) = _any2mpfr($x);
638             goto &_any2si;
639             }
640              
641             sub _big2istr {
642             my ($x) = @_;
643             Math::GMPz::Rmpz_get_str((_any2mpz($$x) // return undef), 10);
644             }
645              
646             sub _big2uistr {
647             my ($x) = @_;
648             my $str = Math::GMPz::Rmpz_get_str((_any2mpz($$x) // return undef), 10);
649             $str < 0 && return undef;
650             "$str";
651             }
652              
653             #
654             ## Internal conversion methods
655             #
656              
657             sub __boolify__ {
658             my ($x) = @_;
659             goto(ref($x) =~ tr/:/_/rs);
660              
661             Math_MPFR: {
662             return !Math::MPFR::Rmpfr_zero_p($x);
663             }
664              
665             Math_GMPq: {
666             return !!Math::GMPq::Rmpq_sgn($x);
667             }
668              
669             Math_GMPz: {
670             return !!Math::GMPz::Rmpz_sgn($x);
671             }
672              
673             Math_MPC: {
674             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
675             Math::MPC::RMPC_RE($r, $x);
676             Math::MPFR::Rmpfr_zero_p($r) || return 1;
677             Math::MPC::RMPC_IM($r, $x);
678             return !Math::MPFR::Rmpfr_zero_p($r);
679             }
680             }
681              
682             sub __numify__ {
683             my ($x) = @_;
684             goto(ref($x) =~ tr/:/_/rs);
685              
686             Math_MPFR: {
687             return Math::MPFR::Rmpfr_get_d($x, $ROUND);
688             }
689              
690             Math_GMPq: {
691             goto &Math::GMPq::Rmpq_get_d;
692             }
693              
694             Math_GMPz: {
695             goto &Math::GMPz::Rmpz_get_d;
696             }
697              
698             Math_MPC: {
699             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
700             Math::MPC::RMPC_RE($r, $x);
701             return Math::MPFR::Rmpfr_get_d($r, $ROUND);
702             }
703             }
704              
705             sub __stringify__ {
706             my ($x) = @_;
707             goto(ref($x) =~ tr/:/_/rs);
708              
709             Math_GMPz: {
710             return Math::GMPz::Rmpz_get_str($x, 10);
711             }
712              
713             Math_GMPq: {
714              
715             #~ return Math::GMPq::Rmpq_get_str($x, 10);
716             Math::GMPq::Rmpq_integer_p($x) && return Math::GMPq::Rmpq_get_str($x, 10);
717              
718             $PREC = CORE::int($PREC) if ref($PREC);
719              
720             my $prec = $PREC >> 2;
721             my $sgn = Math::GMPq::Rmpq_sgn($x);
722              
723             my $n = Math::GMPq::Rmpq_init();
724             Math::GMPq::Rmpq_set($n, $x);
725             Math::GMPq::Rmpq_abs($n, $n) if $sgn < 0;
726              
727             my $p = Math::GMPq::Rmpq_init();
728             Math::GMPq::Rmpq_set_str($p, '1' . ('0' x CORE::abs($prec)), 10);
729              
730             if ($prec < 0) {
731             Math::GMPq::Rmpq_div($n, $n, $p);
732             }
733             else {
734             Math::GMPq::Rmpq_mul($n, $n, $p);
735             }
736              
737             state $half = do {
738             my $q = Math::GMPq::Rmpq_init_nobless();
739             Math::GMPq::Rmpq_set_ui($q, 1, 2);
740             $q;
741             };
742              
743             my $z = Math::GMPz::Rmpz_init();
744             Math::GMPq::Rmpq_add($n, $n, $half);
745             Math::GMPz::Rmpz_set_q($z, $n);
746              
747             # Too much rounding... Give up and return an MPFR stringified number.
748             !Math::GMPz::Rmpz_sgn($z) && $PREC >= 2 && do {
749             my $mpfr = Math::MPFR::Rmpfr_init2($PREC);
750             Math::MPFR::Rmpfr_set_q($mpfr, $x, $ROUND);
751             return Math::MPFR::Rmpfr_get_str($mpfr, 10, $prec, $ROUND);
752             };
753              
754             if (Math::GMPz::Rmpz_odd_p($z) and Math::GMPq::Rmpq_integer_p($n)) {
755             Math::GMPz::Rmpz_sub_ui($z, $z, 1);
756             }
757              
758             Math::GMPq::Rmpq_set_z($n, $z);
759              
760             if ($prec < 0) {
761             Math::GMPq::Rmpq_mul($n, $n, $p);
762             }
763             else {
764             Math::GMPq::Rmpq_div($n, $n, $p);
765             }
766              
767             my $num = Math::GMPz::Rmpz_init();
768             my $den = Math::GMPz::Rmpz_init();
769              
770             Math::GMPq::Rmpq_numref($num, $n);
771             Math::GMPq::Rmpq_denref($den, $n);
772              
773             my @r;
774             while (1) {
775             Math::GMPz::Rmpz_div($z, $num, $den);
776             push @r, Math::GMPz::Rmpz_get_str($z, 10);
777              
778             Math::GMPz::Rmpz_mul($z, $z, $den);
779             Math::GMPz::Rmpz_sub($num, $num, $z);
780             last if !Math::GMPz::Rmpz_sgn($num);
781              
782             my $s = -1;
783             while (Math::GMPz::Rmpz_cmp($den, $num) > 0) {
784             Math::GMPz::Rmpz_mul_ui($num, $num, 10);
785             ++$s;
786             }
787              
788             push(@r, '0' x $s) if ($s > 0);
789             }
790              
791             return (($sgn < 0 ? "-" : '') . shift(@r) . (('.' . join('', @r)) =~ s/0+\z//r =~ s/\.\z//r));
792             }
793              
794             Math_MPFR: {
795             Math::MPFR::Rmpfr_number_p($x)
796             || return (
797             Math::MPFR::Rmpfr_nan_p($x) ? 'NaN'
798             : Math::MPFR::Rmpfr_sgn($x) < 0 ? '-Inf'
799             : 'Inf'
800             );
801              
802             # log(10)/log(2) =~ 3.3219280948873623
803             my $digits = CORE::int($PREC) >> 2;
804             my ($mantissa, $exponent) = Math::MPFR::Rmpfr_deref2($x, 10, $digits, $ROUND);
805              
806             my $sgn = '';
807             if (substr($mantissa, 0, 1) eq '-') {
808             $sgn = substr($mantissa, 0, 1, '');
809             }
810              
811             $mantissa =~ /[^0]/ or return '0';
812              
813             if (CORE::abs($exponent) < CORE::length($mantissa)) {
814              
815             if ($exponent > 0) {
816             substr($mantissa, $exponent, 0, '.');
817             }
818             else {
819             substr($mantissa, 0, 0, '0.' . ('0' x CORE::abs($exponent)));
820             }
821              
822             $mantissa = reverse($mantissa);
823             $mantissa =~ s/^0+//;
824             $mantissa =~ s/^\.//;
825             $mantissa = reverse($mantissa);
826              
827             return ($sgn . $mantissa);
828             }
829              
830             if (CORE::length($mantissa) > 1) {
831             substr($mantissa, 1, 0, '.');
832             }
833              
834             return ($sgn . $mantissa . 'e' . ($exponent - 1));
835             }
836              
837             Math_MPC: {
838             my $fr = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
839              
840             Math::MPC::RMPC_RE($fr, $x);
841             my $re = __SUB__->($fr);
842              
843             Math::MPC::RMPC_IM($fr, $x);
844             my $im = __SUB__->($fr);
845              
846             if ($im eq '0' or $im eq '-0') {
847             return $re;
848             }
849              
850             my $sign = '+';
851              
852             if (substr($im, 0, 1) eq '-') {
853             $sign = '-';
854             substr($im, 0, 1, '');
855             }
856              
857             $im = '' if $im eq '1';
858             return ($re eq '0' ? $sign eq '+' ? "${im}i" : "$sign${im}i" : "$re$sign${im}i");
859             }
860             }
861              
862             sub get_value {
863             (@_) = (${$_[0]});
864             goto &__stringify__;
865             }
866              
867             #
868             ## Public conversion methods
869             #
870              
871             sub int {
872             my ($x) = @_;
873             ref($$x) eq 'Math::GMPz' ? $x : bless \(_any2mpz($$x) // (goto &nan));
874             }
875              
876             *trunc = \∫
877              
878             sub rat {
879             my ($x) = @_;
880             ref($$x) eq 'Math::GMPq' ? $x : bless \(_any2mpq($$x) // (goto &nan));
881             }
882              
883             sub float {
884             my ($x) = @_;
885             ref($$x) eq 'Math::MPFR' ? $x : bless \_any2mpfr($$x);
886             }
887              
888             sub complex {
889             my ($x) = @_;
890             ref($$x) eq 'Math::MPC' ? $x : bless \_any2mpc($$x);
891             }
892              
893             sub rat_approx {
894             my ($x) = @_;
895              
896             $x = _any2mpfr($$x);
897              
898             Math::MPFR::Rmpfr_number_p($x) || goto &nan;
899              
900             my $t = Math::MPFR::Rmpfr_init2(CORE::int($PREC)); # temporary variable
901             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
902              
903             Math::MPFR::Rmpfr_set($r, $x, $ROUND);
904              
905             my $num2cfrac = sub {
906             my ($callback, $n) = @_;
907              
908             while (1) {
909             Math::MPFR::Rmpfr_floor($t, $r);
910              
911             my $z = Math::GMPz::Rmpz_init();
912             Math::MPFR::Rmpfr_get_z($z, $t, $round_z);
913              
914             $callback->($z) && return 1;
915              
916             Math::MPFR::Rmpfr_sub($r, $r, $t, $ROUND);
917             Math::MPFR::Rmpfr_zero_p($r) && last;
918             Math::MPFR::Rmpfr_ui_div($r, 1, $r, $ROUND);
919             }
920             };
921              
922             my $q = Math::GMPq::Rmpq_init();
923              
924             my $cfrac2num = sub {
925             my (@f) = @_;
926              
927             Math::GMPq::Rmpq_set_ui($q, 0, 1);
928              
929             for (1 .. $#f) {
930             Math::GMPq::Rmpq_add_z($q, $q, CORE::pop(@f));
931             Math::GMPq::Rmpq_inv($q, $q);
932             }
933              
934             Math::GMPq::Rmpq_add_z($q, $q, $f[0]);
935             };
936              
937             my @cfrac;
938             my $s = __stringify__($x);
939             my $u = Math::MPFR::Rmpfr_init2(CORE::int($PREC)); # temporary variable
940              
941             #<<<
942             $num2cfrac->(
943             sub {
944             my ($n) = @_;
945             CORE::push(@cfrac, $n);
946             $cfrac2num->(@cfrac);
947             Math::MPFR::Rmpfr_set_q($u, $q, $ROUND);
948             CORE::index(__stringify__($u), $s) == 0;
949             }, $x
950             );
951             #>>>
952              
953             bless \$q;
954             }
955              
956             sub pair {
957             my ($x, $y) = @_;
958             Sidef::Types::Number::Complex->new($x, $y);
959             }
960              
961             sub __norm__ {
962             my ($x) = @_;
963              
964             goto(ref($x) =~ tr/:/_/rs);
965              
966             Math_MPC: {
967             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
968             Math::MPC::Rmpc_norm($r, $x, $ROUND);
969             return $r;
970             }
971              
972             Math_MPFR: {
973             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
974             Math::MPFR::Rmpfr_sqr($r, $x, $ROUND);
975             return $r;
976             }
977              
978             Math_GMPz: {
979             my $r = Math::GMPz::Rmpz_init();
980             Math::GMPz::Rmpz_mul($r, $x, $x);
981             return $r;
982             }
983              
984             Math_GMPq: {
985             my $r = Math::GMPq::Rmpq_init();
986             Math::GMPq::Rmpq_mul($r, $x, $x);
987             return $r;
988             }
989             }
990              
991             sub norm {
992             my ($x) = @_;
993             bless \__norm__($$x);
994             }
995              
996             sub conj {
997             my ($x) = @_;
998             ref($$x) eq 'Math::MPC' or return $x;
999             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1000             Math::MPC::Rmpc_conj($r, $$x, $ROUND);
1001             bless \$r;
1002             }
1003              
1004             *conjug = \&conj;
1005             *conjugate = \&conj;
1006              
1007             sub real {
1008             my ($x) = @_;
1009              
1010             if (ref($$x) eq 'Math::MPC') {
1011             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1012             Math::MPC::RMPC_RE($r, $$x);
1013             bless \$r;
1014             }
1015             else {
1016             $x;
1017             }
1018             }
1019              
1020             *re = \ℜ
1021              
1022             sub imag {
1023             my ($x) = @_;
1024              
1025             if (ref($$x) eq 'Math::MPC') {
1026             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1027             Math::MPC::RMPC_IM($r, $$x);
1028             bless \$r;
1029             }
1030             else {
1031             ZERO;
1032             }
1033             }
1034              
1035             *im = \&imag;
1036             *imaginary = \&imag;
1037              
1038             sub reals {
1039             ($_[0]->real, $_[0]->imag);
1040             }
1041              
1042             #
1043             ## CONSTANTS
1044             #
1045              
1046             sub pi {
1047             my $pi = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1048             Math::MPFR::Rmpfr_const_pi($pi, $ROUND);
1049             bless \$pi;
1050             }
1051              
1052             sub tau {
1053             my $tau = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1054             Math::MPFR::Rmpfr_const_pi($tau, $ROUND);
1055             Math::MPFR::Rmpfr_mul_2ui($tau, $tau, 1, $ROUND);
1056             bless \$tau;
1057             }
1058              
1059             sub ln2 {
1060             my $ln2 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1061             Math::MPFR::Rmpfr_const_log2($ln2, $ROUND);
1062             bless \$ln2;
1063             }
1064              
1065             sub euler {
1066             my $euler = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1067             Math::MPFR::Rmpfr_const_euler($euler, $ROUND);
1068             bless \$euler;
1069             }
1070              
1071             *Y = \&euler;
1072              
1073             sub catalan {
1074             my $catalan = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1075             Math::MPFR::Rmpfr_const_catalan($catalan, $ROUND);
1076             bless \$catalan;
1077             }
1078              
1079             *C = \&catalan;
1080              
1081             sub i {
1082             my ($x) = @_;
1083              
1084             state $i = do {
1085             my $c = Math::MPC::Rmpc_init2(CORE::int($PREC));
1086             Math::MPC::Rmpc_set_ui_ui($c, 0, 1, $ROUND);
1087             $c;
1088             };
1089              
1090             if (ref($x) eq __PACKAGE__) {
1091             bless \__mul__($i, $$x);
1092             }
1093             else {
1094             state $obj = bless \$i;
1095             }
1096             }
1097              
1098             sub e {
1099             state $one_f = (Math::MPFR::Rmpfr_init_set_ui_nobless(1, $ROUND))[0];
1100             my $e = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1101             Math::MPFR::Rmpfr_exp($e, $one_f, $ROUND);
1102             bless \$e;
1103             }
1104              
1105             sub phi {
1106             state $five4_f = (Math::MPFR::Rmpfr_init_set_d_nobless(1.25, $ROUND))[0];
1107              
1108             my $phi = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1109             Math::MPFR::Rmpfr_sqrt($phi, $five4_f, $ROUND);
1110             Math::MPFR::Rmpfr_add_d($phi, $phi, 0.5, $ROUND);
1111              
1112             bless \$phi;
1113             }
1114              
1115             sub _nan {
1116             state $nan = do {
1117             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1118             Math::MPFR::Rmpfr_set_nan($r);
1119             $r;
1120             };
1121             }
1122              
1123             sub nan {
1124             state $nan = do {
1125             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1126             Math::MPFR::Rmpfr_set_nan($r);
1127             bless \$r;
1128             };
1129             }
1130              
1131             sub _inf {
1132             state $inf = do {
1133             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1134             Math::MPFR::Rmpfr_set_inf($r, 1);
1135             $r;
1136             };
1137             }
1138              
1139             sub inf {
1140             state $inf = do {
1141             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1142             Math::MPFR::Rmpfr_set_inf($r, 1);
1143             bless \$r;
1144             };
1145             }
1146              
1147             sub _ninf {
1148             state $ninf = do {
1149             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1150             Math::MPFR::Rmpfr_set_inf($r, -1);
1151             $r;
1152             };
1153             }
1154              
1155             sub ninf {
1156             state $ninf = do {
1157             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1158             Math::MPFR::Rmpfr_set_inf($r, -1);
1159             bless \$r;
1160             };
1161             }
1162              
1163             sub _zero {
1164             state $zero = Math::GMPz::Rmpz_init_set_ui(0);
1165             }
1166              
1167             sub zero {
1168             state $zero = do {
1169             my $r = Math::GMPz::Rmpz_init_set_ui(0);
1170             bless \$r;
1171             };
1172             }
1173              
1174             sub _one {
1175             state $one = Math::GMPz::Rmpz_init_set_ui(1);
1176             }
1177              
1178             sub one {
1179             state $one = do {
1180             my $r = Math::GMPz::Rmpz_init_set_ui(1);
1181             bless \$r;
1182             };
1183             }
1184              
1185             sub _mone {
1186             state $mone = Math::GMPz::Rmpz_init_set_si(-1);
1187             }
1188              
1189             sub mone {
1190             state $mone = do {
1191             my $r = Math::GMPz::Rmpz_init_set_si(-1);
1192             bless \$r;
1193             };
1194             }
1195              
1196             sub __add__ {
1197             my ($x, $y) = @_;
1198              
1199             goto(join('__', ref($x), ref($y)) =~ tr/:/_/rs);
1200              
1201             #
1202             ## GMPz
1203             #
1204             Math_GMPz__Math_GMPz: {
1205             my $r = Math::GMPz::Rmpz_init();
1206             Math::GMPz::Rmpz_add($r, $x, $y);
1207             return $r;
1208             }
1209              
1210             Math_GMPz__Math_GMPq: {
1211             my $r = Math::GMPq::Rmpq_init();
1212             Math::GMPq::Rmpq_add_z($r, $y, $x);
1213             return $r;
1214             }
1215              
1216             Math_GMPz__Math_MPFR: {
1217             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1218             Math::MPFR::Rmpfr_add_z($r, $y, $x, $ROUND);
1219             return $r;
1220             }
1221              
1222             Math_GMPz__Math_MPC: {
1223             my $c = Math::MPC::Rmpc_init2(CORE::int($PREC));
1224             Math::MPC::Rmpc_set_z($c, $x, $ROUND);
1225             Math::MPC::Rmpc_add($c, $c, $y, $ROUND);
1226             return $c;
1227             }
1228              
1229             #
1230             ## GMPq
1231             #
1232             Math_GMPq__Math_GMPq: {
1233             my $r = Math::GMPq::Rmpq_init();
1234             Math::GMPq::Rmpq_add($r, $x, $y);
1235             return $r;
1236             }
1237              
1238             Math_GMPq__Math_GMPz: {
1239             my $r = Math::GMPq::Rmpq_init();
1240             Math::GMPq::Rmpq_add_z($r, $x, $y);
1241             return $r;
1242             }
1243              
1244             Math_GMPq__Math_MPFR: {
1245             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1246             Math::MPFR::Rmpfr_add_q($r, $y, $x, $ROUND);
1247             return $r;
1248             }
1249              
1250             Math_GMPq__Math_MPC: {
1251             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1252             Math::MPC::Rmpc_set_q($r, $x, $ROUND);
1253             Math::MPC::Rmpc_add($r, $r, $y, $ROUND);
1254             return $r;
1255             }
1256              
1257             #
1258             ## MPFR
1259             #
1260             Math_MPFR__Math_MPFR: {
1261             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1262             Math::MPFR::Rmpfr_add($r, $x, $y, $ROUND);
1263             return $r;
1264             }
1265              
1266             Math_MPFR__Math_GMPq: {
1267             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1268             Math::MPFR::Rmpfr_add_q($r, $x, $y, $ROUND);
1269             return $r;
1270             }
1271              
1272             Math_MPFR__Math_GMPz: {
1273             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1274             Math::MPFR::Rmpfr_add_z($r, $x, $y, $ROUND);
1275             return $r;
1276             }
1277              
1278             Math_MPFR__Math_MPC: {
1279             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1280             Math::MPC::Rmpc_add_fr($r, $y, $x, $ROUND);
1281             return $r;
1282             }
1283              
1284             #
1285             ## MPC
1286             #
1287             Math_MPC__Math_MPC: {
1288             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1289             Math::MPC::Rmpc_add($r, $x, $y, $ROUND);
1290             return $r;
1291             }
1292              
1293             Math_MPC__Math_MPFR: {
1294             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1295             Math::MPC::Rmpc_add_fr($r, $x, $y, $ROUND);
1296             return $r;
1297             }
1298              
1299             Math_MPC__Math_GMPz: {
1300             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1301             Math::MPC::Rmpc_set_z($r, $y, $ROUND);
1302             Math::MPC::Rmpc_add($r, $r, $x, $ROUND);
1303             return $r;
1304             }
1305              
1306             Math_MPC__Math_GMPq: {
1307             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1308             Math::MPC::Rmpc_set_q($r, $y, $ROUND);
1309             Math::MPC::Rmpc_add($r, $r, $x, $ROUND);
1310             return $r;
1311             }
1312             }
1313              
1314             sub add {
1315             my ($x, $y) = @_;
1316             _valid(\$y);
1317             bless \__add__($$x, $$y);
1318             }
1319              
1320             sub __sub__ {
1321             my ($x, $y) = @_;
1322              
1323             goto(join('__', ref($x), ref($y)) =~ tr/:/_/rs);
1324              
1325             #
1326             ## GMPq
1327             #
1328             Math_GMPq__Math_GMPq: {
1329             my $r = Math::GMPq::Rmpq_init();
1330             Math::GMPq::Rmpq_sub($r, $x, $y);
1331             return $r;
1332             }
1333              
1334             Math_GMPq__Math_GMPz: {
1335             my $r = Math::GMPq::Rmpq_init();
1336             Math::GMPq::Rmpq_sub_z($r, $x, $y);
1337             return $r;
1338             }
1339              
1340             Math_GMPq__Math_MPFR: {
1341             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1342             Math::MPFR::Rmpfr_sub_q($r, $y, $x, $ROUND);
1343             Math::MPFR::Rmpfr_neg($r, $r, $ROUND);
1344             return $r;
1345             }
1346              
1347             Math_GMPq__Math_MPC: {
1348             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1349             Math::MPC::Rmpc_set_q($r, $x, $ROUND);
1350             Math::MPC::Rmpc_sub($r, $r, $y, $ROUND);
1351             return $r;
1352             }
1353              
1354             #
1355             ## GMPz
1356             #
1357             Math_GMPz__Math_GMPz: {
1358             my $r = Math::GMPz::Rmpz_init();
1359             Math::GMPz::Rmpz_sub($r, $x, $y);
1360             return $r;
1361             }
1362              
1363             Math_GMPz__Math_GMPq: {
1364             my $r = Math::GMPq::Rmpq_init();
1365             Math::GMPq::Rmpq_z_sub($r, $x, $y);
1366             return $r;
1367             }
1368              
1369             Math_GMPz__Math_MPFR: {
1370             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1371             Math::MPFR::Rmpfr_set_z($r, $x, $ROUND);
1372             Math::MPFR::Rmpfr_sub($r, $r, $y, $ROUND);
1373             return $r;
1374             }
1375              
1376             Math_GMPz__Math_MPC: {
1377             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1378             Math::MPC::Rmpc_set_z($r, $x, $ROUND);
1379             Math::MPC::Rmpc_sub($r, $r, $y, $ROUND);
1380             return $r;
1381             }
1382              
1383             #
1384             ## MPFR
1385             #
1386             Math_MPFR__Math_MPFR: {
1387             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1388             Math::MPFR::Rmpfr_sub($r, $x, $y, $ROUND);
1389             return $r;
1390             }
1391              
1392             Math_MPFR__Math_GMPq: {
1393             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1394             Math::MPFR::Rmpfr_sub_q($r, $x, $y, $ROUND);
1395             return $r;
1396             }
1397              
1398             Math_MPFR__Math_GMPz: {
1399             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1400             Math::MPFR::Rmpfr_sub_z($r, $x, $y, $ROUND);
1401             return $r;
1402             }
1403              
1404             Math_MPFR__Math_MPC: {
1405             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1406             Math::MPC::Rmpc_set_fr($r, $x, $ROUND);
1407             Math::MPC::Rmpc_sub($r, $r, $y, $ROUND);
1408             return $r;
1409             }
1410              
1411             #
1412             ## MPC
1413             #
1414             Math_MPC__Math_MPC: {
1415             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1416             Math::MPC::Rmpc_sub($r, $x, $y, $ROUND);
1417             return $r;
1418             }
1419              
1420             Math_MPC__Math_MPFR: {
1421             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1422             Math::MPC::Rmpc_set_fr($r, $y, $ROUND);
1423             Math::MPC::Rmpc_sub($r, $x, $r, $ROUND);
1424             return $r;
1425             }
1426              
1427             Math_MPC__Math_GMPz: {
1428             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1429             Math::MPC::Rmpc_set_z($r, $y, $ROUND);
1430             Math::MPC::Rmpc_sub($r, $x, $r, $ROUND);
1431             return $r;
1432             }
1433              
1434             Math_MPC__Math_GMPq: {
1435             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1436             Math::MPC::Rmpc_set_q($r, $y, $ROUND);
1437             Math::MPC::Rmpc_sub($r, $x, $r, $ROUND);
1438             return $r;
1439             }
1440             }
1441              
1442             sub sub {
1443             my ($x, $y) = @_;
1444             _valid(\$y);
1445             bless \__sub__($$x, $$y);
1446             }
1447              
1448             sub __mul__ {
1449             my ($x, $y) = @_;
1450              
1451             goto(join('__', ref($x), ref($y)) =~ tr/:/_/rs);
1452              
1453             #
1454             ## GMPq
1455             #
1456             Math_GMPq__Math_GMPq: {
1457             my $r = Math::GMPq::Rmpq_init();
1458             Math::GMPq::Rmpq_mul($r, $x, $y);
1459             return $r;
1460             }
1461              
1462             Math_GMPq__Math_GMPz: {
1463             my $r = Math::GMPq::Rmpq_init();
1464             Math::GMPq::Rmpq_mul_z($r, $x, $y);
1465             return $r;
1466             }
1467              
1468             Math_GMPq__Math_MPFR: {
1469             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1470             Math::MPFR::Rmpfr_mul_q($r, $y, $x, $ROUND);
1471             return $r;
1472             }
1473              
1474             Math_GMPq__Math_MPC: {
1475             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1476             Math::MPC::Rmpc_set_q($r, $x, $ROUND);
1477             Math::MPC::Rmpc_mul($r, $r, $y, $ROUND);
1478             return $r;
1479             }
1480              
1481             #
1482             ## GMPz
1483             #
1484             Math_GMPz__Math_GMPz: {
1485             my $r = Math::GMPz::Rmpz_init();
1486             Math::GMPz::Rmpz_mul($r, $x, $y);
1487             return $r;
1488             }
1489              
1490             Math_GMPz__Math_GMPq: {
1491             my $r = Math::GMPq::Rmpq_init();
1492             Math::GMPq::Rmpq_mul_z($r, $y, $x);
1493             return $r;
1494             }
1495              
1496             Math_GMPz__Math_MPFR: {
1497             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1498             Math::MPFR::Rmpfr_mul_z($r, $y, $x, $ROUND);
1499             return $r;
1500             }
1501              
1502             Math_GMPz__Math_MPC: {
1503             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1504             Math::MPC::Rmpc_set_z($r, $x, $ROUND);
1505             Math::MPC::Rmpc_mul($r, $r, $y, $ROUND);
1506             return $r;
1507             }
1508              
1509             #
1510             ## MPFR
1511             #
1512             Math_MPFR__Math_MPFR: {
1513             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1514             Math::MPFR::Rmpfr_mul($r, $x, $y, $ROUND);
1515             return $r;
1516             }
1517              
1518             Math_MPFR__Math_GMPq: {
1519             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1520             Math::MPFR::Rmpfr_mul_q($r, $x, $y, $ROUND);
1521             return $r;
1522             }
1523              
1524             Math_MPFR__Math_GMPz: {
1525             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1526             Math::MPFR::Rmpfr_mul_z($r, $x, $y, $ROUND);
1527             return $r;
1528             }
1529              
1530             Math_MPFR__Math_MPC: {
1531             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1532             Math::MPC::Rmpc_mul_fr($r, $y, $x, $ROUND);
1533             return $r;
1534             }
1535              
1536             #
1537             ## MPC
1538             #
1539             Math_MPC__Math_MPC: {
1540             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1541             Math::MPC::Rmpc_mul($r, $x, $y, $ROUND);
1542             return $r;
1543             }
1544              
1545             Math_MPC__Math_MPFR: {
1546             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1547             Math::MPC::Rmpc_mul_fr($r, $x, $y, $ROUND);
1548             return $r;
1549             }
1550              
1551             Math_MPC__Math_GMPz: {
1552             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1553             Math::MPC::Rmpc_set_z($r, $y, $ROUND);
1554             Math::MPC::Rmpc_mul($r, $r, $x, $ROUND);
1555             return $r;
1556             }
1557              
1558             Math_MPC__Math_GMPq: {
1559             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1560             Math::MPC::Rmpc_set_q($r, $y, $ROUND);
1561             Math::MPC::Rmpc_mul($r, $r, $x, $ROUND);
1562             return $r;
1563             }
1564             }
1565              
1566             sub mul {
1567             my ($x, $y) = @_;
1568             _valid(\$y);
1569             bless \__mul__($$x, $$y);
1570             }
1571              
1572             sub __div__ {
1573             my ($x, $y) = @_;
1574              
1575             goto(join('__', ref($x), ref($y)) =~ tr/:/_/rs);
1576              
1577             #
1578             ## GMPq
1579             #
1580             Math_GMPq__Math_GMPq: {
1581              
1582             # Check for division by zero
1583             Math::GMPq::Rmpq_sgn($y) || do {
1584             $x = _mpq2mpfr($x);
1585             goto Math_MPFR__Math_GMPq;
1586             };
1587              
1588             my $r = Math::GMPq::Rmpq_init();
1589             Math::GMPq::Rmpq_div($r, $x, $y);
1590             return $r;
1591             }
1592              
1593             Math_GMPq__Math_GMPz: {
1594              
1595             # Check for division by zero
1596             Math::GMPz::Rmpz_sgn($y) || do {
1597             $x = _mpq2mpfr($x);
1598             goto Math_MPFR__Math_GMPz;
1599             };
1600              
1601             my $r = Math::GMPq::Rmpq_init();
1602             Math::GMPq::Rmpq_div_z($r, $x, $y);
1603             return $r;
1604             }
1605              
1606             Math_GMPq__Math_MPFR: {
1607             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1608             Math::MPFR::Rmpfr_q_div($r, $x, $y, $ROUND);
1609             return $r;
1610             }
1611              
1612             Math_GMPq__Math_MPC: {
1613             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1614             Math::MPC::Rmpc_set_q($r, $x, $ROUND);
1615             Math::MPC::Rmpc_div($r, $r, $y, $ROUND);
1616             return $r;
1617             }
1618              
1619             #
1620             ## GMPz
1621             #
1622             Math_GMPz__Math_GMPz: {
1623              
1624             # Check for division by zero
1625             Math::GMPz::Rmpz_sgn($y) || do {
1626             $x = _mpz2mpfr($x);
1627             goto Math_MPFR__Math_GMPz;
1628             };
1629              
1630             # Check for exact divisibility
1631             if (Math::GMPz::Rmpz_divisible_p($x, $y)) {
1632             my $r = Math::GMPz::Rmpz_init();
1633             Math::GMPz::Rmpz_divexact($r, $x, $y);
1634             return $r;
1635             }
1636              
1637             my $r = Math::GMPq::Rmpq_init();
1638             Math::GMPq::Rmpq_set_num($r, $x);
1639             Math::GMPq::Rmpq_set_den($r, $y);
1640             Math::GMPq::Rmpq_canonicalize($r);
1641             return $r;
1642             }
1643              
1644             Math_GMPz__Math_GMPq: {
1645              
1646             # Check for division by zero
1647             Math::GMPq::Rmpq_sgn($y) || do {
1648             $x = _mpz2mpfr($x);
1649             goto Math_MPFR__Math_GMPq;
1650             };
1651              
1652             my $r = Math::GMPq::Rmpq_init();
1653             Math::GMPq::Rmpq_z_div($r, $x, $y);
1654             return $r;
1655             }
1656              
1657             Math_GMPz__Math_MPFR: {
1658             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1659             Math::MPFR::Rmpfr_z_div($r, $x, $y, $ROUND);
1660             return $r;
1661             }
1662              
1663             Math_GMPz__Math_MPC: {
1664             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1665             Math::MPC::Rmpc_set_z($r, $x, $ROUND);
1666             Math::MPC::Rmpc_div($r, $r, $y, $ROUND);
1667             return $r;
1668             }
1669              
1670             #
1671             ## MPFR
1672             #
1673             Math_MPFR__Math_MPFR: {
1674             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1675             Math::MPFR::Rmpfr_div($r, $x, $y, $ROUND);
1676             return $r;
1677             }
1678              
1679             Math_MPFR__Math_GMPq: {
1680             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1681             Math::MPFR::Rmpfr_div_q($r, $x, $y, $ROUND);
1682             return $r;
1683             }
1684              
1685             Math_MPFR__Math_GMPz: {
1686             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1687             Math::MPFR::Rmpfr_div_z($r, $x, $y, $ROUND);
1688             return $r;
1689             }
1690              
1691             Math_MPFR__Math_MPC: {
1692             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1693             Math::MPC::Rmpc_set_fr($r, $x, $ROUND);
1694             Math::MPC::Rmpc_div($r, $r, $y, $ROUND);
1695             return $r;
1696             }
1697              
1698             #
1699             ## MPC
1700             #
1701             Math_MPC__Math_MPC: {
1702             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1703             Math::MPC::Rmpc_div($r, $x, $y, $ROUND);
1704             return $r;
1705             }
1706              
1707             Math_MPC__Math_MPFR: {
1708             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1709             Math::MPC::Rmpc_div_fr($r, $x, $y, $ROUND);
1710             return $r;
1711             }
1712              
1713             Math_MPC__Math_GMPz: {
1714             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1715             Math::MPC::Rmpc_set_z($r, $y, $ROUND);
1716             Math::MPC::Rmpc_div($r, $x, $r, $ROUND);
1717             return $r;
1718             }
1719              
1720             Math_MPC__Math_GMPq: {
1721             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1722             Math::MPC::Rmpc_set_q($r, $y, $ROUND);
1723             Math::MPC::Rmpc_div($r, $x, $r, $ROUND);
1724             return $r;
1725             }
1726             }
1727              
1728             sub div {
1729             my ($x, $y) = @_;
1730             _valid(\$y);
1731             bless \__div__($$x, $$y);
1732             }
1733              
1734             #
1735             ## Integer operations
1736             #
1737              
1738             sub iadd {
1739             my ($x, $y) = @_;
1740              
1741             _valid(\$y);
1742              
1743             $x = _any2mpz($$x) // (goto &nan);
1744             $y = _any2mpz($$y) // (goto &nan);
1745              
1746             my $r = Math::GMPz::Rmpz_init();
1747             Math::GMPz::Rmpz_add($r, $x, $y);
1748             bless \$r;
1749             }
1750              
1751             sub isub {
1752             my ($x, $y) = @_;
1753              
1754             _valid(\$y);
1755              
1756             $x = _any2mpz($$x) // (goto &nan);
1757             $y = _any2mpz($$y) // (goto &nan);
1758              
1759             my $r = Math::GMPz::Rmpz_init();
1760             Math::GMPz::Rmpz_sub($r, $x, $y);
1761             bless \$r;
1762             }
1763              
1764             sub imul {
1765             my ($x, $y) = @_;
1766              
1767             _valid(\$y);
1768              
1769             $x = _any2mpz($$x) // (goto &nan);
1770             $y = _any2mpz($$y) // (goto &nan);
1771              
1772             my $r = Math::GMPz::Rmpz_init();
1773             Math::GMPz::Rmpz_mul($r, $x, $y);
1774             bless \$r;
1775             }
1776              
1777             sub idiv {
1778             my ($x, $y) = @_;
1779              
1780             _valid(\$y);
1781              
1782             $x = _any2mpz($$x) // (goto &nan);
1783             $y = _any2mpz($$y) // (goto &nan);
1784              
1785             # Detect division by zero
1786             Math::GMPz::Rmpz_sgn($y) || do {
1787             my $sign = Math::GMPz::Rmpz_sgn($x);
1788              
1789             if ($sign == 0) { # 0/0
1790             goto &nan;
1791             }
1792             elsif ($sign > 0) { # x/0 where: x > 0
1793             goto &inf;
1794             }
1795             else { # x/0 where: x < 0
1796             goto &ninf;
1797             }
1798             };
1799              
1800             my $r = Math::GMPz::Rmpz_init();
1801             Math::GMPz::Rmpz_tdiv_q($r, $x, $y);
1802             bless \$r;
1803             }
1804              
1805             sub neg {
1806             my ($x) = @_;
1807              
1808             $x = $$x;
1809             goto(ref($x) =~ tr/:/_/rs);
1810              
1811             Math_GMPz: {
1812             my $r = Math::GMPz::Rmpz_init_set($x);
1813             Math::GMPz::Rmpz_neg($r, $r);
1814             return bless \$r;
1815             }
1816              
1817             Math_GMPq: {
1818             my $r = Math::GMPq::Rmpq_init();
1819             Math::GMPq::Rmpq_neg($r, $x);
1820             return bless \$r;
1821             }
1822              
1823             Math_MPFR: {
1824             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1825             Math::MPFR::Rmpfr_neg($r, $x, $ROUND);
1826             return bless \$r;
1827             }
1828              
1829             Math_MPC: {
1830             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1831             Math::MPC::Rmpc_neg($r, $x, $ROUND);
1832             return bless \$r;
1833             }
1834             }
1835              
1836             sub abs {
1837             my ($x) = @_;
1838              
1839             $x = $$x;
1840             goto(ref($x) =~ tr/:/_/rs);
1841              
1842             Math_GMPz: {
1843             Math::GMPz::Rmpz_sgn($x) >= 0 and return $_[0];
1844             my $r = Math::GMPz::Rmpz_init_set($x);
1845             Math::GMPz::Rmpz_abs($r, $r);
1846             return bless \$r;
1847             }
1848              
1849             Math_GMPq: {
1850             Math::GMPq::Rmpq_sgn($x) >= 0 and return $_[0];
1851             my $r = Math::GMPq::Rmpq_init();
1852             Math::GMPq::Rmpq_abs($r, $x);
1853             return bless \$r;
1854             }
1855              
1856             Math_MPFR: {
1857             Math::MPFR::Rmpfr_sgn($x) >= 0 and return $_[0];
1858             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1859             Math::MPFR::Rmpfr_abs($r, $x, $ROUND);
1860             return bless \$r;
1861             }
1862              
1863             Math_MPC: {
1864             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1865             Math::MPC::Rmpc_abs($r, $x, $ROUND);
1866             return bless \$r;
1867             }
1868             }
1869              
1870             sub __inv__ {
1871             my ($x) = @_;
1872              
1873             goto(ref($x) =~ tr/:/_/rs);
1874              
1875             Math_GMPq: {
1876              
1877             # Check for division by zero
1878             Math::GMPq::Rmpq_sgn($x) || do {
1879             $x = _mpq2mpfr($x);
1880             goto Math_MPFR;
1881             };
1882              
1883             my $r = Math::GMPq::Rmpq_init();
1884             Math::GMPq::Rmpq_inv($r, $x);
1885             return $r;
1886             }
1887              
1888             Math_MPFR: {
1889             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1890             Math::MPFR::Rmpfr_ui_div($r, 1, $x, $ROUND);
1891             return $r;
1892             }
1893              
1894             Math_GMPz: {
1895              
1896             # Check for division by zero
1897             Math::GMPz::Rmpz_sgn($x) || do {
1898             $x = _mpz2mpfr($x);
1899             goto Math_MPFR;
1900             };
1901              
1902             my $r = Math::GMPq::Rmpq_init();
1903             Math::GMPq::Rmpq_set_z($r, $x);
1904             Math::GMPq::Rmpq_inv($r, $r);
1905             return $r;
1906             }
1907              
1908             Math_MPC: {
1909             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1910             Math::MPC::Rmpc_ui_div($r, 1, $x, $ROUND);
1911             return $r;
1912             }
1913             }
1914              
1915             sub inv {
1916             my ($x) = @_;
1917             bless \__inv__($$x);
1918             }
1919              
1920             sub sqr {
1921             my ($x) = @_;
1922             bless \__mul__($$x, $$x);
1923             }
1924              
1925             sub __sqrt__ {
1926             my ($x) = @_;
1927              
1928             goto(ref($x) =~ tr/:/_/rs);
1929              
1930             Math_MPFR: {
1931              
1932             # Complex for x < 0
1933             if (Math::MPFR::Rmpfr_sgn($x) < 0) {
1934             $x = _mpfr2mpc($x);
1935             goto Math_MPC;
1936             }
1937              
1938             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1939             Math::MPFR::Rmpfr_sqrt($r, $x, $ROUND);
1940             return $r;
1941             }
1942              
1943             Math_MPC: {
1944             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1945             Math::MPC::Rmpc_sqrt($r, $x, $ROUND);
1946             return $r;
1947             }
1948             }
1949              
1950             sub sqrt {
1951             my ($x) = @_;
1952             bless \__sqrt__(_any2mpfr_mpc($$x));
1953             }
1954              
1955             sub __cbrt__ {
1956             my ($x) = @_;
1957              
1958             goto(ref($x) =~ tr/:/_/rs);
1959              
1960             Math_MPFR: {
1961              
1962             # Complex for x < 0
1963             if (Math::MPFR::Rmpfr_sgn($x) < 0) {
1964             $x = _mpfr2mpc($x);
1965             goto Math_MPC;
1966             }
1967              
1968             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
1969             Math::MPFR::Rmpfr_cbrt($r, $x, $ROUND);
1970             return $r;
1971             }
1972              
1973             Math_MPC: {
1974             state $three_inv = do {
1975             my $r = Math::MPC::Rmpc_init2_nobless(CORE::int($PREC));
1976             Math::MPC::Rmpc_set_ui($r, 3, $ROUND);
1977             Math::MPC::Rmpc_ui_div($r, 1, $r, $ROUND);
1978             $r;
1979             };
1980              
1981             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
1982             Math::MPC::Rmpc_pow($r, $x, $three_inv, $ROUND);
1983             return $r;
1984             }
1985             }
1986              
1987             sub cbrt {
1988             my ($x) = @_;
1989             bless \__cbrt__(_any2mpfr_mpc($$x));
1990             }
1991              
1992             sub __iroot__ {
1993             my ($x, $y) = @_;
1994              
1995             # $x is a Math::GMPz object
1996             # $y is a signed integer
1997              
1998             if ($y == 0) {
1999             Math::GMPz::Rmpz_sgn($x) || return $x; # 0^Inf = 0
2000              
2001             # 1^Inf = 1 ; (-1)^Inf = 1
2002             if (Math::GMPz::Rmpz_cmpabs_ui($x, 1) == 0) {
2003             return Math::GMPz::Rmpz_init_set_ui(1);
2004             }
2005              
2006             goto &_inf;
2007             }
2008             elsif ($y < 0) {
2009             my $sign = Math::GMPz::Rmpz_sgn($x) || goto &_inf; # 1 / 0^k = Inf
2010             Math::GMPz::Rmpz_cmp_ui($x, 1) || return $x; # 1 / 1^k = 1
2011              
2012             if ($sign < 0) {
2013             goto &_nan;
2014             }
2015              
2016             return Math::GMPz::Rmpz_init_set_ui(0);
2017             }
2018             elsif ($y % 2 == 0 and Math::GMPz::Rmpz_sgn($x) < 0) {
2019             goto &_nan;
2020             }
2021              
2022             my $r = Math::GMPz::Rmpz_init();
2023             Math::GMPz::Rmpz_root($r, $x, $y);
2024             $r;
2025             }
2026              
2027             sub iroot {
2028             my ($x, $y) = @_;
2029             _valid(\$y);
2030             bless \__iroot__(_any2mpz($$x) // (goto &nan), _any2si($$y) // (goto &nan));
2031             }
2032              
2033             sub isqrt {
2034             my ($x) = @_;
2035              
2036             $x = _any2mpz($$x) // goto &nan;
2037             Math::GMPz::Rmpz_sgn($x) < 0 and goto &nan;
2038              
2039             my $r = Math::GMPz::Rmpz_init();
2040             Math::GMPz::Rmpz_sqrt($r, $x);
2041             bless \$r;
2042             }
2043              
2044             sub icbrt {
2045             my ($x) = @_;
2046             bless \__iroot__(_any2mpz($$x) // (goto &nan), 3);
2047             }
2048              
2049             sub isqrtrem {
2050             my ($x) = @_;
2051              
2052             $x = _any2mpz($$x) // goto &nan;
2053              
2054             Math::GMPz::Rmpz_sgn($x) < 0
2055             and return ((nan()) x 2);
2056              
2057             my $r = Math::GMPz::Rmpz_init();
2058             my $s = Math::GMPz::Rmpz_init();
2059              
2060             Math::GMPz::Rmpz_sqrtrem($r, $s, $x);
2061             ((bless \$r), (bless \$s));
2062             }
2063              
2064             sub irootrem {
2065             my ($x, $y) = @_;
2066              
2067             _valid(\$y);
2068              
2069             $x = _any2mpz($$x) // goto &nan;
2070             $y = _any2si($$y) // goto &nan;
2071              
2072             if ($y == 0) {
2073             Math::GMPz::Rmpz_sgn($x) || return (ZERO, MONE); # 0^Inf = 0
2074              
2075             if (Math::GMPz::Rmpz_cmpabs_ui($x, 1) == 0) { # 1^Inf = 1 ; (-1)^Inf = 1
2076             return (ONE, bless \__dec__($x));
2077             }
2078              
2079             return (inf(), bless \__dec__($x));
2080             }
2081             elsif ($y < 0) {
2082             my $sign = Math::GMPz::Rmpz_sgn($x) || return (inf(), ZERO); # 1 / 0^k = Inf
2083             Math::GMPz::Rmpz_cmp_ui($x, 1) == 0 and return (ONE, ZERO); # 1 / 1^k = 1
2084             return ($sign < 0 ? (nan(), nan()) : (ZERO, ninf()));
2085             }
2086             elsif ($y % 2 == 0 and Math::GMPz::Rmpz_sgn($x) < 0) {
2087             return (nan(), nan());
2088             }
2089              
2090             my $r = Math::GMPz::Rmpz_init();
2091             my $s = Math::GMPz::Rmpz_init();
2092              
2093             Math::GMPz::Rmpz_rootrem($r, $s, $x, $y);
2094             ((bless \$r), (bless \$s));
2095             }
2096              
2097             sub __pow__ {
2098             my ($x, $y) = @_;
2099              
2100             goto(join('__', ref($x), ref($y) || 'Scalar') =~ tr/:/_/rs);
2101              
2102             #
2103             ## GMPq
2104             #
2105             Math_GMPq__Scalar: {
2106              
2107             my $r = Math::GMPq::Rmpq_init();
2108             Math::GMPq::Rmpq_pow_ui($r, $x, CORE::abs($y));
2109              
2110             if ($y < 0) {
2111             Math::GMPq::Rmpq_sgn($r) || goto &_inf;
2112             Math::GMPq::Rmpq_inv($r, $r);
2113             }
2114              
2115             return $r;
2116             }
2117              
2118             Math_GMPq__Math_GMPq: {
2119              
2120             # Integer power
2121             if (Math::GMPq::Rmpq_integer_p($y)) {
2122             $y = Math::GMPq::Rmpq_get_d($y);
2123             goto Math_GMPq__Scalar;
2124             }
2125              
2126             # (-x)^(a/b) is a complex number
2127             elsif (Math::GMPq::Rmpq_sgn($x) < 0) {
2128             ($x, $y) = (_mpq2mpc($x), _mpq2mpc($y));
2129             goto Math_MPC__Math_MPC;
2130             }
2131              
2132             ($x, $y) = (_mpq2mpfr($x), _mpq2mpfr($y));
2133             goto Math_MPFR__Math_MPFR;
2134             }
2135              
2136             Math_GMPq__Math_GMPz: {
2137             $y = Math::GMPz::Rmpz_get_d($y);
2138             goto Math_GMPq__Scalar;
2139             }
2140              
2141             Math_GMPq__Math_MPFR: {
2142             $x = _mpq2mpfr($x);
2143             goto Math_MPFR__Math_MPFR;
2144             }
2145              
2146             Math_GMPq__Math_MPC: {
2147             $x = _mpq2mpc($x);
2148             goto Math_MPC__Math_MPC;
2149             }
2150              
2151             #
2152             ## GMPz
2153             #
2154             Math_GMPz__Scalar: {
2155              
2156             my $r = Math::GMPz::Rmpz_init();
2157             Math::GMPz::Rmpz_pow_ui($r, $x, CORE::abs($y));
2158              
2159             if ($y < 0) {
2160             Math::GMPz::Rmpz_sgn($r) || goto &_inf;
2161              
2162             my $q = Math::GMPq::Rmpq_init();
2163             Math::GMPq::Rmpq_set_z($q, $r);
2164             Math::GMPq::Rmpq_inv($q, $q);
2165             return $q;
2166             }
2167              
2168             return $r;
2169             }
2170              
2171             Math_GMPz__Math_GMPz: {
2172             $y = Math::GMPz::Rmpz_get_d($y);
2173             goto Math_GMPz__Scalar;
2174             }
2175              
2176             Math_GMPz__Math_GMPq: {
2177             if (Math::GMPq::Rmpq_integer_p($y)) {
2178             $y = Math::GMPq::Rmpq_get_d($y);
2179             goto Math_GMPz__Scalar;
2180             }
2181              
2182             ($x, $y) = (_mpz2mpfr($x), _mpq2mpfr($y));
2183             goto Math_MPFR__Math_MPFR;
2184             }
2185              
2186             Math_GMPz__Math_MPFR: {
2187             $x = _mpz2mpfr($x);
2188             goto Math_MPFR__Math_MPFR;
2189             }
2190              
2191             Math_GMPz__Math_MPC: {
2192             $x = _mpz2mpc($x);
2193             goto Math_MPC__Math_MPC;
2194             }
2195              
2196             #
2197             ## MPFR
2198             #
2199             Math_MPFR__Math_MPFR: {
2200             if ( Math::MPFR::Rmpfr_sgn($x) < 0
2201             and !Math::MPFR::Rmpfr_integer_p($y)
2202             and Math::MPFR::Rmpfr_number_p($y)) {
2203             $x = _mpfr2mpc($x);
2204             goto Math_MPC__Math_MPFR;
2205             }
2206              
2207             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2208             Math::MPFR::Rmpfr_pow($r, $x, $y, $ROUND);
2209             return $r;
2210             }
2211              
2212             Math_MPFR__Scalar: {
2213             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2214             $y < 0
2215             ? Math::MPFR::Rmpfr_pow_si($r, $x, $y, $ROUND)
2216             : Math::MPFR::Rmpfr_pow_ui($r, $x, $y, $ROUND);
2217             return $r;
2218             }
2219              
2220             Math_MPFR__Math_GMPq: {
2221             $y = _mpq2mpfr($y);
2222             goto Math_MPFR__Math_MPFR;
2223             }
2224              
2225             Math_MPFR__Math_GMPz: {
2226             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2227             Math::MPFR::Rmpfr_pow_z($r, $x, $y, $ROUND);
2228             return $r;
2229             }
2230              
2231             Math_MPFR__Math_MPC: {
2232             $x = _mpfr2mpc($x);
2233             goto Math_MPC__Math_MPC;
2234             }
2235              
2236             #
2237             ## MPC
2238             #
2239             Math_MPC__Math_MPC: {
2240             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2241             Math::MPC::Rmpc_pow($r, $x, $y, $ROUND);
2242             return $r;
2243             }
2244              
2245             Math_MPC__Scalar: {
2246             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2247             $y < 0
2248             ? Math::MPC::Rmpc_pow_si($r, $x, $y, $ROUND)
2249             : Math::MPC::Rmpc_pow_ui($r, $x, $y, $ROUND);
2250             return $r;
2251             }
2252              
2253             Math_MPC__Math_MPFR: {
2254             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2255             Math::MPC::Rmpc_pow_fr($r, $x, $y, $ROUND);
2256             return $r;
2257             }
2258              
2259             Math_MPC__Math_GMPz: {
2260             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2261             Math::MPC::Rmpc_pow_z($r, $x, $y, $ROUND);
2262             return $r;
2263             }
2264              
2265             Math_MPC__Math_GMPq: {
2266             $y = _mpq2mpc($y);
2267             goto Math_MPC__Math_MPC;
2268             }
2269             }
2270              
2271             sub root {
2272             my ($x, $y) = @_;
2273             _valid(\$y);
2274             bless \__pow__($$x, __inv__($$y));
2275             }
2276              
2277             sub pow {
2278             my ($x, $y) = @_;
2279             _valid(\$y);
2280             bless \__pow__($$x, $$y);
2281             }
2282              
2283             sub ipow {
2284             my ($x, $y) = @_;
2285             _valid(\$y);
2286              
2287             $x = _any2mpz($$x) // goto &nan;
2288             $y = _any2si($$y) // goto &nan;
2289              
2290             my $r = Math::GMPz::Rmpz_init();
2291             Math::GMPz::Rmpz_pow_ui($r, $x, CORE::abs($y));
2292              
2293             if ($y < 0) {
2294             Math::GMPz::Rmpz_sgn($r) || goto &inf; # 0^(-y) = Inf
2295             state $ONE_Z = Math::GMPz::Rmpz_init_set_ui_nobless(1);
2296             Math::GMPz::Rmpz_tdiv_q($r, $ONE_Z, $r);
2297             }
2298              
2299             bless \$r;
2300             }
2301              
2302             sub ipow2 {
2303             my ($n) = @_;
2304              
2305             $n = _any2si($$n) // goto &nan;
2306              
2307             goto &zero if $n < 0;
2308             state $one = Math::GMPz::Rmpz_init_set_ui_nobless(1);
2309              
2310             my $r = Math::GMPz::Rmpz_init();
2311             Math::GMPz::Rmpz_mul_2exp($r, $one, $n);
2312             bless \$r;
2313             }
2314              
2315             sub ipow10 {
2316             my ($n) = @_;
2317              
2318             $n = _any2si($$n) // goto &nan;
2319              
2320             goto &zero if $n < 0;
2321              
2322             my $r = Math::GMPz::Rmpz_init();
2323             Math::GMPz::Rmpz_ui_pow_ui($r, 10, $n);
2324             bless \$r;
2325             }
2326              
2327             sub __log2__ {
2328             my ($x) = @_;
2329              
2330             goto(ref($x) =~ tr/:/_/rs);
2331              
2332             Math_MPFR: {
2333              
2334             # Complex for x < 0
2335             if (Math::MPFR::Rmpfr_sgn($x) < 0) {
2336             $x = _mpfr2mpc($x);
2337             goto Math_MPC;
2338             }
2339              
2340             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2341             Math::MPFR::Rmpfr_log2($r, $x, $ROUND);
2342             return $r;
2343             }
2344              
2345             Math_MPC: {
2346             my $ln2 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2347             Math::MPFR::Rmpfr_const_log2($ln2, $ROUND);
2348             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2349             Math::MPC::Rmpc_log($r, $x, $ROUND);
2350             Math::MPC::Rmpc_div_fr($r, $r, $ln2, $ROUND);
2351             return $r;
2352             }
2353             }
2354              
2355             sub __log10__ {
2356             my ($x) = @_;
2357              
2358             goto(ref($x) =~ tr/:/_/rs);
2359              
2360             Math_MPFR: {
2361              
2362             # Complex for x < 0
2363             if (Math::MPFR::Rmpfr_sgn($x) < 0) {
2364             $x = _mpfr2mpc($x);
2365             goto Math_MPC;
2366             }
2367              
2368             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2369             Math::MPFR::Rmpfr_log10($r, $x, $ROUND);
2370             return $r;
2371             }
2372              
2373             Math_MPC: {
2374             state $MPC_VERSION = Math::MPC::MPC_VERSION();
2375              
2376             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2377              
2378             if ($MPC_VERSION >= 65536) { # available only in mpc>=1.0.0
2379             Math::MPC::Rmpc_log10($r, $x, $ROUND);
2380             }
2381             else {
2382             my $ln10 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2383             Math::MPFR::Rmpfr_set_ui($ln10, 10, $ROUND);
2384             Math::MPFR::Rmpfr_log($ln10, $ln10, $ROUND);
2385             Math::MPC::Rmpc_log($r, $x, $ROUND);
2386             Math::MPC::Rmpc_div_fr($r, $r, $ln10, $ROUND);
2387             }
2388              
2389             return $r;
2390             }
2391             }
2392              
2393             sub __log__ {
2394             my ($x) = @_;
2395              
2396             goto(ref($x) =~ tr/:/_/rs);
2397              
2398             #
2399             ## MPFR
2400             #
2401             Math_MPFR: {
2402              
2403             # Complex for x < 0
2404             if (Math::MPFR::Rmpfr_sgn($x) < 0) {
2405             $x = _mpfr2mpc($x);
2406             goto Math_MPC;
2407             }
2408              
2409             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2410             Math::MPFR::Rmpfr_log($r, $x, $ROUND);
2411             return $r;
2412             }
2413              
2414             #
2415             ## MPC
2416             #
2417             Math_MPC: {
2418             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2419             Math::MPC::Rmpc_log($r, $x, $ROUND);
2420             return $r;
2421             }
2422             }
2423              
2424             sub log {
2425             my ($x, $y) = @_;
2426              
2427             if (defined($y)) {
2428             _valid(\$y);
2429             bless \__div__(__log__(_any2mpfr_mpc($$x)), __log__(_any2mpfr_mpc($$y)));
2430             }
2431             else {
2432             bless \__log__(_any2mpfr_mpc($$x));
2433             }
2434             }
2435              
2436             sub ln {
2437             my ($x) = @_;
2438             bless \__log__(_any2mpfr_mpc($$x));
2439             }
2440              
2441             sub log2 {
2442             my ($x) = @_;
2443             bless \__log2__(_any2mpfr_mpc($$x));
2444             }
2445              
2446             sub log10 {
2447             my ($x) = @_;
2448             bless \__log10__(_any2mpfr_mpc($$x));
2449             }
2450              
2451             sub __ilog__ {
2452             my ($x, $y) = @_;
2453              
2454             # ilog(x, y <= 1) = NaN
2455             Math::GMPz::Rmpz_cmp_ui($y, 1) <= 0 and goto &_nan;
2456              
2457             # ilog(x <= 0, y) = NaN
2458             Math::GMPz::Rmpz_sgn($x) <= 0 and goto &_nan;
2459              
2460             # Return faster for y <= 62
2461             if (Math::GMPz::Rmpz_cmp_ui($y, 62) <= 0) {
2462              
2463             $y = Math::GMPz::Rmpz_get_ui($y);
2464              
2465             my $t = Math::GMPz::Rmpz_init();
2466             my $e = (Math::GMPz::Rmpz_sizeinbase($x, $y) || goto &_nan) - 1;
2467              
2468             if ($e > 0) {
2469             Math::GMPz::Rmpz_ui_pow_ui($t, $y, $e);
2470             Math::GMPz::Rmpz_cmp($t, $x) > 0 and --$e;
2471             }
2472              
2473             Math::GMPz::Rmpz_set_ui($t, $e);
2474             return $t;
2475             }
2476              
2477             my $e = 0;
2478             my $t = Math::GMPz::Rmpz_init();
2479              
2480             state $logx = Math::MPFR::Rmpfr_init2_nobless(64);
2481             state $logy = Math::MPFR::Rmpfr_init2_nobless(64);
2482              
2483             Math::MPFR::Rmpfr_set_z($logx, $x, $round_z);
2484             Math::MPFR::Rmpfr_set_z($logy, $y, $round_z);
2485              
2486             Math::MPFR::Rmpfr_log($logx, $logx, $round_z);
2487             Math::MPFR::Rmpfr_log($logy, $logy, $round_z);
2488              
2489             Math::MPFR::Rmpfr_div($logx, $logx, $logy, $round_z);
2490              
2491             if (Math::MPFR::Rmpfr_fits_ulong_p($logx, $round_z)) {
2492             $e = Math::MPFR::Rmpfr_get_ui($logx, $round_z) - 1;
2493             Math::GMPz::Rmpz_pow_ui($t, $y, $e + 1);
2494             }
2495             else {
2496             Math::GMPz::Rmpz_set($t, $y);
2497             }
2498              
2499             for (; Math::GMPz::Rmpz_cmp($t, $x) <= 0 ; Math::GMPz::Rmpz_mul($t, $t, $y)) {
2500             ++$e;
2501             }
2502              
2503             Math::GMPz::Rmpz_set_ui($t, $e);
2504             $t;
2505             }
2506              
2507             sub ilog {
2508             my ($x, $y) = @_;
2509              
2510             if (defined($y)) {
2511             _valid(\$y);
2512             bless \__ilog__((_any2mpz($$x) // goto &nan), (_any2mpz($$y) // goto &nan));
2513             }
2514             else {
2515             bless \(_any2mpz(__log__(_any2mpfr_mpc($$x))) // goto &nan);
2516             }
2517             }
2518              
2519             sub ilog2 {
2520             my ($x) = @_;
2521             state $two = Math::GMPz::Rmpz_init_set_ui(2);
2522             bless \__ilog__((_any2mpz($$x) // goto &nan), $two);
2523             }
2524              
2525             sub ilog10 {
2526             my ($x) = @_;
2527             state $ten = Math::GMPz::Rmpz_init_set_ui(10);
2528             bless \__ilog__((_any2mpz($$x) // goto &nan), $ten);
2529             }
2530              
2531             sub __lgrt__ {
2532             my ($c) = @_;
2533              
2534             $PREC = CORE::int($PREC) if ref($PREC);
2535              
2536             my $p = Math::MPFR::Rmpfr_init2($PREC);
2537             Math::MPFR::Rmpfr_set_str($p, '1e-' . CORE::int($PREC >> 2), 10, $ROUND);
2538              
2539             goto(ref($c) =~ tr/:/_/rs);
2540              
2541             Math_MPFR: {
2542              
2543             # Return a complex number for x < e^(-1/e)
2544             if (Math::MPFR::Rmpfr_cmp_d($c, CORE::exp(-1 / CORE::exp(1))) < 0) {
2545             $c = _mpfr2mpc($c);
2546             goto Math_MPC;
2547             }
2548              
2549             my $r = Math::MPFR::Rmpfr_init2($PREC);
2550             Math::MPFR::Rmpfr_log($r, $c, $ROUND);
2551              
2552             Math::MPFR::Rmpfr_set_ui((my $x = Math::MPFR::Rmpfr_init2($PREC)), 1, $ROUND);
2553             Math::MPFR::Rmpfr_set_ui((my $y = Math::MPFR::Rmpfr_init2($PREC)), 0, $ROUND);
2554              
2555             my $count = 0;
2556             my $tmp = Math::MPFR::Rmpfr_init2($PREC);
2557              
2558             while (1) {
2559             Math::MPFR::Rmpfr_sub($tmp, $x, $y, $ROUND);
2560             Math::MPFR::Rmpfr_cmpabs($tmp, $p) <= 0 and last;
2561              
2562             Math::MPFR::Rmpfr_set($y, $x, $ROUND);
2563              
2564             Math::MPFR::Rmpfr_log($tmp, $x, $ROUND);
2565             Math::MPFR::Rmpfr_add_ui($tmp, $tmp, 1, $ROUND);
2566              
2567             Math::MPFR::Rmpfr_add($x, $x, $r, $ROUND);
2568             Math::MPFR::Rmpfr_div($x, $x, $tmp, $ROUND);
2569             last if ++$count > $PREC;
2570             }
2571              
2572             return $x;
2573             }
2574              
2575             Math_MPC: {
2576             my $d = Math::MPC::Rmpc_init2($PREC);
2577             Math::MPC::Rmpc_log($d, $c, $ROUND);
2578              
2579             my $x = Math::MPC::Rmpc_init2($PREC);
2580             Math::MPC::Rmpc_sqrt($x, $c, $ROUND);
2581             Math::MPC::Rmpc_add_ui($x, $x, 1, $ROUND);
2582             Math::MPC::Rmpc_log($x, $x, $ROUND);
2583              
2584             my $y = Math::MPC::Rmpc_init2($PREC);
2585             Math::MPC::Rmpc_set_ui($y, 0, $ROUND);
2586              
2587             my $tmp = Math::MPC::Rmpc_init2($PREC);
2588             my $abs = Math::MPFR::Rmpfr_init2($PREC);
2589              
2590             my $count = 0;
2591             while (1) {
2592             Math::MPC::Rmpc_sub($tmp, $x, $y, $ROUND);
2593              
2594             Math::MPC::Rmpc_abs($abs, $tmp, $ROUND);
2595             Math::MPFR::Rmpfr_cmp($abs, $p) <= 0 and last;
2596              
2597             Math::MPC::Rmpc_set($y, $x, $ROUND);
2598              
2599             Math::MPC::Rmpc_log($tmp, $x, $ROUND);
2600             Math::MPC::Rmpc_add_ui($tmp, $tmp, 1, $ROUND);
2601              
2602             Math::MPC::Rmpc_add($x, $x, $d, $ROUND);
2603             Math::MPC::Rmpc_div($x, $x, $tmp, $ROUND);
2604             last if ++$count > $PREC;
2605             }
2606              
2607             return $x;
2608             }
2609             }
2610              
2611             sub lgrt {
2612             my ($x) = @_;
2613             bless \__lgrt__(_any2mpfr_mpc($$x));
2614             }
2615              
2616             sub __LambertW__ {
2617             my ($x) = @_;
2618              
2619             $PREC = CORE::int($PREC) if ref($PREC);
2620              
2621             my $p = Math::MPFR::Rmpfr_init2($PREC);
2622             Math::MPFR::Rmpfr_set_str($p, '1e-' . CORE::int($PREC >> 2), 10, $ROUND);
2623              
2624             goto(ref($x) =~ tr/:/_/rs);
2625              
2626             Math_MPFR: {
2627              
2628             # Return a complex number for x < -1/e
2629             if (Math::MPFR::Rmpfr_cmp_d($x, -1 / CORE::exp(1)) < 0) {
2630             $x = _mpfr2mpc($x);
2631             goto Math_MPC;
2632             }
2633              
2634             Math::MPFR::Rmpfr_set_ui((my $r = Math::MPFR::Rmpfr_init2($PREC)), 1, $ROUND);
2635             Math::MPFR::Rmpfr_set_ui((my $y = Math::MPFR::Rmpfr_init2($PREC)), 0, $ROUND);
2636              
2637             my $count = 0;
2638             my $tmp = Math::MPFR::Rmpfr_init2($PREC);
2639              
2640             while (1) {
2641             Math::MPFR::Rmpfr_sub($tmp, $r, $y, $ROUND);
2642             Math::MPFR::Rmpfr_cmpabs($tmp, $p) <= 0 and last;
2643              
2644             Math::MPFR::Rmpfr_set($y, $r, $ROUND);
2645              
2646             Math::MPFR::Rmpfr_log($tmp, $r, $ROUND);
2647             Math::MPFR::Rmpfr_add_ui($tmp, $tmp, 1, $ROUND);
2648              
2649             Math::MPFR::Rmpfr_add($r, $r, $x, $ROUND);
2650             Math::MPFR::Rmpfr_div($r, $r, $tmp, $ROUND);
2651             last if ++$count > $PREC;
2652             }
2653              
2654             Math::MPFR::Rmpfr_log($r, $r, $ROUND);
2655             return $r;
2656             }
2657              
2658             Math_MPC: {
2659             my $r = Math::MPC::Rmpc_init2($PREC);
2660             Math::MPC::Rmpc_sqrt($r, $x, $ROUND);
2661             Math::MPC::Rmpc_add_ui($r, $r, 1, $ROUND);
2662              
2663             my $y = Math::MPC::Rmpc_init2($PREC);
2664             Math::MPC::Rmpc_set_ui($y, 0, $ROUND);
2665              
2666             my $tmp = Math::MPC::Rmpc_init2($PREC);
2667             my $abs = Math::MPFR::Rmpfr_init2($PREC);
2668              
2669             my $count = 0;
2670             while (1) {
2671             Math::MPC::Rmpc_sub($tmp, $r, $y, $ROUND);
2672              
2673             Math::MPC::Rmpc_abs($abs, $tmp, $ROUND);
2674             Math::MPFR::Rmpfr_cmp($abs, $p) <= 0 and last;
2675              
2676             Math::MPC::Rmpc_set($y, $r, $ROUND);
2677              
2678             Math::MPC::Rmpc_log($tmp, $r, $ROUND);
2679             Math::MPC::Rmpc_add_ui($tmp, $tmp, 1, $ROUND);
2680              
2681             Math::MPC::Rmpc_add($r, $r, $x, $ROUND);
2682             Math::MPC::Rmpc_div($r, $r, $tmp, $ROUND);
2683             last if ++$count > $PREC;
2684             }
2685              
2686             Math::MPC::Rmpc_log($r, $r, $ROUND);
2687             return $r;
2688             }
2689             }
2690              
2691             sub lambert_w {
2692             my ($x) = @_;
2693             bless \__LambertW__(_any2mpfr_mpc($$x));
2694             }
2695              
2696             *LambertW = \&lambert_w;
2697              
2698             sub __exp__ {
2699             my ($x) = @_;
2700             goto(ref($x) =~ tr/:/_/rs);
2701              
2702             Math_MPFR: {
2703             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2704             Math::MPFR::Rmpfr_exp($r, $x, $ROUND);
2705             return $r;
2706             }
2707              
2708             Math_MPC: {
2709             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2710             Math::MPC::Rmpc_exp($r, $x, $ROUND);
2711             return $r;
2712             }
2713             }
2714              
2715             sub exp {
2716             my ($x) = @_;
2717             bless \__exp__(_any2mpfr_mpc($$x));
2718             }
2719              
2720             sub exp2 {
2721             my ($x) = @_;
2722             state $base = Math::GMPz::Rmpz_init_set_ui(2);
2723             bless \__pow__($base, $$x);
2724             }
2725              
2726             sub exp10 {
2727             my ($x) = @_;
2728             state $base = Math::GMPz::Rmpz_init_set_ui(10);
2729             bless \__pow__($base, $$x);
2730             }
2731              
2732             #
2733             ## sin / sinh / asin / asinh
2734             #
2735              
2736             sub __sin__ {
2737             my ($x) = @_;
2738             goto(ref($x) =~ tr/:/_/rs);
2739              
2740             Math_MPFR: {
2741             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2742             Math::MPFR::Rmpfr_sin($r, $x, $ROUND);
2743             return $r;
2744             }
2745              
2746             Math_MPC: {
2747             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2748             Math::MPC::Rmpc_sin($r, $x, $ROUND);
2749             return $r;
2750             }
2751             }
2752              
2753             sub sin {
2754             my ($x) = @_;
2755             bless \__sin__(_any2mpfr_mpc($$x));
2756             }
2757              
2758             sub __sinh__ {
2759             my ($x) = @_;
2760             goto(ref($x) =~ tr/:/_/rs);
2761              
2762             Math_MPFR: {
2763             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2764             Math::MPFR::Rmpfr_sinh($r, $x, $ROUND);
2765             return $r;
2766             }
2767              
2768             Math_MPC: {
2769             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2770             Math::MPC::Rmpc_sinh($r, $x, $ROUND);
2771             return $r;
2772             }
2773             }
2774              
2775             sub sinh {
2776             my ($x) = @_;
2777             bless \__sinh__(_any2mpfr_mpc($$x));
2778             }
2779              
2780             sub __asin__ {
2781             my ($x) = @_;
2782             goto(ref($x) =~ tr/:/_/rs);
2783              
2784             Math_MPFR: {
2785              
2786             # Return a complex number for x < -1 or x > 1
2787             if ( Math::MPFR::Rmpfr_cmp_ui($x, 1) > 0
2788             or Math::MPFR::Rmpfr_cmp_si($x, -1) < 0) {
2789             my $r = _mpfr2mpc($x);
2790             Math::MPC::Rmpc_asin($r, $r, $ROUND);
2791             return $r;
2792             }
2793              
2794             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2795             Math::MPFR::Rmpfr_asin($r, $x, $ROUND);
2796             return $r;
2797             }
2798              
2799             Math_MPC: {
2800             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2801             Math::MPC::Rmpc_asin($r, $x, $ROUND);
2802             return $r;
2803             }
2804             }
2805              
2806             sub asin {
2807             my ($x) = @_;
2808             bless \__asin__(_any2mpfr_mpc($$x));
2809             }
2810              
2811             sub __asinh__ {
2812             my ($x) = @_;
2813             goto(ref($x) =~ tr/:/_/rs);
2814              
2815             Math_MPFR: {
2816             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2817             Math::MPFR::Rmpfr_asinh($r, $x, $ROUND);
2818             return $r;
2819             }
2820              
2821             Math_MPC: {
2822             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2823             Math::MPC::Rmpc_asinh($r, $x, $ROUND);
2824             return $r;
2825             }
2826             }
2827              
2828             sub asinh {
2829             my ($x) = @_;
2830             bless \__asinh__(_any2mpfr_mpc($$x));
2831             }
2832              
2833             #
2834             ## cos / cosh / acos / acosh
2835             #
2836              
2837             sub __cos__ {
2838             my ($x) = @_;
2839             goto(ref($x) =~ tr/:/_/rs);
2840              
2841             Math_MPFR: {
2842             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2843             Math::MPFR::Rmpfr_cos($r, $x, $ROUND);
2844             return $r;
2845             }
2846              
2847             Math_MPC: {
2848             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2849             Math::MPC::Rmpc_cos($r, $x, $ROUND);
2850             return $r;
2851             }
2852             }
2853              
2854             sub cos {
2855             my ($x) = @_;
2856             bless \__cos__(_any2mpfr_mpc($$x));
2857             }
2858              
2859             sub __cosh__ {
2860             my ($x) = @_;
2861             goto(ref($x) =~ tr/:/_/rs);
2862              
2863             Math_MPFR: {
2864             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2865             Math::MPFR::Rmpfr_cosh($r, $x, $ROUND);
2866             return $r;
2867             }
2868              
2869             Math_MPC: {
2870             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2871             Math::MPC::Rmpc_cosh($r, $x, $ROUND);
2872             return $r;
2873             }
2874             }
2875              
2876             sub cosh {
2877             my ($x) = @_;
2878             bless \__cosh__(_any2mpfr_mpc($$x));
2879             }
2880              
2881             sub __acos__ {
2882             my ($x) = @_;
2883             goto(ref($x) =~ tr/:/_/rs);
2884              
2885             Math_MPFR: {
2886              
2887             # Return a complex number for x < -1 or x > 1
2888             if ( Math::MPFR::Rmpfr_cmp_ui($x, 1) > 0
2889             or Math::MPFR::Rmpfr_cmp_si($x, -1) < 0) {
2890             my $r = _mpfr2mpc($x);
2891             Math::MPC::Rmpc_acos($r, $r, $ROUND);
2892             return $r;
2893             }
2894              
2895             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2896             Math::MPFR::Rmpfr_acos($r, $x, $ROUND);
2897             return $r;
2898             }
2899              
2900             Math_MPC: {
2901             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2902             Math::MPC::Rmpc_acos($r, $x, $ROUND);
2903             return $r;
2904             }
2905             }
2906              
2907             sub acos {
2908             my ($x) = @_;
2909             bless \__acos__(_any2mpfr_mpc($$x));
2910             }
2911              
2912             sub __acosh__ {
2913             my ($x) = @_;
2914             goto(ref($x) =~ tr/:/_/rs);
2915              
2916             Math_MPFR: {
2917              
2918             # Return a complex number for x < 1
2919             if (Math::MPFR::Rmpfr_cmp_ui($x, 1) < 0) {
2920             my $r = _mpfr2mpc($x);
2921             Math::MPC::Rmpc_acosh($r, $r, $ROUND);
2922             return $r;
2923             }
2924              
2925             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2926             Math::MPFR::Rmpfr_acosh($r, $x, $ROUND);
2927             return $r;
2928             }
2929              
2930             Math_MPC: {
2931             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2932             Math::MPC::Rmpc_acosh($r, $x, $ROUND);
2933             return $r;
2934             }
2935             }
2936              
2937             sub acosh {
2938             my ($x) = @_;
2939             bless \__acosh__(_any2mpfr_mpc($$x));
2940             }
2941              
2942             #
2943             ## tan / tanh / atan / atanh
2944             #
2945              
2946             sub __tan__ {
2947             my ($x) = @_;
2948             goto(ref($x) =~ tr/:/_/rs);
2949              
2950             Math_MPFR: {
2951             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2952             Math::MPFR::Rmpfr_tan($r, $x, $ROUND);
2953             return $r;
2954             }
2955              
2956             Math_MPC: {
2957             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2958             Math::MPC::Rmpc_tan($r, $x, $ROUND);
2959             return $r;
2960             }
2961             }
2962              
2963             sub tan {
2964             my ($x) = @_;
2965             bless \__tan__(_any2mpfr_mpc($$x));
2966             }
2967              
2968             sub __tanh__ {
2969             my ($x) = @_;
2970             goto(ref($x) =~ tr/:/_/rs);
2971              
2972             Math_MPFR: {
2973             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2974             Math::MPFR::Rmpfr_tanh($r, $x, $ROUND);
2975             return $r;
2976             }
2977              
2978             Math_MPC: {
2979             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
2980             Math::MPC::Rmpc_tanh($r, $x, $ROUND);
2981             return $r;
2982             }
2983             }
2984              
2985             sub tanh {
2986             my ($x) = @_;
2987             bless \__tanh__(_any2mpfr_mpc($$x));
2988             }
2989              
2990             sub __atan__ {
2991             my ($x) = @_;
2992             goto(ref($x) =~ tr/:/_/rs);
2993              
2994             Math_MPFR: {
2995             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
2996             Math::MPFR::Rmpfr_atan($r, $x, $ROUND);
2997             return $r;
2998             }
2999              
3000             Math_MPC: {
3001             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3002             Math::MPC::Rmpc_atan($r, $x, $ROUND);
3003             return $r;
3004             }
3005             }
3006              
3007             sub atan {
3008             my ($x) = @_;
3009             bless \__atan__(_any2mpfr_mpc($$x));
3010             }
3011              
3012             sub __atanh__ {
3013             my ($x) = @_;
3014             goto(ref($x) =~ tr/:/_/rs);
3015              
3016             Math_MPFR: {
3017              
3018             # Return a complex number for x < -1 or x > 1
3019             if ( Math::MPFR::Rmpfr_cmp_ui($x, +1) > 0
3020             or Math::MPFR::Rmpfr_cmp_si($x, -1) < 0) {
3021             my $r = _mpfr2mpc($x);
3022             Math::MPC::Rmpc_atanh($r, $r, $ROUND);
3023             return $r;
3024             }
3025              
3026             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3027             Math::MPFR::Rmpfr_atanh($r, $x, $ROUND);
3028             return $r;
3029             }
3030              
3031             Math_MPC: {
3032             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3033             Math::MPC::Rmpc_atanh($r, $x, $ROUND);
3034             return $r;
3035             }
3036             }
3037              
3038             sub atanh {
3039             my ($x) = @_;
3040             bless \__atanh__(_any2mpfr_mpc($$x));
3041             }
3042              
3043             sub __atan2__ {
3044             my ($x, $y) = @_;
3045             goto(join('__', ref($x), ref($y)) =~ tr/:/_/rs);
3046              
3047             Math_MPFR__Math_MPFR: {
3048             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3049             Math::MPFR::Rmpfr_atan2($r, $x, $y, $ROUND);
3050             return $r;
3051             }
3052              
3053             Math_MPFR__Math_MPC: {
3054             $x = _mpfr2mpc($x);
3055             goto Math_MPC__Math_MPC;
3056             }
3057              
3058             # atan2(x, y) = atan(x/y)
3059             Math_MPC__Math_MPFR: {
3060             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3061             Math::MPC::Rmpc_div_fr($r, $x, $y, $ROUND);
3062             Math::MPC::Rmpc_atan($r, $r, $ROUND);
3063             return $r;
3064             }
3065              
3066             # atan2(x, y) = atan(x/y)
3067             Math_MPC__Math_MPC: {
3068             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3069             Math::MPC::Rmpc_div($r, $x, $y, $ROUND);
3070             Math::MPC::Rmpc_atan($r, $r, $ROUND);
3071             return $r;
3072             }
3073             }
3074              
3075             sub atan2 {
3076             my ($x, $y) = @_;
3077             _valid(\$y);
3078             bless \__atan2__(_any2mpfr_mpc($$x), _any2mpfr_mpc($$y));
3079             }
3080              
3081             #
3082             ## sec / sech / asec / asech
3083             #
3084              
3085             sub __sec__ {
3086             my ($x) = @_;
3087             goto(ref($x) =~ tr/:/_/rs);
3088              
3089             Math_MPFR: {
3090             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3091             Math::MPFR::Rmpfr_sec($r, $x, $ROUND);
3092             return $r;
3093             }
3094              
3095             # sec(x) = 1/cos(x)
3096             Math_MPC: {
3097             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3098             Math::MPC::Rmpc_cos($r, $x, $ROUND);
3099             Math::MPC::Rmpc_ui_div($r, 1, $r, $ROUND);
3100             return $r;
3101             }
3102             }
3103              
3104             sub sec {
3105             my ($x) = @_;
3106             bless \__sec__(_any2mpfr_mpc($$x));
3107             }
3108              
3109             sub __sech__ {
3110             my ($x) = @_;
3111             goto(ref($x) =~ tr/:/_/rs);
3112              
3113             Math_MPFR: {
3114             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3115             Math::MPFR::Rmpfr_sech($r, $x, $ROUND);
3116             return $r;
3117             }
3118              
3119             # sech(x) = 1/cosh(x)
3120             Math_MPC: {
3121             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3122             Math::MPC::Rmpc_cosh($r, $x, $ROUND);
3123             Math::MPC::Rmpc_ui_div($r, 1, $r, $ROUND);
3124             return $r;
3125             }
3126             }
3127              
3128             sub sech {
3129             my ($x) = @_;
3130             bless \__sech__(_any2mpfr_mpc($$x));
3131             }
3132              
3133             sub __asec__ {
3134             my ($x) = @_;
3135             goto(ref($x) =~ tr/:/_/rs);
3136              
3137             # asec(x) = acos(1/x)
3138             Math_MPFR: {
3139              
3140             # Return a complex number for x > -1 and x < 1
3141             if ( Math::MPFR::Rmpfr_cmp_ui($x, 1) < 0
3142             and Math::MPFR::Rmpfr_cmp_si($x, -1) > 0) {
3143             $x = _mpfr2mpc($x);
3144             goto Math_MPC;
3145             }
3146              
3147             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3148             Math::MPFR::Rmpfr_ui_div($r, 1, $x, $ROUND);
3149             Math::MPFR::Rmpfr_acos($r, $r, $ROUND);
3150             return $r;
3151             }
3152              
3153             # asec(x) = acos(1/x)
3154             Math_MPC: {
3155             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3156             Math::MPC::Rmpc_ui_div($r, 1, $x, $ROUND);
3157             Math::MPC::Rmpc_acos($r, $r, $ROUND);
3158             return $r;
3159             }
3160             }
3161              
3162             sub asec {
3163             my ($x) = @_;
3164             bless \__asec__(_any2mpfr_mpc($$x));
3165             }
3166              
3167             sub __asech__ {
3168             my ($x) = @_;
3169             goto(ref($x) =~ tr/:/_/rs);
3170              
3171             # asech(x) = acosh(1/x)
3172             Math_MPFR: {
3173              
3174             # Return a complex number for x < 0 or x > 1
3175             if ( Math::MPFR::Rmpfr_cmp_ui($x, 1) > 0
3176             or Math::MPFR::Rmpfr_cmp_ui($x, 0) < 0) {
3177             $x = _mpfr2mpc($x);
3178             goto Math_MPC;
3179             }
3180              
3181             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3182             Math::MPFR::Rmpfr_ui_div($r, 1, $x, $ROUND);
3183             Math::MPFR::Rmpfr_acosh($r, $r, $ROUND);
3184             return $r;
3185             }
3186              
3187             # asech(x) = acosh(1/x)
3188             Math_MPC: {
3189             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3190             Math::MPC::Rmpc_ui_div($r, 1, $x, $ROUND);
3191             Math::MPC::Rmpc_acosh($r, $r, $ROUND);
3192             return $r;
3193             }
3194             }
3195              
3196             sub asech {
3197             my ($x) = @_;
3198             bless \__asech__(_any2mpfr_mpc($$x));
3199             }
3200              
3201             #
3202             ## csc / csch / acsc / acsch
3203             #
3204              
3205             sub __csc__ {
3206             my ($x) = @_;
3207             goto(ref($x) =~ tr/:/_/rs);
3208              
3209             Math_MPFR: {
3210             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3211             Math::MPFR::Rmpfr_csc($r, $x, $ROUND);
3212             return $r;
3213             }
3214              
3215             # csc(x) = 1/sin(x)
3216             Math_MPC: {
3217             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3218             Math::MPC::Rmpc_sin($r, $x, $ROUND);
3219             Math::MPC::Rmpc_ui_div($r, 1, $r, $ROUND);
3220             return $r;
3221             }
3222             }
3223              
3224             sub csc {
3225             my ($x) = @_;
3226             bless \__csc__(_any2mpfr_mpc($$x));
3227             }
3228              
3229             sub __csch__ {
3230             my ($x) = @_;
3231             goto(ref($x) =~ tr/:/_/rs);
3232              
3233             Math_MPFR: {
3234             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3235             Math::MPFR::Rmpfr_csch($r, $x, $ROUND);
3236             return $r;
3237             }
3238              
3239             # csch(x) = 1/sinh(x)
3240             Math_MPC: {
3241             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3242             Math::MPC::Rmpc_sinh($r, $x, $ROUND);
3243             Math::MPC::Rmpc_ui_div($r, 1, $r, $ROUND);
3244             return $r;
3245             }
3246             }
3247              
3248             sub csch {
3249             my ($x) = @_;
3250             bless \__csch__(_any2mpfr_mpc($$x));
3251             }
3252              
3253             sub __acsc__ {
3254             my ($x) = @_;
3255             goto(ref($x) =~ tr/:/_/rs);
3256              
3257             # acsc(x) = asin(1/x)
3258             Math_MPFR: {
3259              
3260             # Return a complex number for x > -1 and x < 1
3261             if ( Math::MPFR::Rmpfr_cmp_ui($x, 1) < 0
3262             and Math::MPFR::Rmpfr_cmp_si($x, -1) > 0) {
3263             $x = _mpfr2mpc($x);
3264             goto Math_MPC;
3265             }
3266              
3267             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3268             Math::MPFR::Rmpfr_ui_div($r, 1, $x, $ROUND);
3269             Math::MPFR::Rmpfr_asin($r, $r, $ROUND);
3270             return $r;
3271             }
3272              
3273             # acsc(x) = asin(1/x)
3274             Math_MPC: {
3275             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3276             Math::MPC::Rmpc_ui_div($r, 1, $x, $ROUND);
3277             Math::MPC::Rmpc_asin($r, $r, $ROUND);
3278             return $r;
3279             }
3280             }
3281              
3282             sub acsc {
3283             my ($x) = @_;
3284             bless \__acsc__(_any2mpfr_mpc($$x));
3285             }
3286              
3287             sub __acsch__ {
3288             my ($x) = @_;
3289             goto(ref($x) =~ tr/:/_/rs);
3290              
3291             # acsch(x) = asinh(1/x)
3292             Math_MPFR: {
3293             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3294             Math::MPFR::Rmpfr_ui_div($r, 1, $x, $ROUND);
3295             Math::MPFR::Rmpfr_asinh($r, $r, $ROUND);
3296             return $r;
3297             }
3298              
3299             # acsch(x) = asinh(1/x)
3300             Math_MPC: {
3301             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3302             Math::MPC::Rmpc_ui_div($r, 1, $x, $ROUND);
3303             Math::MPC::Rmpc_asinh($r, $r, $ROUND);
3304             return $r;
3305             }
3306             }
3307              
3308             sub acsch {
3309             my ($x) = @_;
3310             bless \__acsch__(_any2mpfr_mpc($$x));
3311             }
3312              
3313             #
3314             ## cot / coth / acot / acoth
3315             #
3316              
3317             sub __cot__ {
3318             my ($x) = @_;
3319             goto(ref($x) =~ tr/:/_/rs);
3320              
3321             Math_MPFR: {
3322             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3323             Math::MPFR::Rmpfr_cot($r, $x, $ROUND);
3324             return $r;
3325             }
3326              
3327             # cot(x) = 1/tan(x)
3328             Math_MPC: {
3329             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3330             Math::MPC::Rmpc_tan($r, $x, $ROUND);
3331             Math::MPC::Rmpc_ui_div($r, 1, $r, $ROUND);
3332             return $r;
3333             }
3334             }
3335              
3336             sub cot {
3337             my ($x) = @_;
3338             bless \__cot__(_any2mpfr_mpc($$x));
3339             }
3340              
3341             sub __coth__ {
3342             my ($x) = @_;
3343             goto(ref($x) =~ tr/:/_/rs);
3344              
3345             Math_MPFR: {
3346             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3347             Math::MPFR::Rmpfr_coth($r, $x, $ROUND);
3348             return $r;
3349             }
3350              
3351             # coth(x) = 1/tanh(x)
3352             Math_MPC: {
3353             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3354             Math::MPC::Rmpc_tanh($r, $x, $ROUND);
3355             Math::MPC::Rmpc_ui_div($r, 1, $r, $ROUND);
3356             return $r;
3357             }
3358             }
3359              
3360             sub coth {
3361             my ($x) = @_;
3362             bless \__coth__(_any2mpfr_mpc($$x));
3363             }
3364              
3365             sub __acot__ {
3366             my ($x) = @_;
3367             goto(ref($x) =~ tr/:/_/rs);
3368              
3369             # acot(x) = atan(1/x)
3370             Math_MPFR: {
3371             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3372             Math::MPFR::Rmpfr_ui_div($r, 1, $x, $ROUND);
3373             Math::MPFR::Rmpfr_atan($r, $r, $ROUND);
3374             return $r;
3375             }
3376              
3377             # acot(x) = atan(1/x)
3378             Math_MPC: {
3379             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3380             Math::MPC::Rmpc_ui_div($r, 1, $x, $ROUND);
3381             Math::MPC::Rmpc_atan($r, $r, $ROUND);
3382             return $r;
3383             }
3384             }
3385              
3386             sub acot {
3387             my ($x) = @_;
3388             bless \__acot__(_any2mpfr_mpc($$x));
3389             }
3390              
3391             sub __acoth__ {
3392             my ($x) = @_;
3393             goto(ref($x) =~ tr/:/_/rs);
3394              
3395             # acoth(x) = atanh(1/x)
3396             Math_MPFR: {
3397              
3398             # Return a complex number for x > -1 and x < 1
3399             if ( Math::MPFR::Rmpfr_cmp_ui($x, 1) < 0
3400             and Math::MPFR::Rmpfr_cmp_si($x, -1) > 0) {
3401             $x = _mpfr2mpc($x);
3402             goto Math_MPC;
3403             }
3404              
3405             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3406             Math::MPFR::Rmpfr_ui_div($r, 1, $x, $ROUND);
3407             Math::MPFR::Rmpfr_atanh($r, $r, $ROUND);
3408             return $r;
3409             }
3410              
3411             # acoth(x) = atanh(1/x)
3412             Math_MPC: {
3413             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3414             Math::MPC::Rmpc_ui_div($r, 1, $x, $ROUND);
3415             Math::MPC::Rmpc_atanh($r, $r, $ROUND);
3416             return $r;
3417             }
3418             }
3419              
3420             sub acoth {
3421             my ($x) = @_;
3422             bless \__acoth__(_any2mpfr_mpc($$x));
3423             }
3424              
3425             sub __cis__ {
3426             my ($x) = @_;
3427             goto(ref($x) =~ tr/:/_/rs);
3428              
3429             Math_MPFR: {
3430             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3431             Math::MPC::Rmpc_set_ui_fr($r, 0, $x, $ROUND);
3432             Math::MPC::Rmpc_exp($r, $r, $ROUND);
3433             return $r;
3434             }
3435              
3436             Math_MPC: {
3437             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
3438             Math::MPC::Rmpc_mul_i($r, $x, 1, $ROUND);
3439             Math::MPC::Rmpc_exp($r, $r, $ROUND);
3440             return $r;
3441             }
3442             }
3443              
3444             sub cis {
3445             my ($x) = @_;
3446             bless \__cis__(_any2mpfr_mpc($$x));
3447             }
3448              
3449             sub __sin_cos__ {
3450             my ($x) = @_;
3451             goto(ref($x) =~ tr/:/_/rs);
3452              
3453             Math_MPFR: {
3454             my $cos = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3455             my $sin = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3456              
3457             Math::MPFR::Rmpfr_sin_cos($sin, $cos, $x, $ROUND);
3458              
3459             return ($sin, $cos);
3460             }
3461              
3462             Math_MPC: {
3463             my $cos = Math::MPC::Rmpc_init2(CORE::int($PREC));
3464             my $sin = Math::MPC::Rmpc_init2(CORE::int($PREC));
3465              
3466             Math::MPC::Rmpc_sin_cos($sin, $cos, $x, $ROUND, $ROUND);
3467              
3468             return ($sin, $cos);
3469             }
3470             }
3471              
3472             sub sin_cos {
3473             my ($x) = @_;
3474             my ($sin, $cos) = __sin_cos__(_any2mpfr_mpc($$x));
3475             ((bless \$sin), (bless \$cos));
3476             }
3477              
3478             #
3479             ## Special functions
3480             #
3481              
3482             sub __agm__ {
3483             my ($x, $y) = @_;
3484             goto(join('__', ref($x), ref($y)) =~ tr/:/_/rs);
3485              
3486             Math_MPFR__Math_MPFR: {
3487             if ( Math::MPFR::Rmpfr_sgn($x) < 0
3488             or Math::MPFR::Rmpfr_sgn($y) < 0) {
3489             ($x, $y) = (_mpfr2mpc($x), _mpfr2mpc($y));
3490             goto Math_MPC__Math_MPC;
3491             }
3492              
3493             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3494             Math::MPFR::Rmpfr_agm($r, $x, $y, $ROUND);
3495             return $r;
3496             }
3497              
3498             Math_MPC__Math_MPC: {
3499              
3500             # agm(0, x) = 0
3501             Math::MPC::Rmpc_cmp_si_si($x, 0, 0) || return $x;
3502              
3503             # agm(x, 0) = 0
3504             Math::MPC::Rmpc_cmp_si_si($y, 0, 0) || return $y;
3505              
3506             $PREC = CORE::int($PREC) if ref($PREC);
3507              
3508             my $a0 = Math::MPC::Rmpc_init2($PREC);
3509             my $g0 = Math::MPC::Rmpc_init2($PREC);
3510              
3511             my $a1 = Math::MPC::Rmpc_init2($PREC);
3512             my $g1 = Math::MPC::Rmpc_init2($PREC);
3513              
3514             my $t = Math::MPC::Rmpc_init2($PREC);
3515              
3516             Math::MPC::Rmpc_set($a0, $x, $ROUND);
3517             Math::MPC::Rmpc_set($g0, $y, $ROUND);
3518              
3519             my $count = 0;
3520             {
3521             Math::MPC::Rmpc_add($a1, $a0, $g0, $ROUND);
3522             Math::MPC::Rmpc_div_2ui($a1, $a1, 1, $ROUND);
3523              
3524             Math::MPC::Rmpc_mul($g1, $a0, $g0, $ROUND);
3525             Math::MPC::Rmpc_add($t, $a0, $g0, $ROUND);
3526             Math::MPC::Rmpc_sqr($t, $t, $ROUND);
3527             Math::MPC::Rmpc_cmp_si_si($t, 0, 0) || return $t;
3528             Math::MPC::Rmpc_div($g1, $g1, $t, $ROUND);
3529             Math::MPC::Rmpc_sqrt($g1, $g1, $ROUND);
3530             Math::MPC::Rmpc_add($t, $a0, $g0, $ROUND);
3531             Math::MPC::Rmpc_mul($g1, $g1, $t, $ROUND);
3532              
3533             if (Math::MPC::Rmpc_cmp($a0, $a1) and ++$count < $PREC) {
3534             Math::MPC::Rmpc_set($a0, $a1, $ROUND);
3535             Math::MPC::Rmpc_set($g0, $g1, $ROUND);
3536             redo;
3537             }
3538             }
3539              
3540             return $g0;
3541             }
3542              
3543             Math_MPFR__Math_MPC: {
3544             $x = _mpfr2mpc($x);
3545             goto Math_MPC__Math_MPC;
3546             }
3547              
3548             Math_MPC__Math_MPFR: {
3549             $y = _mpfr2mpc($y);
3550             goto Math_MPC__Math_MPC;
3551             }
3552             }
3553              
3554             sub agm {
3555             my ($x, $y) = @_;
3556             _valid(\$y);
3557             bless \__agm__(_any2mpfr_mpc($$x), _any2mpfr_mpc($$y));
3558             }
3559              
3560             sub __hypot__ {
3561             my ($x, $y) = @_;
3562              
3563             # hypot(x, y) = sqrt(x^2 + y^2)
3564              
3565             goto(join('__', ref($x), ref($y)) =~ tr/:/_/rs);
3566              
3567             Math_MPFR__Math_MPFR: {
3568             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3569             Math::MPFR::Rmpfr_hypot($r, $x, $y, $ROUND);
3570             return $r;
3571             }
3572              
3573             Math_MPFR__Math_MPC: {
3574             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3575             Math::MPC::Rmpc_abs($r, $y, $ROUND);
3576             Math::MPFR::Rmpfr_hypot($r, $r, $x, $ROUND);
3577             return $r;
3578             }
3579              
3580             Math_MPC__Math_MPFR: {
3581             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3582             Math::MPC::Rmpc_abs($r, $x, $ROUND);
3583             Math::MPFR::Rmpfr_hypot($r, $r, $y, $ROUND);
3584             return $r;
3585             }
3586              
3587             Math_MPC__Math_MPC: {
3588             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3589             Math::MPC::Rmpc_abs($r, $x, $ROUND);
3590             my $t = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3591             Math::MPC::Rmpc_abs($t, $y, $ROUND);
3592             Math::MPFR::Rmpfr_hypot($r, $r, $t, $ROUND);
3593             return $r;
3594             }
3595             }
3596              
3597             sub hypot {
3598             my ($x, $y) = @_;
3599             _valid(\$y);
3600             bless \__hypot__(_any2mpfr_mpc($$x), _any2mpfr_mpc($$y));
3601             }
3602              
3603             sub gamma {
3604             my ($x) = @_;
3605             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3606             Math::MPFR::Rmpfr_gamma($r, _any2mpfr($$x), $ROUND);
3607             bless \$r;
3608             }
3609              
3610             sub lngamma {
3611             my ($x) = @_;
3612             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3613             Math::MPFR::Rmpfr_lngamma($r, _any2mpfr($$x), $ROUND);
3614             bless \$r;
3615             }
3616              
3617             sub lgamma {
3618             my ($x) = @_;
3619             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3620             Math::MPFR::Rmpfr_lgamma($r, _any2mpfr($$x), $ROUND);
3621             bless \$r;
3622             }
3623              
3624             sub digamma {
3625             my ($x) = @_;
3626             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3627             Math::MPFR::Rmpfr_digamma($r, _any2mpfr($$x), $ROUND);
3628             bless \$r;
3629             }
3630              
3631             #
3632             ## beta(x, y) = gamma(x)*gamma(y) / gamma(x+y)
3633             #
3634             sub beta {
3635             my ($x, $y) = @_;
3636              
3637             _valid(\$y);
3638              
3639             $x = _any2mpfr($$x);
3640             $y = _any2mpfr($$y);
3641              
3642             my $t1 = Math::MPFR::Rmpfr_init2(CORE::int($PREC)); # gamma(x+y)
3643             my $t2 = Math::MPFR::Rmpfr_init2(CORE::int($PREC)); # gamma(y)
3644              
3645             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3646              
3647             Math::MPFR::Rmpfr_add($t1, $x, $y, $ROUND);
3648             Math::MPFR::Rmpfr_gamma($t1, $t1, $ROUND);
3649             Math::MPFR::Rmpfr_gamma($r, $x, $ROUND);
3650             Math::MPFR::Rmpfr_gamma($t2, $y, $ROUND);
3651             Math::MPFR::Rmpfr_mul($r, $r, $t2, $ROUND);
3652             Math::MPFR::Rmpfr_div($r, $r, $t1, $ROUND);
3653              
3654             bless \$r;
3655             }
3656              
3657             #
3658             ## eta(s) = (1 - 2^(1-s)) * zeta(s)
3659             #
3660             sub eta {
3661             my ($x) = @_;
3662              
3663             $x = _any2mpfr($$x);
3664              
3665             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3666              
3667             # Special case for eta(1) = log(2)
3668             if ( Math::MPFR::Rmpfr_integer_p($x)
3669             and Math::MPFR::Rmpfr_cmp_ui($x, 1) == 0) {
3670             Math::MPFR::Rmpfr_const_log2($r, $ROUND);
3671             return bless \$r;
3672             }
3673              
3674             my $t = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3675              
3676             Math::MPFR::Rmpfr_ui_sub($r, 1, $x, $ROUND);
3677             Math::MPFR::Rmpfr_ui_pow($r, 2, $r, $ROUND);
3678             Math::MPFR::Rmpfr_ui_sub($r, 1, $r, $ROUND);
3679              
3680             Math::MPFR::Rmpfr_zeta($t, $x, $ROUND);
3681             Math::MPFR::Rmpfr_mul($r, $r, $t, $ROUND);
3682              
3683             bless \$r;
3684             }
3685              
3686             sub zeta {
3687             my ($x) = @_;
3688             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3689              
3690             my $f = _any2mpfr($$x);
3691             if ( Math::MPFR::Rmpfr_integer_p($f)
3692             and Math::MPFR::Rmpfr_fits_ulong_p($f, $ROUND)) {
3693             Math::MPFR::Rmpfr_zeta_ui($r, Math::MPFR::Rmpfr_get_ui($f, $ROUND), $ROUND);
3694             }
3695             else {
3696             Math::MPFR::Rmpfr_zeta($r, $f, $ROUND);
3697             }
3698             bless \$r;
3699             }
3700              
3701             sub bernfrac {
3702             my ($n) = @_;
3703              
3704             $n = _any2ui($$n) // goto &nan;
3705              
3706             $n == 0 and return ONE;
3707             $n > 1 and $n % 2 and return ZERO; # Bn=0 for odd n>1
3708              
3709             # Using bernfrac() from `Math::Prime::Util::GMP`
3710             my ($num, $den) = Math::Prime::Util::GMP::bernfrac($n);
3711              
3712             my $q = Math::GMPq::Rmpq_init();
3713             Math::GMPq::Rmpq_set_str($q, "$num/$den", 10);
3714             bless \$q;
3715             }
3716              
3717             *bern = \&bernfrac;
3718             *bernoulli = \&bernfrac;
3719              
3720             sub bernreal {
3721             my ($n) = @_;
3722              
3723             $n = _any2ui($$n) // goto &nan;
3724              
3725             # |B(n)| = zeta(n) * n! / 2^(n-1) / pi^n
3726              
3727             $n == 0 and return ONE;
3728             $n == 1 and return do { state $x = bless(\_str2obj('1/2')) };
3729             $n % 2 and return ZERO; # Bn = 0 for odd n>1
3730              
3731             #local $PREC = CORE::int($n*CORE::log($n)+1);
3732              
3733             my $f = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3734             my $p = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3735              
3736             Math::MPFR::Rmpfr_zeta_ui($f, $n, $ROUND); # f = zeta(n)
3737             Math::MPFR::Rmpfr_set_ui($p, $n + 1, $ROUND); # p = n+1
3738             Math::MPFR::Rmpfr_gamma($p, $p, $ROUND); # p = gamma(p)
3739              
3740             Math::MPFR::Rmpfr_mul($f, $f, $p, $ROUND); # f = f * p
3741              
3742             Math::MPFR::Rmpfr_const_pi($p, $ROUND); # p = PI
3743             Math::MPFR::Rmpfr_pow_ui($p, $p, $n, $ROUND); # p = p^n
3744              
3745             Math::MPFR::Rmpfr_div_2ui($f, $f, $n - 1, $ROUND); # f = f / 2^(n-1)
3746              
3747             Math::MPFR::Rmpfr_div($f, $f, $p, $ROUND); # f = f/p
3748             Math::MPFR::Rmpfr_neg($f, $f, $ROUND) if $n % 4 == 0;
3749              
3750             bless \$f;
3751             }
3752              
3753             sub harmfrac {
3754             my ($n) = @_;
3755              
3756             $n = _any2ui($$n) // goto &nan;
3757             $n || return ZERO();
3758              
3759             # Using harmfrac() from Math::Prime::Util::GMP
3760             my ($num, $den) = Math::Prime::Util::GMP::harmfrac($n);
3761              
3762             my $q = Math::GMPq::Rmpq_init();
3763             Math::GMPq::Rmpq_set_str($q, "$num/$den", 10);
3764             bless \$q;
3765             }
3766              
3767             *harm = \&harmfrac;
3768             *harmonic = \&harmfrac;
3769              
3770             sub harmreal {
3771             my ($x) = @_;
3772              
3773             $x = _any2mpfr($$x);
3774              
3775             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3776             Math::MPFR::Rmpfr_add_ui($r, $x, 1, $ROUND);
3777             Math::MPFR::Rmpfr_digamma($r, $r, $ROUND);
3778              
3779             my $t = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3780             Math::MPFR::Rmpfr_const_euler($t, $ROUND);
3781             Math::MPFR::Rmpfr_add($r, $r, $t, $ROUND);
3782              
3783             bless \$r;
3784             }
3785              
3786             sub erf {
3787             my ($x) = @_;
3788             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3789             Math::MPFR::Rmpfr_erf($r, _any2mpfr($$x), $ROUND);
3790             bless \$r;
3791             }
3792              
3793             sub erfc {
3794             my ($x) = @_;
3795             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3796             Math::MPFR::Rmpfr_erfc($r, _any2mpfr($$x), $ROUND);
3797             bless \$r;
3798             }
3799              
3800             sub bessel_j {
3801             my ($x, $n) = @_;
3802              
3803             $n = defined($n) ? do { _valid(\$n); __numify__($$n) } : 0;
3804              
3805             if ($n < LONG_MIN or $n > ULONG_MAX) {
3806             return ZERO;
3807             }
3808              
3809             $x = _any2mpfr($$x);
3810             $n = CORE::int($n);
3811              
3812             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3813              
3814             if ($n == 0) {
3815             Math::MPFR::Rmpfr_j0($r, $x, $ROUND);
3816             }
3817             elsif ($n == 1) {
3818             Math::MPFR::Rmpfr_j1($r, $x, $ROUND);
3819             }
3820             else {
3821             Math::MPFR::Rmpfr_jn($r, $n, $x, $ROUND);
3822             }
3823              
3824             bless \$r;
3825             }
3826              
3827             *BesselJ = \&bessel_j;
3828              
3829             sub bessel_y {
3830             my ($x, $n) = @_;
3831              
3832             $n = defined($n) ? do { _valid(\$n); __numify__($$n) } : 0;
3833              
3834             if ($n < LONG_MIN or $n > ULONG_MAX) {
3835             if (__cmp__($$x, 0) < 0) {
3836             return nan();
3837             }
3838             return ($n < 0 ? inf() : ninf());
3839             }
3840              
3841             $x = _any2mpfr($$x);
3842             $n = CORE::int($n);
3843              
3844             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3845              
3846             if ($n == 0) {
3847             Math::MPFR::Rmpfr_y0($r, $x, $ROUND);
3848             }
3849             elsif ($n == 1) {
3850             Math::MPFR::Rmpfr_y1($r, $x, $ROUND);
3851             }
3852             else {
3853             Math::MPFR::Rmpfr_yn($r, $n, $x, $ROUND);
3854             }
3855              
3856             bless \$r;
3857             }
3858              
3859             *BesselY = \&bessel_y;
3860              
3861             sub eint {
3862             my ($x) = @_;
3863             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3864             Math::MPFR::Rmpfr_eint($r, _any2mpfr($$x), $ROUND);
3865             bless \$r;
3866             }
3867              
3868             *ei = \&eint;
3869             *Ei = \&eint;
3870              
3871             sub ai {
3872             my ($x) = @_;
3873             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3874             Math::MPFR::Rmpfr_ai($r, _any2mpfr($$x), $ROUND);
3875             bless \$r;
3876             }
3877              
3878             *airy = \&ai;
3879             *Ai = \&ai;
3880              
3881             sub li {
3882             my ($x) = @_;
3883             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3884             Math::MPFR::Rmpfr_log($r, _any2mpfr($$x), $ROUND);
3885             Math::MPFR::Rmpfr_eint($r, $r, $ROUND);
3886             bless \$r;
3887             }
3888              
3889             *Li = \&li;
3890              
3891             sub li2 {
3892             my ($x) = @_;
3893             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
3894             Math::MPFR::Rmpfr_li2($r, _any2mpfr($$x), $ROUND);
3895             bless \$r;
3896             }
3897              
3898             *Li2 = \&li2;
3899              
3900             #
3901             ## Comparison and testing operations
3902             #
3903              
3904             sub __eq__ {
3905             my ($x, $y) = @_;
3906              
3907             goto(join('__', ref($x), ref($y) || 'Scalar') =~ tr/:/_/rs);
3908              
3909             #
3910             ## MPFR
3911             #
3912             Math_MPFR__Math_MPFR: {
3913             return Math::MPFR::Rmpfr_equal_p($x, $y);
3914             }
3915              
3916             Math_MPFR__Math_GMPz: {
3917             return (Math::MPFR::Rmpfr_integer_p($x) and Math::MPFR::Rmpfr_cmp_z($x, $y) == 0);
3918             }
3919              
3920             Math_MPFR__Math_GMPq: {
3921             return (Math::MPFR::Rmpfr_number_p($x) and Math::MPFR::Rmpfr_cmp_q($x, $y) == 0);
3922             }
3923              
3924             Math_MPFR__Math_MPC: {
3925             $x = _mpfr2mpc($x);
3926             goto Math_MPC__Math_MPC;
3927             }
3928              
3929             Math_MPFR__Scalar: {
3930             return (
3931             Math::MPFR::Rmpfr_integer_p($x)
3932             and (
3933             $y < 0
3934             ? Math::MPFR::Rmpfr_cmp_si($x, $y)
3935             : Math::MPFR::Rmpfr_cmp_ui($x, $y)
3936             ) == 0
3937             );
3938             }
3939              
3940             #
3941             ## GMPq
3942             #
3943             Math_GMPq__Math_GMPq: {
3944             return Math::GMPq::Rmpq_equal($x, $y);
3945             }
3946              
3947             Math_GMPq__Math_GMPz: {
3948             return (Math::GMPq::Rmpq_integer_p($x) and Math::GMPq::Rmpq_cmp_z($x, $y) == 0);
3949             }
3950              
3951             Math_GMPq__Math_MPFR: {
3952             return (Math::MPFR::Rmpfr_number_p($y) and Math::MPFR::Rmpfr_cmp_q($y, $x) == 0);
3953             }
3954              
3955             Math_GMPq__Math_MPC: {
3956             $x = _mpq2mpc($x);
3957             goto Math_MPC__Math_MPC;
3958             }
3959              
3960             Math_GMPq__Scalar: {
3961             return (
3962             Math::GMPq::Rmpq_integer_p($x)
3963             and (
3964             $y < 0
3965             ? Math::GMPq::Rmpq_cmp_si($x, $y, 1)
3966             : Math::GMPq::Rmpq_cmp_ui($x, $y, 1)
3967             ) == 0
3968             );
3969             }
3970              
3971             #
3972             ## GMPz
3973             #
3974             Math_GMPz__Math_GMPz: {
3975             return (Math::GMPz::Rmpz_cmp($x, $y) == 0);
3976             }
3977              
3978             Math_GMPz__Math_GMPq: {
3979             return (Math::GMPq::Rmpq_integer_p($y) and Math::GMPq::Rmpq_cmp_z($y, $x) == 0);
3980             }
3981              
3982             Math_GMPz__Math_MPFR: {
3983             return (Math::MPFR::Rmpfr_integer_p($y) and Math::MPFR::Rmpfr_cmp_z($y, $x) == 0);
3984             }
3985              
3986             Math_GMPz__Math_MPC: {
3987             $x = _mpz2mpc($x);
3988             goto Math_MPC__Math_MPC;
3989             }
3990              
3991             Math_GMPz__Scalar: {
3992             return (
3993             (
3994             $y < 0
3995             ? Math::GMPz::Rmpz_cmp_si($x, $y)
3996             : Math::GMPz::Rmpz_cmp_ui($x, $y)
3997             ) == 0
3998             );
3999             }
4000              
4001             #
4002             ## MPC
4003             #
4004             Math_MPC__Math_MPC: {
4005             my $f1 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4006             my $f2 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4007              
4008             Math::MPC::RMPC_RE($f1, $x);
4009             Math::MPC::RMPC_RE($f2, $y);
4010              
4011             Math::MPFR::Rmpfr_equal_p($f1, $f2) || return 0;
4012              
4013             Math::MPC::RMPC_IM($f1, $x);
4014             Math::MPC::RMPC_IM($f2, $y);
4015              
4016             return Math::MPFR::Rmpfr_equal_p($f1, $f2);
4017             }
4018              
4019             Math_MPC__Math_GMPz: {
4020             $y = _mpz2mpc($y);
4021             goto Math_MPC__Math_MPC;
4022             }
4023              
4024             Math_MPC__Math_GMPq: {
4025             $y = _mpq2mpc($y);
4026             goto Math_MPC__Math_MPC;
4027             }
4028              
4029             Math_MPC__Math_MPFR: {
4030             $y = _mpfr2mpc($y);
4031             goto Math_MPC__Math_MPC;
4032             }
4033              
4034             Math_MPC__Scalar: {
4035             my $f = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4036             Math::MPC::RMPC_IM($f, $x);
4037             Math::MPFR::Rmpfr_zero_p($f) || return 0;
4038             Math::MPC::RMPC_RE($f, $x);
4039             $x = $f;
4040             goto Math_MPFR__Scalar;
4041             }
4042             }
4043              
4044             sub eq {
4045             my ($x, $y) = @_;
4046              
4047             ref($y) ne __PACKAGE__
4048             and return Sidef::Types::Bool::Bool::FALSE;
4049              
4050             __eq__($$x, $$y)
4051             ? (Sidef::Types::Bool::Bool::TRUE)
4052             : (Sidef::Types::Bool::Bool::FALSE);
4053             }
4054              
4055             sub __ne__ {
4056             my ($x, $y) = @_;
4057              
4058             goto(join('__', ref($x), ref($y) || 'Scalar') =~ tr/:/_/rs);
4059              
4060             #
4061             ## MPFR
4062             #
4063             Math_MPFR__Math_MPFR: {
4064             return !Math::MPFR::Rmpfr_equal_p($x, $y);
4065             }
4066              
4067             Math_MPFR__Math_GMPz: {
4068             return (!Math::MPFR::Rmpfr_integer_p($x) or Math::MPFR::Rmpfr_cmp_z($x, $y) != 0);
4069             }
4070              
4071             Math_MPFR__Math_GMPq: {
4072             return (!Math::MPFR::Rmpfr_number_p($x) or Math::MPFR::Rmpfr_cmp_q($x, $y) != 0);
4073             }
4074              
4075             Math_MPFR__Math_MPC: {
4076             $x = _mpfr2mpc($x);
4077             goto Math_MPC__Math_MPC;
4078             }
4079              
4080             Math_MPFR__Scalar: {
4081             return (
4082             !Math::MPFR::Rmpfr_integer_p($x)
4083             or (
4084             $y < 0
4085             ? Math::MPFR::Rmpfr_cmp_si($x, $y)
4086             : Math::MPFR::Rmpfr_cmp_ui($x, $y)
4087             ) != 0
4088             );
4089             }
4090              
4091             #
4092             ## GMPq
4093             #
4094             Math_GMPq__Math_GMPq: {
4095             return !Math::GMPq::Rmpq_equal($x, $y);
4096             }
4097              
4098             Math_GMPq__Math_GMPz: {
4099             return (!Math::GMPq::Rmpq_integer_p($x) or Math::GMPq::Rmpq_cmp_z($x, $y) != 0);
4100             }
4101              
4102             Math_GMPq__Math_MPFR: {
4103             return (!Math::MPFR::Rmpfr_number_p($y) or Math::MPFR::Rmpfr_cmp_q($y, $x) != 0);
4104             }
4105              
4106             Math_GMPq__Math_MPC: {
4107             $x = _mpq2mpc($x);
4108             goto Math_MPC__Math_MPC;
4109             }
4110              
4111             Math_GMPq__Scalar: {
4112             return (
4113             !Math::GMPq::Rmpq_integer_p($x)
4114             or (
4115             $y < 0
4116             ? Math::GMPq::Rmpq_cmp_si($x, $y, 1)
4117             : Math::GMPq::Rmpq_cmp_ui($x, $y, 1)
4118             ) != 0
4119             );
4120             }
4121              
4122             #
4123             ## GMPz
4124             #
4125             Math_GMPz__Math_GMPz: {
4126             return (Math::GMPz::Rmpz_cmp($x, $y) != 0);
4127             }
4128              
4129             Math_GMPz__Math_GMPq: {
4130             return (!Math::GMPq::Rmpq_integer_p($y) or Math::GMPq::Rmpq_cmp_z($y, $x) != 0);
4131             }
4132              
4133             Math_GMPz__Math_MPFR: {
4134             return (!Math::MPFR::Rmpfr_integer_p($y) or Math::MPFR::Rmpfr_cmp_z($y, $x) != 0);
4135             }
4136              
4137             Math_GMPz__Math_MPC: {
4138             $x = _mpz2mpc($x);
4139             goto Math_MPC__Math_MPC;
4140             }
4141              
4142             Math_GMPz__Scalar: {
4143             return (
4144             (
4145             $y < 0
4146             ? Math::GMPz::Rmpz_cmp_si($x, $y)
4147             : Math::GMPz::Rmpz_cmp_ui($x, $y)
4148             ) != 0
4149             );
4150             }
4151              
4152             #
4153             ## MPC
4154             #
4155             Math_MPC__Math_MPC: {
4156              
4157             my $f1 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4158             my $f2 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4159              
4160             Math::MPC::RMPC_RE($f1, $x);
4161             Math::MPC::RMPC_RE($f2, $y);
4162              
4163             Math::MPFR::Rmpfr_equal_p($f1, $f2) || return 1;
4164              
4165             Math::MPC::RMPC_IM($f1, $x);
4166             Math::MPC::RMPC_IM($f2, $y);
4167              
4168             return !Math::MPFR::Rmpfr_equal_p($f1, $f2);
4169             }
4170              
4171             Math_MPC__Math_GMPz: {
4172             $y = _mpz2mpc($y);
4173             goto Math_MPC__Math_MPC;
4174             }
4175              
4176             Math_MPC__Math_GMPq: {
4177             $y = _mpq2mpc($y);
4178             goto Math_MPC__Math_MPC;
4179             }
4180              
4181             Math_MPC__Math_MPFR: {
4182             $y = _mpfr2mpc($y);
4183             goto Math_MPC__Math_MPC;
4184             }
4185              
4186             Math_MPC__Scalar: {
4187             my $f = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4188             Math::MPC::RMPC_IM($f, $x);
4189             Math::MPFR::Rmpfr_zero_p($f) || return 1;
4190             Math::MPC::RMPC_RE($f, $x);
4191             $x = $f;
4192             goto Math_MPFR__Scalar;
4193             }
4194             }
4195              
4196             sub ne {
4197             my ($x, $y) = @_;
4198              
4199             ref($y) ne __PACKAGE__
4200             and return Sidef::Types::Bool::Bool::TRUE;
4201              
4202             __ne__($$x, $$y)
4203             ? (Sidef::Types::Bool::Bool::TRUE)
4204             : (Sidef::Types::Bool::Bool::FALSE);
4205             }
4206              
4207             sub __cmp__ {
4208             my ($x, $y) = @_;
4209              
4210             goto(join('__', ref($x), ref($y) || 'Scalar') =~ tr/:/_/rs);
4211              
4212             #
4213             ## MPFR
4214             #
4215             Math_MPFR__Math_MPFR: {
4216             if ( Math::MPFR::Rmpfr_nan_p($x)
4217             or Math::MPFR::Rmpfr_nan_p($y)) {
4218             return undef;
4219             }
4220              
4221             return Math::MPFR::Rmpfr_cmp($x, $y);
4222             }
4223              
4224             Math_MPFR__Math_GMPz: {
4225             Math::MPFR::Rmpfr_nan_p($x) && return undef;
4226             return Math::MPFR::Rmpfr_cmp_z($x, $y);
4227             }
4228              
4229             Math_MPFR__Math_GMPq: {
4230             Math::MPFR::Rmpfr_nan_p($x) && return undef;
4231             return Math::MPFR::Rmpfr_cmp_q($x, $y);
4232             }
4233              
4234             Math_MPFR__Math_MPC: {
4235             $x = _mpfr2mpc($x);
4236             goto Math_MPC__Math_MPC;
4237             }
4238              
4239             Math_MPFR__Scalar: {
4240             Math::MPFR::Rmpfr_nan_p($x) && return undef;
4241             return (
4242             $y < 0
4243             ? Math::MPFR::Rmpfr_cmp_si($x, $y)
4244             : Math::MPFR::Rmpfr_cmp_ui($x, $y)
4245             );
4246             }
4247              
4248             #
4249             ## GMPq
4250             #
4251             Math_GMPq__Math_GMPq: {
4252             return Math::GMPq::Rmpq_cmp($x, $y);
4253             }
4254              
4255             Math_GMPq__Math_GMPz: {
4256             return Math::GMPq::Rmpq_cmp_z($x, $y);
4257             }
4258              
4259             Math_GMPq__Math_MPFR: {
4260             Math::MPFR::Rmpfr_nan_p($y) && return undef;
4261             return -(Math::MPFR::Rmpfr_cmp_q($y, $x));
4262             }
4263              
4264             Math_GMPq__Math_MPC: {
4265             $x = _mpq2mpc($x);
4266             goto Math_MPC__Math_MPC;
4267             }
4268              
4269             Math_GMPq__Scalar: {
4270             return (
4271             $y < 0
4272             ? Math::GMPq::Rmpq_cmp_si($x, $y, 1)
4273             : Math::GMPq::Rmpq_cmp_ui($x, $y, 1)
4274             );
4275             }
4276              
4277             #
4278             ## GMPz
4279             #
4280             Math_GMPz__Math_GMPz: {
4281             return Math::GMPz::Rmpz_cmp($x, $y);
4282             }
4283              
4284             Math_GMPz__Math_GMPq: {
4285             return -(Math::GMPq::Rmpq_cmp_z($y, $x));
4286             }
4287              
4288             Math_GMPz__Math_MPFR: {
4289             Math::MPFR::Rmpfr_nan_p($y) && return undef;
4290             return -(Math::MPFR::Rmpfr_cmp_z($y, $x));
4291             }
4292              
4293             Math_GMPz__Math_MPC: {
4294             $x = _mpz2mpc($x);
4295             goto Math_MPC__Math_MPC;
4296             }
4297              
4298             Math_GMPz__Scalar: {
4299             return (
4300             $y < 0
4301             ? Math::GMPz::Rmpz_cmp_si($x, $y)
4302             : Math::GMPz::Rmpz_cmp_ui($x, $y)
4303             );
4304             }
4305              
4306             #
4307             ## MPC
4308             #
4309             Math_MPC__Math_MPC: {
4310             my $f = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4311              
4312             Math::MPC::RMPC_RE($f, $x);
4313             Math::MPFR::Rmpfr_nan_p($f) && return undef;
4314              
4315             Math::MPC::RMPC_RE($f, $y);
4316             Math::MPFR::Rmpfr_nan_p($f) && return undef;
4317              
4318             Math::MPC::RMPC_IM($f, $x);
4319             Math::MPFR::Rmpfr_nan_p($f) && return undef;
4320              
4321             Math::MPC::RMPC_IM($f, $y);
4322             Math::MPFR::Rmpfr_nan_p($f) && return undef;
4323              
4324             my $si = Math::MPC::Rmpc_cmp($x, $y);
4325             my $re_cmp = Math::MPC::RMPC_INEX_RE($si);
4326             $re_cmp == 0 or return $re_cmp;
4327             return Math::MPC::RMPC_INEX_IM($si);
4328             }
4329              
4330             Math_MPC__Math_GMPz: {
4331             $y = _mpz2mpc($y);
4332             goto Math_MPC__Math_MPC;
4333             }
4334              
4335             Math_MPC__Math_GMPq: {
4336             $y = _mpq2mpc($y);
4337             goto Math_MPC__Math_MPC;
4338             }
4339              
4340             Math_MPC__Math_MPFR: {
4341             $y = _mpfr2mpc($y);
4342             goto Math_MPC__Math_MPC;
4343             }
4344              
4345             Math_MPC__Scalar: {
4346             $y = _any2mpc(_str2obj($y));
4347             goto Math_MPC__Math_MPC;
4348             }
4349             }
4350              
4351             sub cmp {
4352             my ($x, $y) = @_;
4353             _valid(\$y);
4354             my $cmp = __cmp__($$x, $$y) // return undef;
4355             !$cmp ? ZERO : ($cmp > 0) ? ONE : MONE;
4356             }
4357              
4358             # TODO: add the acmp() method.
4359              
4360             sub gt {
4361             my ($x, $y) = @_;
4362             _valid(\$y);
4363             ((__cmp__($$x, $$y) // return undef) > 0)
4364             ? (Sidef::Types::Bool::Bool::TRUE)
4365             : (Sidef::Types::Bool::Bool::FALSE);
4366             }
4367              
4368             sub ge {
4369             my ($x, $y) = @_;
4370             _valid(\$y);
4371             ((__cmp__($$x, $$y) // return undef) >= 0)
4372             ? (Sidef::Types::Bool::Bool::TRUE)
4373             : (Sidef::Types::Bool::Bool::FALSE);
4374             }
4375              
4376             sub lt {
4377             my ($x, $y) = @_;
4378             _valid(\$y);
4379             ((__cmp__($$x, $$y) // return undef) < 0)
4380             ? (Sidef::Types::Bool::Bool::TRUE)
4381             : (Sidef::Types::Bool::Bool::FALSE);
4382             }
4383              
4384             sub le {
4385             my ($x, $y) = @_;
4386             _valid(\$y);
4387             ((__cmp__($$x, $$y) // return undef) <= 0)
4388             ? (Sidef::Types::Bool::Bool::TRUE)
4389             : (Sidef::Types::Bool::Bool::FALSE);
4390             }
4391              
4392             sub is_zero {
4393             my ($x) = @_;
4394             __eq__($$x, 0)
4395             ? (Sidef::Types::Bool::Bool::TRUE)
4396             : (Sidef::Types::Bool::Bool::FALSE);
4397             }
4398              
4399             sub is_one {
4400             my ($x) = @_;
4401             __eq__($$x, 1)
4402             ? (Sidef::Types::Bool::Bool::TRUE)
4403             : (Sidef::Types::Bool::Bool::FALSE);
4404             }
4405              
4406             sub is_mone {
4407             my ($x) = @_;
4408             __eq__($$x, -1)
4409             ? (Sidef::Types::Bool::Bool::TRUE)
4410             : (Sidef::Types::Bool::Bool::FALSE);
4411             }
4412              
4413             sub is_positive {
4414             my ($x) = @_;
4415             ((__cmp__($$x, 0) // return undef) > 0)
4416             ? (Sidef::Types::Bool::Bool::TRUE)
4417             : (Sidef::Types::Bool::Bool::FALSE);
4418             }
4419              
4420             *is_pos = \&is_positive;
4421              
4422             sub is_negative {
4423             my ($x) = @_;
4424             ((__cmp__($$x, 0) // return undef) < 0)
4425             ? (Sidef::Types::Bool::Bool::TRUE)
4426             : (Sidef::Types::Bool::Bool::FALSE);
4427             }
4428              
4429             *is_neg = \&is_negative;
4430              
4431             sub __sgn__ {
4432             my ($x) = @_;
4433             goto(ref($x) =~ tr/:/_/rs);
4434              
4435             Math_MPFR: {
4436             goto &Math::MPFR::Rmpfr_sgn;
4437             }
4438              
4439             Math_GMPq: {
4440             goto &Math::GMPq::Rmpq_sgn;
4441             }
4442              
4443             Math_GMPz: {
4444             goto &Math::GMPz::Rmpz_sgn;
4445             }
4446              
4447             Math_MPC: {
4448             my $abs = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4449             Math::MPC::Rmpc_abs($abs, $x, $ROUND);
4450              
4451             if (Math::MPFR::Rmpfr_zero_p($abs)) { # it's zero
4452             return 0;
4453             }
4454              
4455             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
4456             Math::MPC::Rmpc_div_fr($r, $x, $abs, $ROUND);
4457             return $r;
4458             }
4459             }
4460              
4461             sub sign {
4462             my ($x) = @_;
4463             my $r = __sgn__($$x);
4464             if (ref($r)) {
4465             bless \$r;
4466             }
4467             else {
4468             ($r < 0) ? MONE : ($r > 0) ? ONE : ZERO;
4469             }
4470             }
4471              
4472             *sgn = \&sign;
4473              
4474             sub popcount {
4475             my ($x) = @_;
4476             my $z = _any2mpz($$x) // return MONE;
4477              
4478             if (Math::GMPz::Rmpz_sgn($z) < 0) {
4479             my $t = Math::GMPz::Rmpz_init();
4480             Math::GMPz::Rmpz_neg($t, $z);
4481             $z = $t;
4482             }
4483              
4484             __PACKAGE__->_set_uint(Math::GMPz::Rmpz_popcount($z));
4485             }
4486              
4487             sub __is_int__ {
4488             my ($x) = @_;
4489              
4490             ref($x) eq 'Math::GMPz' && return 1;
4491             ref($x) eq 'Math::GMPq' && return Math::GMPq::Rmpq_integer_p($x);
4492             ref($x) eq 'Math::MPFR' && return Math::MPFR::Rmpfr_integer_p($x);
4493              
4494             (@_) = _any2mpfr($x);
4495             goto __SUB__;
4496             }
4497              
4498             sub is_int {
4499             my ($x) = @_;
4500             __is_int__($$x)
4501             ? (Sidef::Types::Bool::Bool::TRUE)
4502             : (Sidef::Types::Bool::Bool::FALSE);
4503             }
4504              
4505             sub __is_rat__ {
4506             my ($x) = @_;
4507             (ref($x) eq 'Math::GMPz' or ref($x) eq 'Math::GMPq');
4508             }
4509              
4510             sub is_rat {
4511             my ($x) = @_;
4512             __is_rat__($$x)
4513             ? (Sidef::Types::Bool::Bool::TRUE)
4514             : (Sidef::Types::Bool::Bool::FALSE);
4515             }
4516              
4517             sub __is_real__ {
4518             my ($x) = @_;
4519              
4520             ref($x) eq 'Math::GMPz' && return 1;
4521             ref($x) eq 'Math::GMPq' && return 1;
4522             ref($x) eq 'Math::MPFR' && return Math::MPFR::Rmpfr_number_p($x);
4523              
4524             (@_) = _any2mpfr($x);
4525             goto __SUB__;
4526             }
4527              
4528             sub is_real {
4529             my ($x) = @_;
4530             __is_real__($$x)
4531             ? (Sidef::Types::Bool::Bool::TRUE)
4532             : (Sidef::Types::Bool::Bool::FALSE);
4533             }
4534              
4535             sub __is_imag__ {
4536             my ($x) = @_;
4537              
4538             ref($x) eq 'Math::MPC' or return 0;
4539              
4540             my $f = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4541             Math::MPC::RMPC_RE($f, $x);
4542             Math::MPFR::Rmpfr_zero_p($f) || return 0; # is complex
4543             Math::MPC::RMPC_IM($f, $x);
4544             !Math::MPFR::Rmpfr_zero_p($f);
4545             }
4546              
4547             sub is_imag {
4548             my ($x) = @_;
4549             __is_imag__($$x)
4550             ? (Sidef::Types::Bool::Bool::TRUE)
4551             : (Sidef::Types::Bool::Bool::FALSE);
4552             }
4553              
4554             sub __is_complex__ {
4555             my ($x) = @_;
4556              
4557             ref($x) eq 'Math::MPC' or return 0;
4558              
4559             my $f = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4560             Math::MPC::RMPC_IM($f, $x);
4561             Math::MPFR::Rmpfr_zero_p($f) && return 0; # is real
4562             Math::MPC::RMPC_RE($f, $x);
4563             !Math::MPFR::Rmpfr_zero_p($f);
4564             }
4565              
4566             sub is_complex {
4567             my ($x) = @_;
4568             __is_complex__($$x)
4569             ? (Sidef::Types::Bool::Bool::TRUE)
4570             : (Sidef::Types::Bool::Bool::FALSE);
4571             }
4572              
4573             sub is_even {
4574             my ($x) = @_;
4575             (__is_int__($$x) && Math::GMPz::Rmpz_even_p(_any2mpz($$x) // (return Sidef::Types::Bool::Bool::FALSE)))
4576             ? (Sidef::Types::Bool::Bool::TRUE)
4577             : (Sidef::Types::Bool::Bool::FALSE);
4578             }
4579              
4580             sub is_odd {
4581             my ($x) = @_;
4582             (__is_int__($$x) && Math::GMPz::Rmpz_odd_p(_any2mpz($$x) // (return Sidef::Types::Bool::Bool::FALSE)))
4583             ? (Sidef::Types::Bool::Bool::TRUE)
4584             : (Sidef::Types::Bool::Bool::FALSE);
4585             }
4586              
4587             sub is_div {
4588             my ($x, $y) = @_;
4589             _valid(\$y);
4590             __eq__(__mod__($$x, $$y), 0)
4591             ? (Sidef::Types::Bool::Bool::TRUE)
4592             : (Sidef::Types::Bool::Bool::FALSE);
4593             }
4594              
4595             sub divides {
4596             my ($x, $y) = @_;
4597             _valid(\$y);
4598             __eq__(__mod__($$y, $$x), 0)
4599             ? (Sidef::Types::Bool::Bool::TRUE)
4600             : (Sidef::Types::Bool::Bool::FALSE);
4601             }
4602              
4603             sub __is_inf__ {
4604             my ($x) = @_;
4605              
4606             ref($x) eq 'Math::GMPz' && return 0;
4607             ref($x) eq 'Math::GMPq' && return 0;
4608             ref($x) eq 'Math::MPFR' && return (Math::MPFR::Rmpfr_inf_p($x) and Math::MPFR::Rmpfr_sgn($x) > 0);
4609              
4610             (@_) = _any2mpfr($x);
4611             goto __SUB__;
4612             }
4613              
4614             sub is_inf {
4615             my ($x) = @_;
4616             __is_inf__($$x)
4617             ? Sidef::Types::Bool::Bool::TRUE
4618             : Sidef::Types::Bool::Bool::FALSE;
4619             }
4620              
4621             sub __is_ninf__ {
4622             my ($x) = @_;
4623              
4624             ref($x) eq 'Math::GMPz' && return 0;
4625             ref($x) eq 'Math::GMPq' && return 0;
4626             ref($x) eq 'Math::MPFR' && return (Math::MPFR::Rmpfr_inf_p($x) and Math::MPFR::Rmpfr_sgn($x) < 0);
4627              
4628             (@_) = _any2mpfr($x);
4629             goto __SUB__;
4630             }
4631              
4632             sub is_ninf {
4633             my ($x) = @_;
4634             __is_ninf__($$x)
4635             ? Sidef::Types::Bool::Bool::TRUE
4636             : Sidef::Types::Bool::Bool::FALSE;
4637             }
4638              
4639             sub is_nan {
4640             my ($x) = @_;
4641              
4642             $x = $$x;
4643              
4644             ref($x) eq 'Math::GMPz' && return Sidef::Types::Bool::Bool::FALSE;
4645             ref($x) eq 'Math::GMPq' && return Sidef::Types::Bool::Bool::FALSE;
4646             ref($x) eq 'Math::MPFR'
4647             && return (
4648             Math::MPFR::Rmpfr_nan_p($x)
4649             ? Sidef::Types::Bool::Bool::TRUE
4650             : Sidef::Types::Bool::Bool::FALSE
4651             );
4652              
4653             my $t = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4654              
4655             Math::MPC::RMPC_RE($t, $x);
4656             Math::MPFR::Rmpfr_nan_p($t) && return Sidef::Types::Bool::Bool::TRUE;
4657              
4658             Math::MPC::RMPC_IM($t, $x);
4659             Math::MPFR::Rmpfr_nan_p($t) && return Sidef::Types::Bool::Bool::TRUE;
4660              
4661             return Sidef::Types::Bool::Bool::FALSE;
4662             }
4663              
4664             sub max {
4665             my ($x, $y) = @_;
4666             _valid(\$y);
4667             (__cmp__($$x, $$y) // return undef) > 0 ? $x : $y;
4668             }
4669              
4670             sub min {
4671             my ($x, $y) = @_;
4672             _valid(\$y);
4673             (__cmp__($$x, $$y) // return undef) < 0 ? $x : $y;
4674             }
4675              
4676             sub as_int {
4677             my ($x, $y) = @_;
4678              
4679             my $base = 10;
4680             if (defined($y)) {
4681             _valid(\$y);
4682             $base = _any2ui($$y) // 0;
4683             if ($base < 2 or $base > 36) {
4684             die "[ERROR] Number.as_int(): base must be between 2 and 36, got $y";
4685             }
4686             }
4687              
4688             Sidef::Types::String::String->new(Math::GMPz::Rmpz_get_str((_any2mpz($$x) // return undef), $base));
4689             }
4690              
4691             sub __base__ {
4692             my ($x, $base) = @_;
4693             goto(ref($x) =~ tr/:/_/rs);
4694              
4695             Math_GMPz: {
4696             return Math::GMPz::Rmpz_get_str($x, $base);
4697             }
4698              
4699             Math_GMPq: {
4700             return Math::GMPq::Rmpq_get_str($x, $base);
4701             }
4702              
4703             Math_MPFR: {
4704             return Math::MPFR::Rmpfr_get_str($x, $base, CORE::int($PREC) >> 2, $ROUND);
4705             }
4706              
4707             Math_MPC: {
4708             my $fr = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4709             Math::MPC::RMPC_RE($fr, $x);
4710             my $real = __base__($fr, $base);
4711             Math::MPC::RMPC_IM($fr, $x);
4712             return $real if Math::MPFR::Rmpfr_zero_p($fr);
4713             my $imag = __base__($fr, $base);
4714             return "($real $imag)";
4715             }
4716             }
4717              
4718             sub base {
4719             my ($x, $y) = @_;
4720              
4721             my $base = 10;
4722             if (defined($y)) {
4723             _valid(\$y);
4724             $base = _any2ui($$y) // 0;
4725             if ($base < 2 or $base > 36) {
4726             die "[ERROR] Number.base(): base must be between 2 and 36, got $y";
4727             }
4728             }
4729              
4730             Sidef::Types::String::String->new(($base == 10) ? __stringify__($$x) : __base__($$x, $base));
4731             }
4732              
4733             *in_base = \&base;
4734              
4735             sub as_rat {
4736             my ($x, $y) = @_;
4737              
4738             my $base = 10;
4739             if (defined($y)) {
4740             _valid(\$y);
4741             $base = _any2ui($$y) // 0;
4742             if ($base < 2 or $base > 36) {
4743             die "[ERROR] base must be between 2 and 36, got $y";
4744             }
4745             }
4746              
4747             my $str =
4748             ref($$x) eq 'Math::GMPz'
4749             ? Math::GMPz::Rmpz_get_str($$x, $base)
4750             : Math::GMPq::Rmpq_get_str((_any2mpq($$x) // return undef), $base);
4751              
4752             Sidef::Types::String::String->new($str);
4753             }
4754              
4755             sub as_frac {
4756             my ($x, $y) = @_;
4757              
4758             my $base = 10;
4759             if (defined($y)) {
4760             _valid(\$y);
4761             $base = _any2ui($$y) // 0;
4762             if ($base < 2 or $base > 36) {
4763             die "as_frac(): base must be between 2 and 36, got $y";
4764             }
4765             }
4766              
4767             my $str =
4768             ref($$x) eq 'Math::GMPz'
4769             ? Math::GMPz::Rmpz_get_str($$x, $base)
4770             : Math::GMPq::Rmpq_get_str((_any2mpq($$x) // return undef), $base);
4771              
4772             $str .= '/1' if (index($str, '/') == -1);
4773              
4774             Sidef::Types::String::String->new($str);
4775             }
4776              
4777             sub as_cfrac {
4778             my ($x, $n) = @_;
4779              
4780             my $p = CORE::int($PREC) >> 1;
4781              
4782             $x = $$x;
4783             $n = defined($n) ? do { _valid(\$n); _any2ui($$n) // 0 } : ($p >> 1);
4784              
4785             goto(ref($x) =~ tr/:/_/rs);
4786              
4787             Math_GMPq: {
4788             my @cfrac;
4789             my $q = Math::GMPq::Rmpq_init();
4790              
4791             Math::GMPq::Rmpq_set($q, $x);
4792              
4793             for (1 .. $n) {
4794             my $z = __floor__($q);
4795             push @cfrac, bless \$z;
4796             Math::GMPq::Rmpq_sub_z($q, $q, $z);
4797             Math::GMPq::Rmpq_sgn($q) || last;
4798             Math::GMPq::Rmpq_inv($q, $q);
4799             }
4800              
4801             return Sidef::Types::Array::Array->new(\@cfrac);
4802             }
4803              
4804             Math_MPFR: {
4805             my @cfrac;
4806             my $f = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4807              
4808             Math::MPFR::Rmpfr_set($f, $x, $ROUND);
4809              
4810             for (1 .. $n) {
4811             my $t = __floor__($f);
4812             push @cfrac, bless \$t;
4813              
4814             Math::MPFR::Rmpfr_eq($f, $t, $p) && last;
4815             Math::MPFR::Rmpfr_sub($f, $f, $t, $ROUND);
4816             Math::MPFR::Rmpfr_ui_div($f, 1, $f, $ROUND);
4817             }
4818              
4819             return Sidef::Types::Array::Array->new(\@cfrac);
4820             }
4821              
4822             Math_MPC: {
4823             my @cfrac;
4824             my $c = Math::MPC::Rmpc_init2(CORE::int($PREC));
4825              
4826             my $real_1 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4827             my $real_2 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4828              
4829             my $imag_1 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4830             my $imag_2 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4831              
4832             Math::MPC::Rmpc_set($c, $x, $ROUND);
4833              
4834             for (1 .. $n) {
4835             my $t = __floor__($c);
4836             push @cfrac, bless \$t;
4837              
4838             Math::MPC::Rmpc_real($real_1, $c, $ROUND);
4839             Math::MPC::Rmpc_imag($imag_1, $c, $ROUND);
4840              
4841             if (ref($t) eq 'Math::MPFR') {
4842             Math::MPFR::Rmpfr_neg($t, $t, $ROUND);
4843             Math::MPC::Rmpc_add_fr($c, $c, $t, $ROUND);
4844             Math::MPFR::Rmpfr_neg($t, $t, $ROUND);
4845              
4846             Math::MPFR::Rmpfr_set($real_2, $t, $ROUND);
4847             Math::MPFR::Rmpfr_set_ui($imag_2, 0, $ROUND);
4848             }
4849             else {
4850             Math::MPC::Rmpc_sub($c, $c, $t, $ROUND);
4851              
4852             Math::MPC::Rmpc_real($real_2, $t, $ROUND);
4853             Math::MPC::Rmpc_imag($imag_2, $t, $ROUND);
4854             }
4855              
4856             #<<<
4857             Math::MPFR::Rmpfr_eq($real_1, $real_2, $p)
4858             && Math::MPFR::Rmpfr_eq($imag_1, $imag_2, $p)
4859             && last;
4860             #>>>
4861              
4862             Math::MPC::Rmpc_ui_div($c, 1, $c, $ROUND);
4863             }
4864              
4865             return Sidef::Types::Array::Array->new(\@cfrac);
4866             }
4867              
4868             Math_GMPz: {
4869             return Sidef::Types::Array::Array->new([bless \$x]);
4870             }
4871             }
4872              
4873             sub as_float {
4874             my ($x, $prec) = @_;
4875              
4876             if (defined($prec)) {
4877             _valid(\$prec);
4878             $prec = (_any2ui($$prec) // 0) << 2;
4879              
4880             state $min_prec = Math::MPFR::RMPFR_PREC_MIN();
4881             state $max_prec = Math::MPFR::RMPFR_PREC_MAX();
4882              
4883             if ($prec < $min_prec or $prec > $max_prec) {
4884             die "as_float(): precision must be between $min_prec and $max_prec, got ", $prec >> 2;
4885             }
4886             }
4887             else {
4888             $prec = CORE::int($PREC);
4889             }
4890              
4891             local $PREC = $prec;
4892             Sidef::Types::String::String->new(__stringify__(_any2mpfr_mpc($$x)));
4893             }
4894              
4895             *as_dec = \&as_float;
4896              
4897             sub dump {
4898             my ($x) = @_;
4899              
4900             $x = $$x;
4901             Sidef::Types::String::String->new(
4902             ref($x) eq 'Math::GMPq' ? Math::GMPq::Rmpq_get_str($x, 10)
4903             : ref($x) eq 'Math::GMPz' ? Math::GMPz::Rmpz_get_str($x, 10)
4904             : __stringify__($x)
4905             );
4906             }
4907              
4908             sub as_bin {
4909             my ($x) = @_;
4910             Sidef::Types::String::String->new(Math::GMPz::Rmpz_get_str((_any2mpz($$x) // return undef), 2));
4911             }
4912              
4913             sub as_oct {
4914             my ($x) = @_;
4915             Sidef::Types::String::String->new(Math::GMPz::Rmpz_get_str((_any2mpz($$x) // return undef), 8));
4916             }
4917              
4918             sub as_hex {
4919             my ($x) = @_;
4920             Sidef::Types::String::String->new(Math::GMPz::Rmpz_get_str((_any2mpz($$x) // return undef), 16));
4921             }
4922              
4923             sub digits {
4924             my ($x, $y) = @_;
4925              
4926             my $str = as_int($x, $y) // return undef;
4927             my @digits = split(//, "$str");
4928             shift(@digits) if $digits[0] eq '-';
4929              
4930             Sidef::Types::Array::Array->new(
4931             map {
4932             defined($y)
4933             ? Sidef::Types::String::String->new($_)
4934             : __PACKAGE__->_set_uint($_)
4935             } @digits
4936             );
4937             }
4938              
4939             sub digit {
4940             my ($x, $y, $z) = @_;
4941              
4942             _valid(\$y);
4943              
4944             my $str = as_int($x, $z) // return undef;
4945             my @digits = split(//, "$str");
4946             shift(@digits) if $digits[0] eq '-';
4947              
4948             $y = _any2si($$y) // return undef;
4949             exists($digits[$y])
4950             ? (
4951             defined($z)
4952             ? Sidef::Types::String::String->new($digits[$y])
4953             : __PACKAGE__->_set_uint($digits[$y])
4954             )
4955             : undef;
4956             }
4957              
4958             sub length {
4959             my ($x) = @_;
4960             my ($z) = _any2mpz($$x) // return MONE;
4961             my $neg = (Math::GMPz::Rmpz_sgn($z) < 0) ? 1 : 0;
4962             __PACKAGE__->_set_uint(CORE::length(Math::GMPz::Rmpz_get_str($z, 10)) - $neg);
4963             }
4964              
4965             *len = \&length;
4966             *size = \&length;
4967              
4968             sub __floor__ {
4969             my ($x) = @_;
4970             goto(ref($x) =~ tr/:/_/rs);
4971              
4972             Math_MPFR: {
4973             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4974             Math::MPFR::Rmpfr_floor($r, $x);
4975             return $r;
4976             }
4977              
4978             Math_GMPq: {
4979             my $r = Math::GMPz::Rmpz_init();
4980             Math::GMPz::Rmpz_set_q($r, $x);
4981             Math::GMPq::Rmpq_integer_p($x) && return $r;
4982             Math::GMPz::Rmpz_sub_ui($r, $r, 1) if Math::GMPq::Rmpq_sgn($x) < 0;
4983             return $r;
4984             }
4985              
4986             Math_MPC: {
4987             my $real = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4988             my $imag = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
4989              
4990             Math::MPC::RMPC_RE($real, $x);
4991             Math::MPC::RMPC_IM($imag, $x);
4992              
4993             Math::MPFR::Rmpfr_floor($real, $real);
4994             Math::MPFR::Rmpfr_floor($imag, $imag);
4995              
4996             if (Math::MPFR::Rmpfr_zero_p($imag)) {
4997             return $real;
4998             }
4999              
5000             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
5001             Math::MPC::Rmpc_set_fr_fr($r, $real, $imag, $ROUND);
5002             return $r;
5003             }
5004             }
5005              
5006             sub floor {
5007             my ($x) = @_;
5008             ref($$x) eq 'Math::GMPz' and return $x; # already an integer
5009             bless \__floor__($$x);
5010             }
5011              
5012             sub __ceil__ {
5013             my ($x) = @_;
5014             goto(ref($x) =~ tr/:/_/rs);
5015              
5016             Math_MPFR: {
5017             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5018             Math::MPFR::Rmpfr_ceil($r, $x);
5019             return $r;
5020             }
5021              
5022             Math_GMPq: {
5023             my $r = Math::GMPz::Rmpz_init();
5024             Math::GMPz::Rmpz_set_q($r, $x);
5025             Math::GMPq::Rmpq_integer_p($x) && return $r;
5026             Math::GMPz::Rmpz_add_ui($r, $r, 1) if Math::GMPq::Rmpq_sgn($x) > 0;
5027             return $r;
5028             }
5029              
5030             Math_MPC: {
5031             my $real = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5032             my $imag = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5033              
5034             Math::MPC::RMPC_RE($real, $x);
5035             Math::MPC::RMPC_IM($imag, $x);
5036              
5037             Math::MPFR::Rmpfr_ceil($real, $real);
5038             Math::MPFR::Rmpfr_ceil($imag, $imag);
5039              
5040             if (Math::MPFR::Rmpfr_zero_p($imag)) {
5041             return $real;
5042             }
5043              
5044             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
5045             Math::MPC::Rmpc_set_fr_fr($r, $real, $imag, $ROUND);
5046             return $r;
5047             }
5048             }
5049              
5050             sub ceil {
5051             my ($x) = @_;
5052             ref($$x) eq 'Math::GMPz' and return $x; # already an integer
5053             bless \__ceil__($$x);
5054             }
5055              
5056             sub __inc__ {
5057             my ($x) = @_;
5058             goto(ref($x) =~ tr/:/_/rs);
5059              
5060             Math_GMPz: {
5061             my $r = Math::GMPz::Rmpz_init_set($x);
5062             Math::GMPz::Rmpz_add_ui($r, $r, 1);
5063             return $r;
5064             }
5065              
5066             Math_MPFR: {
5067             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5068             Math::MPFR::Rmpfr_add_ui($r, $x, 1, $ROUND);
5069             return $r;
5070             }
5071              
5072             Math_GMPq: {
5073             state $one = Math::GMPz::Rmpz_init_set_ui_nobless(1);
5074             my $r = Math::GMPq::Rmpq_init();
5075             Math::GMPq::Rmpq_add_z($r, $x, $one);
5076             return $r;
5077             }
5078              
5079             Math_MPC: {
5080             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
5081             Math::MPC::Rmpc_add_ui($r, $x, 1, $ROUND);
5082             return $r;
5083             }
5084             }
5085              
5086             sub inc {
5087             my ($x) = @_;
5088             bless \__inc__($$x);
5089             }
5090              
5091             sub __dec__ {
5092             my ($x) = @_;
5093             goto(ref($x) =~ tr/:/_/rs);
5094              
5095             Math_GMPz: {
5096             my $r = Math::GMPz::Rmpz_init_set($x);
5097             Math::GMPz::Rmpz_sub_ui($r, $r, 1);
5098             return $r;
5099             }
5100              
5101             Math_MPFR: {
5102             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5103             Math::MPFR::Rmpfr_sub_ui($r, $x, 1, $ROUND);
5104             return $r;
5105             }
5106              
5107             Math_GMPq: {
5108             state $mone = Math::GMPz::Rmpz_init_set_si_nobless(-1);
5109             my $r = Math::GMPq::Rmpq_init();
5110             Math::GMPq::Rmpq_add_z($r, $x, $mone);
5111             return $r;
5112             }
5113              
5114             Math_MPC: {
5115             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
5116             Math::MPC::Rmpc_sub_ui($r, $x, 1, $ROUND);
5117             return $r;
5118             }
5119             }
5120              
5121             sub dec {
5122             my ($x) = @_;
5123             bless \__dec__($$x);
5124             }
5125              
5126             sub __mod__ {
5127             my ($x, $y) = @_;
5128             goto(join('__', ref($x), ref($y) || 'Scalar') =~ tr/:/_/rs);
5129              
5130             #
5131             ## GMPq
5132             #
5133             Math_GMPq__Math_GMPq: {
5134              
5135             Math::GMPq::Rmpq_sgn($y)
5136             || goto &_nan;
5137              
5138             my $quo = Math::GMPq::Rmpq_init();
5139             Math::GMPq::Rmpq_div($quo, $x, $y);
5140              
5141             # Floor
5142             Math::GMPq::Rmpq_integer_p($quo) || do {
5143             my $z = Math::GMPz::Rmpz_init();
5144             Math::GMPz::Rmpz_set_q($z, $quo);
5145             Math::GMPz::Rmpz_sub_ui($z, $z, 1) if Math::GMPq::Rmpq_sgn($quo) < 0;
5146             Math::GMPq::Rmpq_set_z($quo, $z);
5147             };
5148              
5149             Math::GMPq::Rmpq_mul($quo, $quo, $y);
5150             Math::GMPq::Rmpq_sub($quo, $x, $quo);
5151              
5152             return $quo;
5153             }
5154              
5155             Math_GMPq__Math_GMPz: {
5156              
5157             Math::GMPz::Rmpz_sgn($y)
5158             || goto &_nan;
5159              
5160             my $quo = Math::GMPq::Rmpq_init();
5161             Math::GMPq::Rmpq_div_z($quo, $x, $y);
5162              
5163             # Floor
5164             Math::GMPq::Rmpq_integer_p($quo) || do {
5165             my $z = Math::GMPz::Rmpz_init();
5166             Math::GMPz::Rmpz_set_q($z, $quo);
5167             Math::GMPz::Rmpz_sub_ui($z, $z, 1) if Math::GMPq::Rmpq_sgn($quo) < 0;
5168             Math::GMPq::Rmpq_set_z($quo, $z);
5169             };
5170              
5171             Math::GMPq::Rmpq_mul_z($quo, $quo, $y);
5172             Math::GMPq::Rmpq_sub($quo, $x, $quo);
5173              
5174             return $quo;
5175             }
5176              
5177             Math_GMPq__Math_MPFR: {
5178             $x = _mpq2mpfr($x);
5179             goto Math_MPFR__Math_MPFR;
5180             }
5181              
5182             Math_GMPq__Math_MPC: {
5183             $x = _mpq2mpc($x);
5184             goto Math_MPC__Math_MPC;
5185             }
5186              
5187             #
5188             ## GMPz
5189             #
5190             Math_GMPz__Math_GMPz: {
5191              
5192             my $sgn_y = Math::GMPz::Rmpz_sgn($y)
5193             || goto &_nan;
5194              
5195             my $r = Math::GMPz::Rmpz_init();
5196             Math::GMPz::Rmpz_mod($r, $x, $y);
5197              
5198             if (!Math::GMPz::Rmpz_sgn($r)) {
5199             ## ok
5200             }
5201             elsif ($sgn_y < 0) {
5202             Math::GMPz::Rmpz_add($r, $r, $y);
5203             }
5204              
5205             return $r;
5206             }
5207              
5208             Math_GMPz__Scalar: {
5209             my $r = Math::GMPz::Rmpz_init();
5210             Math::GMPz::Rmpz_mod_ui($r, $x, $y);
5211             return $r;
5212             }
5213              
5214             Math_GMPz__Math_GMPq: {
5215             $x = _mpz2mpq($x);
5216             goto Math_GMPq__Math_GMPq;
5217             }
5218              
5219             Math_GMPz__Math_MPFR: {
5220             $x = _mpz2mpfr($x);
5221             goto Math_MPFR__Math_MPFR;
5222             }
5223              
5224             Math_GMPz__Math_MPC: {
5225             $x = _mpz2mpc($x);
5226             goto Math_MPC__Math_MPC;
5227             }
5228              
5229             #
5230             ## MPFR
5231             #
5232             Math_MPFR__Math_MPFR: {
5233             my $quo = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5234             Math::MPFR::Rmpfr_div($quo, $x, $y, $ROUND);
5235             Math::MPFR::Rmpfr_floor($quo, $quo);
5236             Math::MPFR::Rmpfr_mul($quo, $quo, $y, $ROUND);
5237             Math::MPFR::Rmpfr_sub($quo, $x, $quo, $ROUND);
5238             return $quo;
5239             }
5240              
5241             Math_MPFR__Scalar: {
5242             my $quo = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5243             Math::MPFR::Rmpfr_div_ui($quo, $x, $y, $ROUND);
5244             Math::MPFR::Rmpfr_floor($quo, $quo);
5245             Math::MPFR::Rmpfr_mul_ui($quo, $quo, $y, $ROUND);
5246             Math::MPFR::Rmpfr_sub($quo, $x, $quo, $ROUND);
5247             return $quo;
5248             }
5249              
5250             Math_MPFR__Math_GMPq: {
5251             my $quo = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5252             Math::MPFR::Rmpfr_div_q($quo, $x, $y, $ROUND);
5253             Math::MPFR::Rmpfr_floor($quo, $quo);
5254             Math::MPFR::Rmpfr_mul_q($quo, $quo, $y, $ROUND);
5255             Math::MPFR::Rmpfr_sub($quo, $x, $quo, $ROUND);
5256             return $quo;
5257             }
5258              
5259             Math_MPFR__Math_GMPz: {
5260             my $quo = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5261             Math::MPFR::Rmpfr_div_z($quo, $x, $y, $ROUND);
5262             Math::MPFR::Rmpfr_floor($quo, $quo);
5263             Math::MPFR::Rmpfr_mul_z($quo, $quo, $y, $ROUND);
5264             Math::MPFR::Rmpfr_sub($quo, $x, $quo, $ROUND);
5265             return $quo;
5266             }
5267              
5268             Math_MPFR__Math_MPC: {
5269             $x = _mpfr2mpc($x);
5270             goto Math_MPC__Math_MPC;
5271             }
5272              
5273             #
5274             ## MPC
5275             #
5276             Math_MPC__Math_MPC: {
5277             my $quo = Math::MPC::Rmpc_init2(CORE::int($PREC));
5278             Math::MPC::Rmpc_div($quo, $x, $y, $ROUND);
5279              
5280             my $real = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5281             my $imag = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5282              
5283             Math::MPC::RMPC_RE($real, $quo);
5284             Math::MPC::RMPC_IM($imag, $quo);
5285              
5286             Math::MPFR::Rmpfr_floor($real, $real);
5287             Math::MPFR::Rmpfr_floor($imag, $imag);
5288              
5289             Math::MPC::Rmpc_set_fr_fr($quo, $real, $imag, $ROUND);
5290              
5291             Math::MPC::Rmpc_mul($quo, $quo, $y, $ROUND);
5292             Math::MPC::Rmpc_sub($quo, $x, $quo, $ROUND);
5293              
5294             return $quo;
5295             }
5296              
5297             Math_MPC__Scalar: {
5298             my $quo = Math::MPC::Rmpc_init2(CORE::int($PREC));
5299             Math::MPC::Rmpc_div_ui($quo, $x, $y, $ROUND);
5300              
5301             my $real = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5302             my $imag = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
5303              
5304             Math::MPC::RMPC_RE($real, $quo);
5305             Math::MPC::RMPC_IM($imag, $quo);
5306              
5307             Math::MPFR::Rmpfr_floor($real, $real);
5308             Math::MPFR::Rmpfr_floor($imag, $imag);
5309              
5310             Math::MPC::Rmpc_set_fr_fr($quo, $real, $imag, $ROUND);
5311              
5312             Math::MPC::Rmpc_mul_ui($quo, $quo, $y, $ROUND);
5313             Math::MPC::Rmpc_sub($quo, $x, $quo, $ROUND);
5314              
5315             return $quo;
5316             }
5317              
5318             Math_MPC__Math_MPFR: {
5319             $y = _mpfr2mpc($y);
5320             goto Math_MPC__Math_MPC;
5321             }
5322              
5323             Math_MPC__Math_GMPz: {
5324             $y = _mpz2mpc($y);
5325             goto Math_MPC__Math_MPC;
5326             }
5327              
5328             Math_MPC__Math_GMPq: {
5329             $y = _mpq2mpc($y);
5330             goto Math_MPC__Math_MPC;
5331             }
5332             }
5333              
5334             sub mod {
5335             my ($x, $y) = @_;
5336             _valid(\$y);
5337             bless \__mod__($$x, $$y);
5338             }
5339              
5340             sub polymod {
5341             my ($x, @m) = @_;
5342              
5343             _valid(map { \$_ } @m);
5344              
5345             $x = $$x;
5346             @m = map { $$_ } @m;
5347              
5348             my @r;
5349             foreach my $m (@m) {
5350             my $mod = __mod__($x, $m);
5351              
5352             $x = __sub__($x, $mod);
5353             $x = __div__($x, $m);
5354              
5355             push @r, $mod;
5356             }
5357              
5358             push @r, $x;
5359             map { bless \$_ } @r;
5360             }
5361              
5362             sub imod {
5363             my ($x, $y) = @_;
5364              
5365             _valid(\$y);
5366              
5367             $x = _any2mpz($$x) // (goto &nan);
5368             $y = _any2mpz($$y) // (goto &nan);
5369              
5370             my $sign_y = Math::GMPz::Rmpz_sgn($y)
5371             || goto &nan;
5372              
5373             my $r = Math::GMPz::Rmpz_init();
5374             Math::GMPz::Rmpz_mod($r, $x, $y);
5375              
5376             if (!Math::GMPz::Rmpz_sgn($r)) {
5377             ## OK
5378             }
5379             elsif ($sign_y < 0) {
5380             Math::GMPz::Rmpz_add($r, $r, $y);
5381             }
5382              
5383             bless \$r;
5384             }
5385              
5386             sub modpow {
5387             my ($x, $y, $z) = @_;
5388              
5389             _valid(\$y, \$z);
5390              
5391             $x = _any2mpz($$x) // (goto &nan);
5392             $y = _any2mpz($$y) // (goto &nan);
5393             $z = _any2mpz($$z) // (goto &nan);
5394              
5395             Math::GMPz::Rmpz_sgn($z) || goto &nan;
5396              
5397             if (Math::GMPz::Rmpz_sgn($y) < 0) {
5398             my $t = Math::GMPz::Rmpz_init();
5399             Math::GMPz::Rmpz_gcd($t, $x, $z);
5400             Math::GMPz::Rmpz_cmp_ui($t, 1) == 0 or goto &nan;
5401             }
5402              
5403             my $r = Math::GMPz::Rmpz_init();
5404             Math::GMPz::Rmpz_powm($r, $x, $y, $z);
5405             bless \$r;
5406             }
5407              
5408             *expmod = \&modpow;
5409             *powmod = \&modpow;
5410              
5411             sub modinv {
5412             my ($x, $y) = @_;
5413              
5414             _valid(\$y);
5415              
5416             $x = _any2mpz($$x) // (goto &nan);
5417             $y = _any2mpz($$y) // (goto &nan);
5418              
5419             my $r = Math::GMPz::Rmpz_init();
5420             Math::GMPz::Rmpz_invert($r, $x, $y) || (goto &nan);
5421             bless \$r;
5422             }
5423              
5424             *invmod = \&modinv;
5425              
5426             sub divmod {
5427             my ($x, $y) = @_;
5428              
5429             _valid(\$y);
5430              
5431             $x = _any2mpz($$x) // return (nan(), nan());
5432             $y = _any2mpz($$y) // return (nan(), nan());
5433              
5434             Math::GMPz::Rmpz_sgn($y)
5435             || return (nan(), nan());
5436              
5437             my $r = Math::GMPz::Rmpz_init();
5438             my $s = Math::GMPz::Rmpz_init();
5439              
5440             Math::GMPz::Rmpz_divmod($r, $s, $x, $y);
5441             ((bless \$r), (bless \$s));
5442             }
5443              
5444             sub and {
5445             my ($x, $y) = @_;
5446              
5447             _valid(\$y);
5448              
5449             $x = _any2mpz($$x) // (goto &nan);
5450             $y = _any2mpz($$y) // (goto &nan);
5451              
5452             my $r = Math::GMPz::Rmpz_init();
5453             Math::GMPz::Rmpz_and($r, $x, $y);
5454             bless \$r;
5455             }
5456              
5457             sub or {
5458             my ($x, $y) = @_;
5459              
5460             _valid(\$y);
5461              
5462             $x = _any2mpz($$x) // (goto &nan);
5463             $y = _any2mpz($$y) // (goto &nan);
5464              
5465             my $r = Math::GMPz::Rmpz_init();
5466             Math::GMPz::Rmpz_ior($r, $x, $y);
5467             bless \$r;
5468             }
5469              
5470             sub xor {
5471             my ($x, $y) = @_;
5472              
5473             _valid(\$y);
5474              
5475             $x = _any2mpz($$x) // (goto &nan);
5476             $y = _any2mpz($$y) // (goto &nan);
5477              
5478             my $r = Math::GMPz::Rmpz_init();
5479             Math::GMPz::Rmpz_xor($r, $x, $y);
5480             bless \$r;
5481             }
5482              
5483             sub not {
5484             my ($x) = @_;
5485              
5486             $x = _any2mpz($$x) // (goto &nan);
5487              
5488             my $r = Math::GMPz::Rmpz_init();
5489             Math::GMPz::Rmpz_com($r, $x);
5490             bless \$r;
5491             }
5492              
5493             sub ramanujan_tau {
5494             __PACKAGE__->_set_str('int', Math::Prime::Util::GMP::ramanujan_tau(&_big2uistr // (goto &nan)));
5495             }
5496              
5497             sub factorial {
5498             my ($x) = @_;
5499             my $ui = _any2ui($$x) // (goto &nan);
5500             my $z = Math::GMPz::Rmpz_init();
5501             Math::GMPz::Rmpz_fac_ui($z, $ui);
5502             bless \$z;
5503             }
5504              
5505             *fac = \&factorial;
5506              
5507             sub double_factorial {
5508             my ($x) = @_;
5509             my $ui = _any2ui($$x) // (goto &nan);
5510             my $z = Math::GMPz::Rmpz_init();
5511             Math::GMPz::Rmpz_2fac_ui($z, $ui);
5512             bless \$z;
5513             }
5514              
5515             *dfac = \&double_factorial;
5516             *dfactorial = \&double_factorial;
5517              
5518             sub mfactorial {
5519             my ($x, $y) = @_;
5520             _valid(\$y);
5521             my $ui1 = _any2ui($$x) // (goto &nan);
5522             my $ui2 = _any2ui($$y) // (goto &nan);
5523             my $z = Math::GMPz::Rmpz_init();
5524             Math::GMPz::Rmpz_mfac_uiui($z, $ui1, $ui2);
5525             bless \$z;
5526             }
5527              
5528             *mfac = \&mfactorial;
5529              
5530             #
5531             ## falling_factorial(x, +y) = binomial(x, y) * y!
5532             ## falling_factorial(x, -y) = 1/falling_factorial(x + y, y)
5533             #
5534              
5535             sub falling_factorial {
5536             my ($x, $y) = @_;
5537             _valid(\$y);
5538              
5539             $x = _any2mpz($$x) // (goto &nan);
5540             $y = _any2si($$y) // (goto &nan);
5541              
5542             my $r = Math::GMPz::Rmpz_init_set($x);
5543              
5544             if ($y < 0) {
5545             Math::GMPz::Rmpz_add_ui($r, $r, CORE::abs($y));
5546             }
5547              
5548             Math::GMPz::Rmpz_fits_ulong_p($r)
5549             ? Math::GMPz::Rmpz_bin_uiui($r, Math::GMPz::Rmpz_get_ui($r), CORE::abs($y))
5550             : Math::GMPz::Rmpz_bin_ui($r, $r, CORE::abs($y));
5551              
5552             Math::GMPz::Rmpz_sgn($r) || do {
5553             $y < 0
5554             ? (goto &nan)
5555             : (goto &zero);
5556             };
5557              
5558             state $t = Math::GMPz::Rmpz_init_nobless();
5559             Math::GMPz::Rmpz_fac_ui($t, CORE::abs($y));
5560             Math::GMPz::Rmpz_mul($r, $r, $t);
5561              
5562             if ($y < 0) {
5563             my $q = Math::GMPq::Rmpq_init();
5564             Math::GMPq::Rmpq_set_z($q, $r);
5565             Math::GMPq::Rmpq_inv($q, $q);
5566             return bless \$q;
5567             }
5568              
5569             bless \$r;
5570             }
5571              
5572             #
5573             ## rising_factorial(x, +y) = binomial(x + y - 1, y) * y!
5574             ## rising_factorial(x, -y) = 1/rising_factorial(x - y, y)
5575             #
5576              
5577             sub rising_factorial {
5578             my ($x, $y) = @_;
5579             _valid(\$y);
5580              
5581             $x = _any2mpz($$x) // (goto &nan);
5582             $y = _any2si($$y) // (goto &nan);
5583              
5584             my $r = Math::GMPz::Rmpz_init_set($x);
5585             Math::GMPz::Rmpz_add_ui($r, $r, CORE::abs($y));
5586             Math::GMPz::Rmpz_sub_ui($r, $r, 1);
5587              
5588             if ($y < 0) {
5589             Math::GMPz::Rmpz_sub_ui($r, $r, CORE::abs($y));
5590             }
5591              
5592             Math::GMPz::Rmpz_fits_ulong_p($r)
5593             ? Math::GMPz::Rmpz_bin_uiui($r, Math::GMPz::Rmpz_get_ui($r), CORE::abs($y))
5594             : Math::GMPz::Rmpz_bin_ui($r, $r, CORE::abs($y));
5595              
5596             Math::GMPz::Rmpz_sgn($r) || do {
5597             $y < 0
5598             ? (goto &nan)
5599             : (goto &zero);
5600             };
5601              
5602             state $t = Math::GMPz::Rmpz_init_nobless();
5603             Math::GMPz::Rmpz_fac_ui($t, CORE::abs($y));
5604             Math::GMPz::Rmpz_mul($r, $r, $t);
5605              
5606             if ($y < 0) {
5607             my $q = Math::GMPq::Rmpq_init();
5608             Math::GMPq::Rmpq_set_z($q, $r);
5609             Math::GMPq::Rmpq_inv($q, $q);
5610             return bless \$q;
5611             }
5612              
5613             bless \$r;
5614             }
5615              
5616             sub primorial {
5617             my ($x) = @_;
5618             my $ui = _any2ui($$x) // (goto &nan);
5619             my $z = Math::GMPz::Rmpz_init();
5620             Math::GMPz::Rmpz_primorial_ui($z, $ui);
5621             bless \$z;
5622             }
5623              
5624             sub pn_primorial {
5625             my ($x) = @_;
5626             __PACKAGE__->_set_str('int', Math::Prime::Util::GMP::pn_primorial(_any2ui($$x) // (goto &nan)));
5627             }
5628              
5629             sub lucas {
5630             my ($x) = @_;
5631             my $ui = _any2ui($$x) // (goto &nan);
5632             my $z = Math::GMPz::Rmpz_init();
5633             Math::GMPz::Rmpz_lucnum_ui($z, $ui);
5634             bless \$z;
5635             }
5636              
5637             sub fibonacci {
5638             my ($x) = @_;
5639             my $ui = _any2ui($$x) // (goto &nan);
5640             my $z = Math::GMPz::Rmpz_init();
5641             Math::GMPz::Rmpz_fib_ui($z, $ui);
5642             bless \$z;
5643             }
5644              
5645             *fib = \&fibonacci;
5646              
5647             sub stirling {
5648             my ($x, $y) = @_;
5649             _valid(\$y);
5650             __PACKAGE__->_set_str('int',
5651             Math::Prime::Util::GMP::stirling(_big2uistr($x) // (goto &nan), _big2uistr($y) // (goto &nan)));
5652             }
5653              
5654             sub stirling2 {
5655             my ($x, $y) = @_;
5656             _valid(\$y);
5657             __PACKAGE__->_set_str(
5658             'int',
5659             Math::Prime::Util::GMP::stirling(
5660             _big2uistr($x) // (goto &nan), _big2uistr($y) // (goto &nan), 2
5661             )
5662             );
5663             }
5664              
5665             sub stirling3 {
5666             my ($x, $y) = @_;
5667             _valid(\$y);
5668             __PACKAGE__->_set_str(
5669             'int',
5670             Math::Prime::Util::GMP::stirling(
5671             _big2uistr($x) // (goto &nan), _big2uistr($y) // (goto &nan), 3
5672             )
5673             );
5674             }
5675              
5676             sub bell {
5677             my ($x) = @_;
5678             my $n = _any2ui($$x) // goto &nan;
5679             __PACKAGE__->_set_str('int',
5680             Math::Prime::Util::GMP::vecsum(map { Math::Prime::Util::GMP::stirling($n, $_, 2) } 0 .. $n));
5681             }
5682              
5683             sub binomial {
5684             my ($x, $y) = @_;
5685             _valid(\$y);
5686              
5687             $x = _any2mpz($$x) // (goto &nan);
5688             $y = _any2si($$y) // (goto &nan);
5689              
5690             my $r = Math::GMPz::Rmpz_init();
5691              
5692             if ($y >= 0 and Math::GMPz::Rmpz_fits_ulong_p($x)) {
5693             Math::GMPz::Rmpz_bin_uiui($r, Math::GMPz::Rmpz_get_ui($x), $y);
5694             }
5695             else {
5696             $y < 0
5697             ? Math::GMPz::Rmpz_bin_si($r, $x, $y)
5698             : Math::GMPz::Rmpz_bin_ui($r, $x, $y);
5699             }
5700              
5701             bless \$r;
5702             }
5703              
5704             *nok = \&binomial;
5705              
5706             sub moebius {
5707             my $mob = Math::Prime::Util::GMP::moebius(&_big2istr // goto &nan);
5708             if (!$mob) {
5709             ZERO;
5710             }
5711             elsif ($mob == 1) {
5712             ONE;
5713             }
5714             else {
5715             MONE;
5716             }
5717             }
5718              
5719             *mobius = \&moebius;
5720              
5721             # Currently, this method is very slow for wide ranges.
5722             # It's included with the hope that it will become faster in the future.
5723             sub prime_count {
5724             my ($x, $y) = @_;
5725             my $n = defined($y)
5726             ? do {
5727             _valid(\$y);
5728             Math::Prime::Util::GMP::prime_count(_big2istr($x) // (goto &nan), _big2istr($y) // (goto &nan));
5729             }
5730             : Math::Prime::Util::GMP::prime_count(2, _big2istr($x) // (goto &nan));
5731             $n <= ULONG_MAX ? __PACKAGE__->_set_uint($n) : __PACKAGE__->_set_str('int', $n);
5732             }
5733              
5734             sub square_free_count {
5735             my ($from, $to) = @_;
5736              
5737             if (defined($to)) {
5738             _valid(\$to);
5739             return $to->square_free_count->sub($from->dec->square_free_count);
5740             }
5741              
5742             (my $n = __numify__($$from)) <= 0 && return ZERO;
5743              
5744             # Optimization for native integers
5745             if ($n <= ULONG_MAX) {
5746              
5747             $n = CORE::int($n);
5748             my $s = CORE::int(CORE::sqrt($n));
5749              
5750             # Using moebius(1, sqrt(n)) for values of n <= 2^40
5751             if ($n <= (1 << 40)) {
5752              
5753             my ($count, $k) = (0, 0);
5754              
5755             foreach my $m (Math::Prime::Util::GMP::moebius(1, $s)) {
5756             ++$k;
5757             if ($m) {
5758             $count += $m * CORE::int($n / ($k * $k));
5759             }
5760             }
5761              
5762             return __PACKAGE__->_set_uint($count);
5763             }
5764              
5765             # Linear counting up to sqrt(n)
5766             my ($count, $m) = 0;
5767             foreach my $k (1 .. $s) {
5768             if ($m = Math::Prime::Util::GMP::moebius($k)) {
5769             $count += $m * CORE::int($n / ($k * $k));
5770             }
5771             }
5772             return __PACKAGE__->_set_uint($count);
5773             }
5774              
5775             # Implementation for large values of n
5776             my $c = Math::GMPz::Rmpz_init_set_ui(0);
5777             my $t = Math::GMPz::Rmpz_init();
5778             my $z = _any2mpz($$from) // return ZERO;
5779              
5780             my $s = Math::GMPz::Rmpz_init();
5781             Math::GMPz::Rmpz_sqrt($s, $z);
5782              
5783             for (my $k = Math::GMPz::Rmpz_init_set_ui(1) ; Math::GMPz::Rmpz_cmp($k, $s) <= 0 ; Math::GMPz::Rmpz_add_ui($k, $k, 1))
5784             {
5785             my $m = Math::Prime::Util::GMP::moebius(Math::GMPz::Rmpz_get_str($k, 10));
5786              
5787             if ($m) {
5788             Math::GMPz::Rmpz_set($t, $z);
5789             Math::GMPz::Rmpz_tdiv_q($t, $t, $k);
5790             Math::GMPz::Rmpz_tdiv_q($t, $t, $k);
5791             ($m == -1)
5792             ? Math::GMPz::Rmpz_sub($c, $c, $t)
5793             : Math::GMPz::Rmpz_add($c, $c, $t);
5794             }
5795             }
5796              
5797             bless \$c;
5798             }
5799              
5800             sub _Li_inverse {
5801             my ($x) = @_;
5802              
5803             # Function translated from:
5804             # https://github.com/kimwalisch/primecount
5805              
5806             my $logx = CORE::log($x);
5807             my $first = CORE::int($x * $logx);
5808             my $last = CORE::int($x * $logx * 2 + 2);
5809              
5810             state $mpfr = Math::MPFR::Rmpfr_init2_nobless(64);
5811              
5812             # Find Li^-1(x) using binary search
5813             while ($first < $last) {
5814             my $mid = $first + (($last - $first) >> 1);
5815              
5816             Math::MPFR::Rmpfr_set_d($mpfr, CORE::log($mid), $ROUND);
5817             Math::MPFR::Rmpfr_eint($mpfr, $mpfr, $ROUND);
5818              
5819             if (Math::MPFR::Rmpfr_get_d($mpfr, $ROUND) - 1.045163780117 < $x) {
5820             $first = $mid + 1;
5821             }
5822             else {
5823             $last = $mid;
5824             }
5825             }
5826              
5827             return $first;
5828             }
5829              
5830             sub nth_prime {
5831             my ($n) = @_;
5832              
5833             $n = _any2ui($$n) // goto &nan;
5834              
5835             if ($n == 0) {
5836             return ONE; # not a prime, but it's convenient...
5837             }
5838              
5839             if ($n > 100_000) {
5840              
5841             my $i = 2;
5842             my $count = 0;
5843             my $prev_count = 0;
5844              
5845             #my $approx = CORE::int($n * CORE::log($n) + $n * (CORE::log(CORE::log($n)) - 1));
5846             #my $up_approx = CORE::int($n * CORE::log($n) + $n * CORE::log(CORE::log($n)));
5847              
5848             my $li_inv_n = _Li_inverse($n);
5849             my $li_inv_sn = _Li_inverse(CORE::int(CORE::sqrt($n)));
5850              
5851             ## Formula due to Dana Jacobsen:
5852             ## Nth prime ≈ Li^-1(n) + Li^-1(sqrt(n)) / 4
5853             my $approx = CORE::int($li_inv_n + $li_inv_sn / 4);
5854             my $up_approx = CORE::int($li_inv_n + $li_inv_sn); # conjecture
5855              
5856             state $checkpoints = [[1000000000000, 37607912018],
5857             [100000000000, 4118054813],
5858             [50000000000, 2119654578],
5859             [45000000000, 1916268743],
5860             [40000000000, 1711955433],
5861             [35000000000, 1506589876],
5862             [30000000000, 1300005926],
5863             [25000000000, 1091987405],
5864             [22000000000, 966358351],
5865             [21000000000, 924324489],
5866             [20000000000, 882206716],
5867             [19000000000, 840000027],
5868             [18000000000, 797703398],
5869             [17000000000, 755305935],
5870             [16000000000, 712799821],
5871             [15000000000, 670180516],
5872             [14000000000, 627440336],
5873             [13000000000, 584570200],
5874             [12000000000, 541555851],
5875             [11000000000, 498388617],
5876             [10000000000, 455052511],
5877             [9900000000, 450708777],
5878             [9700000000, 442014876],
5879             [9500000000, 433311792],
5880             [9300000000, 424603409],
5881             [9000000000, 411523195],
5882             [8700000000, 398425675],
5883             [8500000000, 389682427],
5884             [8300000000, 380930729],
5885             [8000000000, 367783654],
5886             [7500000000, 345826612],
5887             [7300000000, 337024801],
5888             [7000000000, 323804352],
5889             [6700000000, 310558733],
5890             [6500000000, 301711468],
5891             [6400000000, 297285198],
5892             [6300000000, 292856421],
5893             [6000000000, 279545368],
5894             [5700000000, 266206294],
5895             [5500000000, 257294520],
5896             [5300000000, 248370960],
5897             [5200000000, 243902342],
5898             [5000000000, 234954223],
5899             [4900000000, 230475545],
5900             [4700000000, 221504167],
5901             [4500000000, 212514323],
5902             [4300000000, 203507248],
5903             [4200000000, 198996103],
5904             [4000000000, 189961812],
5905             [3900000000, 185436625],
5906             [3800000000, 180906194],
5907             [3700000000, 176369517],
5908             [3500000000, 167279333],
5909             [3400000000, 162725196],
5910             [3300000000, 158165829],
5911             [3100000000, 149028641],
5912             [3000000000, 144449537],
5913             [2900000000, 139864011],
5914             [2800000000, 135270258],
5915             [2700000000, 130670192],
5916             [2600000000, 126062167],
5917             [2500000000, 121443371],
5918             [2400000000, 116818447],
5919             [2200000000, 107540122],
5920             [2000000000, 98222287],
5921             [1900000000, 93547928],
5922             [1800000000, 88862422],
5923             [1700000000, 84163019],
5924             [1600000000, 79451833],
5925             [1500000000, 74726528],
5926             [1400000000, 69985473],
5927             [1300000000, 65228333],
5928             [1200000000, 60454705],
5929             [1100000000, 55662470],
5930             [1000000000, 50847534],
5931             [950000000, 48431471],
5932             [900000000, 46009215],
5933             [850000000, 43581966],
5934             [800000000, 41146179],
5935             [750000000, 38703181],
5936             [700000000, 36252931],
5937             [650000000, 33793395],
5938             [600000000, 31324703],
5939             [550000000, 28845356],
5940             [500000000, 26355867],
5941             [450000000, 23853038],
5942             [400000000, 21336326],
5943             [370000000, 19818405],
5944             [360000000, 19311288],
5945             [350000000, 18803526],
5946             [330000000, 17785475],
5947             [300000000, 16252325],
5948             [290000000, 15739663],
5949             [270000000, 14711384],
5950             [250000000, 13679318],
5951             [230000000, 12642573],
5952             [200000000, 11078937],
5953             [190000000, 10555473],
5954             [170000000, 9503083],
5955             [160000000, 8974458],
5956             [150000000, 8444396],
5957             [140000000, 7912199],
5958             [120000000, 6841648],
5959             [100000000, 5761455],
5960             [95000000, 5489749],
5961             [90000000, 5216954],
5962             [85000000, 4943731],
5963             [80000000, 4669382],
5964             [75000000, 4394304],
5965             [70000000, 4118064],
5966             [65000000, 3840554],
5967             [60000000, 3562115],
5968             [55000000, 3282200],
5969             [50000000, 3001134],
5970             [45000000, 2718160],
5971             [40000000, 2433654],
5972             [35000000, 2146775],
5973             [30000000, 1857859],
5974             [25000000, 1565927],
5975             [20000000, 1270607],
5976             [19000000, 1211050],
5977             [18000000, 1151367],
5978             [17000000, 1091314],
5979             [16000000, 1031130],
5980             [15000000, 970704],
5981             [14000000, 910077],
5982             [13000000, 849252],
5983             [12000000, 788060],
5984             [11000000, 726517],
5985             [10000000, 664579],
5986             [9000000, 602489],
5987             [8000000, 539777],
5988             [7000000, 476648],
5989             [6000000, 412849],
5990             [5000000, 348513],
5991             [4000000, 283146],
5992             [3000000, 216816],
5993             [2000000, 148933],
5994             [1000000, 78498],
5995             ];
5996              
5997             {
5998             state $end = $#{$checkpoints};
5999              
6000             my $left = 0;
6001             my $right = $end;
6002              
6003             my ($middle, $item, $cmp);
6004              
6005             while (1) {
6006             $middle = (($right + $left) >> 1);
6007             $item = $checkpoints->[$middle][0];
6008             $cmp = ($approx <=> $item) || last;
6009              
6010             if ($cmp < 0) {
6011             $left = $middle + 1;
6012             if ($left > $right) {
6013             ++$middle;
6014             last;
6015             }
6016             }
6017             else {
6018             $right = $middle - 1;
6019             $left > $right && last;
6020             }
6021             }
6022              
6023             my $point = $checkpoints->[$middle];
6024              
6025             $count = $point->[1];
6026             $i = $point->[0];
6027             $prev_count = $count;
6028             }
6029              
6030             my $count_approx = $up_approx - $i;
6031             my $step = $count_approx < 1e6 ? $count_approx : $n > 1e8 ? 1e7 : 1e6;
6032              
6033             for (; ; $i += $step) {
6034             my @primes = Math::Prime::Util::GMP::sieve_primes($i, $i + $step);
6035             $count += @primes;
6036              
6037             if ($count >= $n) {
6038             my $p = $primes[$n - $prev_count - 1];
6039             return (
6040             $p <= ULONG_MAX
6041             ? __PACKAGE__->_set_uint($p)
6042             : __PACKAGE__->_set_str('int', $p)
6043             );
6044             }
6045              
6046             $prev_count = $count;
6047             }
6048             }
6049              
6050             state $table = [Math::Prime::Util::GMP::sieve_primes(2, 1_299_709)]; # primes up to prime(100_000)
6051             __PACKAGE__->_set_uint($table->[$n - 1]);
6052             }
6053              
6054             *prime = \&nth_prime;
6055              
6056             sub legendre {
6057             my ($x, $y) = @_;
6058             _valid(\$y);
6059              
6060             my $sym = Math::GMPz::Rmpz_legendre(_any2mpz($$x) // (goto &nan), _any2mpz($$y) // (goto &nan));
6061              
6062             if (!$sym) {
6063             ZERO;
6064             }
6065             elsif ($sym == 1) {
6066             ONE;
6067             }
6068             else {
6069             MONE;
6070             }
6071             }
6072              
6073             sub jacobi {
6074             my ($x, $y) = @_;
6075             _valid(\$y);
6076              
6077             my $sym = Math::GMPz::Rmpz_jacobi(_any2mpz($$x) // (goto &nan), _any2mpz($$y) // (goto &nan));
6078              
6079             if (!$sym) {
6080             ZERO;
6081             }
6082             elsif ($sym == 1) {
6083             ONE;
6084             }
6085             else {
6086             MONE;
6087             }
6088             }
6089              
6090             sub kronecker {
6091             my ($x, $y) = @_;
6092             _valid(\$y);
6093              
6094             my $sym = Math::GMPz::Rmpz_kronecker(_any2mpz($$x) // (goto &nan), _any2mpz($$y) // (goto &nan));
6095              
6096             if (!$sym) {
6097             ZERO;
6098             }
6099             elsif ($sym == 1) {
6100             ONE;
6101             }
6102             else {
6103             MONE;
6104             }
6105             }
6106              
6107             sub is_coprime {
6108             my ($x, $y) = @_;
6109              
6110             _valid(\$y);
6111              
6112             (__is_int__($$x) && __is_int__($$y))
6113             || return Sidef::Types::Bool::Bool::FALSE;
6114              
6115             $x = _any2mpz($$x) // return Sidef::Types::Bool::Bool::FALSE;
6116             $y = _any2mpz($$y) // return Sidef::Types::Bool::Bool::FALSE;
6117              
6118             state $t = Math::GMPz::Rmpz_init_nobless();
6119             Math::GMPz::Rmpz_gcd($t, $x, $y);
6120              
6121             (Math::GMPz::Rmpz_cmp_ui($t, 1) == 0)
6122             ? Sidef::Types::Bool::Bool::TRUE
6123             : Sidef::Types::Bool::Bool::FALSE;
6124             }
6125              
6126             sub gcd {
6127             my ($x, $y) = @_;
6128              
6129             _valid(\$y);
6130              
6131             $x = _any2mpz($$x) // goto &nan;
6132             $y = _any2mpz($$y) // goto &nan;
6133              
6134             my $r = Math::GMPz::Rmpz_init();
6135             Math::GMPz::Rmpz_gcd($r, $x, $y);
6136             bless \$r;
6137             }
6138              
6139             sub lcm {
6140             my ($x, $y) = @_;
6141              
6142             _valid(\$y);
6143              
6144             $x = _any2mpz($$x) // goto &nan;
6145             $y = _any2mpz($$y) // goto &nan;
6146              
6147             my $r = Math::GMPz::Rmpz_init();
6148             Math::GMPz::Rmpz_lcm($r, $x, $y);
6149             bless \$r;
6150             }
6151              
6152             sub valuation {
6153             my ($x, $y) = @_;
6154              
6155             _valid(\$y);
6156              
6157             $x = _any2mpz($$x) // goto &nan;
6158             $y = _any2mpz($$y) // goto &nan;
6159              
6160             Math::GMPz::Rmpz_sgn($y) || return ZERO;
6161             Math::GMPz::Rmpz_cmpabs_ui($y, 1) || return ZERO;
6162              
6163             state $t = Math::GMPz::Rmpz_init_nobless();
6164             __PACKAGE__->_set_uint(scalar Math::GMPz::Rmpz_remove($t, $x, $y));
6165             }
6166              
6167             sub remove {
6168             my ($x, $y) = @_;
6169              
6170             _valid(\$y);
6171              
6172             $x = _any2mpz($$x) // goto &nan;
6173             $y = _any2mpz($$y) // goto &nan;
6174              
6175             Math::GMPz::Rmpz_sgn($y) || return $_[0];
6176             Math::GMPz::Rmpz_cmpabs_ui($y, 1) || return $_[0];
6177              
6178             my $r = Math::GMPz::Rmpz_init();
6179             Math::GMPz::Rmpz_remove($r, $x, $y);
6180             bless \$r;
6181             }
6182              
6183             *remdiv = \&remove;
6184              
6185             sub make_coprime {
6186             my ($x, $y) = @_;
6187              
6188             _valid(\$y);
6189             my $r = Math::GMPz::Rmpz_init_set(_any2mpz($$x) // goto &nan);
6190              
6191             my %factors;
6192             @factors{Math::Prime::Util::GMP::factor(_big2uistr($y) // goto &nan)} = ();
6193              
6194             my $t = Math::GMPz::Rmpz_init();
6195             foreach my $f (keys %factors) {
6196             if ($f <= ULONG_MAX) {
6197             Math::GMPz::Rmpz_divisible_ui_p($r, $f)
6198             ? Math::GMPz::Rmpz_set_ui($t, $f)
6199             : next;
6200             }
6201             else {
6202             Math::GMPz::Rmpz_set_str($t, $f);
6203             }
6204             Math::GMPz::Rmpz_remove($r, $r, $t);
6205             }
6206              
6207             bless \$r;
6208             }
6209              
6210             sub random_prime {
6211             my ($from, $to) = @_;
6212              
6213             my $prime;
6214             if (defined($to)) {
6215             _valid(\$to);
6216             $prime = Math::Prime::Util::GMP::random_prime(_big2uistr($from) // (goto &nan), _big2uistr($to) // (goto &nan));
6217             }
6218             else {
6219             $prime = Math::Prime::Util::GMP::random_prime(2, _big2uistr($from) // (goto &nan));
6220             }
6221              
6222             __PACKAGE__->_set_str('int', $prime // goto &nan);
6223             }
6224              
6225             sub random_nbit_prime {
6226             my ($x) = @_;
6227             my $n = _any2ui($$x) // goto &nan;
6228             $n <= 1 && goto &nan;
6229             __PACKAGE__->_set_str('int', Math::Prime::Util::GMP::random_nbit_prime($n));
6230             }
6231              
6232             sub random_ndigit_prime {
6233             my ($x) = @_;
6234             my $n = _any2ui($$x) || goto &nan;
6235             __PACKAGE__->_set_str('int', Math::Prime::Util::GMP::random_ndigit_prime($n));
6236             }
6237              
6238             sub is_semiprime {
6239             my ($x) = @_;
6240             __is_int__($$x)
6241             && Math::Prime::Util::GMP::is_semiprime(&_big2uistr // return Sidef::Types::Bool::Bool::FALSE)
6242             ? Sidef::Types::Bool::Bool::TRUE
6243             : Sidef::Types::Bool::Bool::FALSE;
6244             }
6245              
6246             sub is_prime {
6247             my ($x) = @_;
6248             __is_int__($$x)
6249             && Math::Prime::Util::GMP::is_prime(&_big2uistr // return Sidef::Types::Bool::Bool::FALSE)
6250             ? Sidef::Types::Bool::Bool::TRUE
6251             : Sidef::Types::Bool::Bool::FALSE;
6252             }
6253              
6254             sub is_prob_prime {
6255             my ($x, $k) = @_;
6256              
6257             my $z = $$x;
6258             if (defined($k)) {
6259             _valid(\$k);
6260             (__is_int__($z) and Math::GMPz::Rmpz_probab_prime_p(_any2mpz($z), CORE::abs(_any2si($$k) // 20)) > 0)
6261             ? Sidef::Types::Bool::Bool::TRUE
6262             : Sidef::Types::Bool::Bool::FALSE;
6263             }
6264             else {
6265             __is_int__($z)
6266             && Math::Prime::Util::GMP::is_prob_prime(_big2uistr($x) // return Sidef::Types::Bool::Bool::FALSE)
6267             ? Sidef::Types::Bool::Bool::TRUE
6268             : Sidef::Types::Bool::Bool::FALSE;
6269             }
6270             }
6271              
6272             sub is_prov_prime {
6273             my ($x) = @_;
6274             __is_int__($$x)
6275             && Math::Prime::Util::GMP::is_provable_prime(_big2uistr($x) // return Sidef::Types::Bool::Bool::FALSE)
6276             ? Sidef::Types::Bool::Bool::TRUE
6277             : Sidef::Types::Bool::Bool::FALSE;
6278             }
6279              
6280             sub is_mersenne_prime {
6281             my ($x) = @_;
6282             __is_int__($$x)
6283             && Math::Prime::Util::GMP::is_mersenne_prime(_big2uistr($x) // return Sidef::Types::Bool::Bool::FALSE)
6284             ? Sidef::Types::Bool::Bool::TRUE
6285             : Sidef::Types::Bool::Bool::FALSE;
6286             }
6287              
6288             sub primes {
6289             my ($x, $y) = @_;
6290              
6291             _valid(\$y) if defined($y);
6292              
6293             Sidef::Types::Array::Array->new(
6294             [
6295             map {
6296             $_ <= ULONG_MAX
6297             ? __PACKAGE__->_set_uint($_)
6298             : __PACKAGE__->_set_str('int', $_)
6299             }
6300              
6301             defined($y)
6302             ? Math::Prime::Util::GMP::sieve_primes((_big2uistr($x) // 0), (_big2uistr($y) // 0), 0)
6303             : Math::Prime::Util::GMP::sieve_primes(2, (_big2uistr($x) // 0), 0)
6304             ]
6305             );
6306             }
6307              
6308             sub prev_prime {
6309             my $p = Math::Prime::Util::GMP::prev_prime(&_big2uistr // goto &nan) || goto &nan;
6310             $p <= ULONG_MAX ? __PACKAGE__->_set_uint($p) : __PACKAGE__->_set_str('int', $p);
6311             }
6312              
6313             sub next_prime {
6314             my $p = Math::Prime::Util::GMP::next_prime(&_big2uistr // goto &nan) || goto &nan;
6315             $p <= ULONG_MAX ? __PACKAGE__->_set_uint($p) : __PACKAGE__->_set_str('int', $p);
6316             }
6317              
6318             sub znorder {
6319             my ($x, $y) = @_;
6320             _valid(\$y);
6321             my $z = Math::Prime::Util::GMP::znorder(_big2uistr($x) // (goto &nan), _big2uistr($y) // (goto &nan)) // goto &nan;
6322             $z <= ULONG_MAX ? __PACKAGE__->_set_uint($z) : __PACKAGE__->_set_str('int', $z);
6323             }
6324              
6325             sub znprimroot {
6326             my $z = Math::Prime::Util::GMP::znprimroot(&_big2uistr // (goto &nan)) // goto &nan;
6327             $z <= ULONG_MAX ? __PACKAGE__->_set_uint($z) : __PACKAGE__->_set_str('int', $z);
6328             }
6329              
6330             sub rad {
6331             my %f;
6332             @f{Math::Prime::Util::GMP::factor(&_big2uistr // goto &nan)} = ();
6333             my $r = Math::Prime::Util::GMP::vecprod(CORE::keys %f);
6334             $r <= ULONG_MAX ? __PACKAGE__->_set_uint($r) : __PACKAGE__->_set_str('int', $r);
6335             }
6336              
6337             sub factor {
6338             Sidef::Types::Array::Array->new(
6339             [
6340             map {
6341             $_ <= ULONG_MAX
6342             ? __PACKAGE__->_set_uint($_)
6343             : __PACKAGE__->_set_str('int', $_)
6344             }
6345              
6346             Math::Prime::Util::GMP::factor(&_big2uistr || return Sidef::Types::Array::Array->new())
6347             ]
6348             );
6349             }
6350              
6351             *factors = \&factor;
6352              
6353             sub factor_exp {
6354             my %count;
6355             foreach my $f (Math::Prime::Util::GMP::factor(&_big2uistr || return Sidef::Types::Array::Array->new())) {
6356             ++$count{$f};
6357             }
6358              
6359             my @pairs;
6360             foreach my $factor (sort { (CORE::length($a) <=> CORE::length($b)) || ($a cmp $b) } keys(%count)) {
6361             push @pairs,
6362             Sidef::Types::Array::Array->new(
6363             [
6364             (
6365             $factor <= ULONG_MAX
6366             ? __PACKAGE__->_set_uint($factor)
6367             : __PACKAGE__->_set_str('int', $factor)
6368             ),
6369             __PACKAGE__->_set_uint($count{$factor})
6370             ]
6371             );
6372             }
6373              
6374             Sidef::Types::Array::Array->new(\@pairs);
6375             }
6376              
6377             *factors_exp = \&factor_exp;
6378              
6379             sub divisors {
6380             my $n = &_big2uistr || return Sidef::Types::Array::Array->new();
6381              
6382             Sidef::Types::Array::Array->new(
6383             [
6384             map {
6385             $_ <= ULONG_MAX
6386             ? __PACKAGE__->_set_uint($_)
6387             : __PACKAGE__->_set_str('int', $_)
6388             } Math::Prime::Util::GMP::divisors($n)
6389             ]
6390             );
6391             }
6392              
6393             sub exp_mangoldt {
6394             my $n = Math::Prime::Util::GMP::exp_mangoldt(&_big2uistr || return ONE);
6395             $n eq '1' and return ONE;
6396             $n <= ULONG_MAX ? __PACKAGE__->_set_uint($n) : __PACKAGE__->_set_str('int', $n);
6397             }
6398              
6399             sub totient {
6400             my $n = Math::Prime::Util::GMP::totient(&_big2uistr // goto &nan);
6401             $n <= ULONG_MAX ? __PACKAGE__->_set_uint($n) : __PACKAGE__->_set_str('int', $n);
6402             }
6403              
6404             *euler_phi = \&totient;
6405             *euler_totient = \&totient;
6406              
6407             sub jordan_totient {
6408             my ($x, $y) = @_;
6409             _valid(\$y);
6410             my $n = Math::Prime::Util::GMP::jordan_totient(_big2istr($x) // (goto &nan), _big2istr($y) // (goto &nan));
6411             $n <= ULONG_MAX ? __PACKAGE__->_set_uint($n) : __PACKAGE__->_set_str('int', $n);
6412             }
6413              
6414             sub carmichael_lambda {
6415             my $n = Math::Prime::Util::GMP::carmichael_lambda(&_big2uistr // goto &nan);
6416             $n <= ULONG_MAX ? __PACKAGE__->_set_uint($n) : __PACKAGE__->_set_str('int', $n);
6417             }
6418              
6419             sub liouville {
6420             Math::Prime::Util::GMP::liouville(&_big2uistr // goto &nan) == 1 ? ONE : MONE;
6421             }
6422              
6423             sub big_omega {
6424             __PACKAGE__->_set_uint(scalar Math::Prime::Util::GMP::factor(&_big2uistr // goto &nan));
6425             }
6426              
6427             sub omega {
6428             my %factors;
6429             @factors{Math::Prime::Util::GMP::factor(&_big2uistr // goto &nan)} = ();
6430             __PACKAGE__->_set_uint(scalar keys %factors);
6431             }
6432              
6433             sub sigma0 {
6434             my $str = &_big2uistr // goto &nan;
6435             $str eq '0' && return ZERO;
6436             my $n = Math::Prime::Util::GMP::sigma($str, 0);
6437             $n <= ULONG_MAX ? __PACKAGE__->_set_uint($n) : __PACKAGE__->_set_str('int', $n);
6438             }
6439              
6440             sub sigma {
6441             my ($x, $y) = @_;
6442              
6443             my $n = defined($y)
6444             ? do {
6445             _valid(\$y);
6446             Math::Prime::Util::GMP::sigma(_big2uistr($x) // (goto &nan), _big2uistr($y) // (goto &nan));
6447             }
6448             : Math::Prime::Util::GMP::sigma(&_big2uistr // (goto &nan), 1);
6449              
6450             $n <= ULONG_MAX ? __PACKAGE__->_set_uint($n) : __PACKAGE__->_set_str('int', $n);
6451             }
6452              
6453             sub partitions {
6454             my $n = Math::Prime::Util::GMP::partitions(&_big2uistr // goto &nan);
6455             $n <= ULONG_MAX ? __PACKAGE__->_set_uint($n) : __PACKAGE__->_set_str('int', $n);
6456             }
6457              
6458             sub is_primitive_root {
6459             my ($x, $y) = @_;
6460             _valid(\$y);
6461             __is_int__($$x)
6462             && __is_int__($$y)
6463             && Math::Prime::Util::GMP::is_primitive_root(_big2uistr($x) // (return Sidef::Types::Bool::Bool::FALSE),
6464             _big2uistr($y) // (return Sidef::Types::Bool::Bool::FALSE))
6465             ? Sidef::Types::Bool::Bool::TRUE
6466             : Sidef::Types::Bool::Bool::FALSE;
6467             }
6468              
6469             sub is_square_free {
6470             my ($x) = @_;
6471             __is_int__($$x)
6472             && Math::Prime::Util::GMP::moebius(_big2uistr($x) // return Sidef::Types::Bool::Bool::FALSE)
6473             ? Sidef::Types::Bool::Bool::TRUE
6474             : Sidef::Types::Bool::Bool::FALSE;
6475             }
6476              
6477             sub is_smooth {
6478             my ($x, $n) = @_;
6479              
6480             _valid(\$n);
6481             __is_int__($$x) || return Sidef::Types::Bool::Bool::FALSE;
6482              
6483             $x = _any2mpz($$x) // return Sidef::Types::Bool::Bool::FALSE;
6484             $n = _any2mpz($$n) // return Sidef::Types::Bool::Bool::FALSE;
6485              
6486             Math::GMPz::Rmpz_sgn($n) <= 0
6487             and return Sidef::Types::Bool::Bool::FALSE;
6488              
6489             my $p = Math::GMPz::Rmpz_init_set_ui(2);
6490             my $t = Math::GMPz::Rmpz_init_set($x);
6491              
6492             while (Math::GMPz::Rmpz_cmp($p, $n) <= 0) {
6493             if (Math::GMPz::Rmpz_divisible_p($t, $p)) {
6494             Math::GMPz::Rmpz_remove($t, $t, $p);
6495             Math::GMPz::Rmpz_cmp_ui($t, 1) == 0
6496             and return Sidef::Types::Bool::Bool::TRUE;
6497             }
6498             Math::GMPz::Rmpz_nextprime($p, $p);
6499             }
6500              
6501             (Math::GMPz::Rmpz_cmp_ui($t, 1) == 0)
6502             ? Sidef::Types::Bool::Bool::TRUE
6503             : Sidef::Types::Bool::Bool::FALSE;
6504             }
6505              
6506             sub is_square {
6507             my ($x) = @_;
6508             __is_int__($$x)
6509             && Math::GMPz::Rmpz_perfect_square_p(_any2mpz($$x))
6510             ? Sidef::Types::Bool::Bool::TRUE
6511             : Sidef::Types::Bool::Bool::FALSE;
6512             }
6513              
6514             *is_sqr = \&is_square;
6515              
6516             sub is_power {
6517             my ($x, $y) = @_;
6518              
6519             __is_int__($$x) || return Sidef::Types::Bool::Bool::FALSE;
6520             $x = _any2mpz($$x) // return Sidef::Types::Bool::Bool::FALSE;
6521              
6522             if (defined $y) {
6523             _valid(\$y);
6524              
6525             if (Math::GMPz::Rmpz_cmp_ui($x, 1) == 0) {
6526             return Sidef::Types::Bool::Bool::TRUE;
6527             }
6528              
6529             $y = _any2si($$y) // return undef;
6530              
6531             # Everything is a first power
6532             $y == 1 and return Sidef::Types::Bool::Bool::TRUE;
6533              
6534             # Return a true value when $x=-1 and $y is odd
6535             $y % 2
6536             and (Math::GMPz::Rmpz_cmp_si($x, -1) == 0)
6537             and return Sidef::Types::Bool::Bool::TRUE;
6538              
6539             # Don't accept a non-positive power
6540             # Also, when $x is negative and $y is even, return faster
6541             if ($y <= 0 or ($y % 2 == 0 and Math::GMPz::Rmpz_sgn($x) < 0)) {
6542             return Sidef::Types::Bool::Bool::FALSE;
6543             }
6544              
6545             # Optimization for perfect squares (thanks to Dana Jacobsen)
6546             $y == 2
6547             and return (
6548             Math::GMPz::Rmpz_perfect_square_p($x)
6549             ? Sidef::Types::Bool::Bool::TRUE
6550             : Sidef::Types::Bool::Bool::FALSE
6551             );
6552              
6553             Math::GMPz::Rmpz_perfect_power_p($x)
6554             || return Sidef::Types::Bool::Bool::FALSE;
6555              
6556             state $t = Math::GMPz::Rmpz_init_nobless();
6557             Math::GMPz::Rmpz_root($t, $x, $y)
6558             ? Sidef::Types::Bool::Bool::TRUE
6559             : Sidef::Types::Bool::Bool::FALSE;
6560             }
6561             else {
6562             Math::GMPz::Rmpz_perfect_power_p($x)
6563             ? Sidef::Types::Bool::Bool::TRUE
6564             : Sidef::Types::Bool::Bool::FALSE;
6565             }
6566             }
6567              
6568             *is_pow = \&is_power;
6569              
6570             sub is_prime_power {
6571             my ($x) = @_;
6572             __is_int__($$x)
6573             && Math::Prime::Util::GMP::is_prime_power(_big2uistr($x) // return Sidef::Types::Bool::Bool::FALSE)
6574             ? Sidef::Types::Bool::Bool::TRUE
6575             : Sidef::Types::Bool::Bool::FALSE;
6576             }
6577              
6578             sub prime_root {
6579             my $str = &_big2uistr // return $_[0];
6580              
6581             my $pow = Math::Prime::Util::GMP::is_prime_power($str) || return $_[0];
6582             $pow == 1 and return $_[0];
6583              
6584             my $x = Math::GMPz::Rmpz_init_set_str($str, 10);
6585             $pow == 2
6586             ? Math::GMPz::Rmpz_sqrt($x, $x)
6587             : Math::GMPz::Rmpz_root($x, $x, $pow);
6588             bless \$x;
6589             }
6590              
6591             sub prime_power {
6592             my $pow = Math::Prime::Util::GMP::is_prime_power(&_big2uistr // return ONE) || return ONE;
6593             $pow == 1 ? ONE : __PACKAGE__->_set_uint($pow);
6594             }
6595              
6596             sub perfect_root {
6597             my $str = &_big2istr // return $_[0];
6598             my $pow = Math::Prime::Util::GMP::is_power($str) || return $_[0];
6599              
6600             my $x = Math::GMPz::Rmpz_init_set_str($str, 10);
6601             $pow == 2
6602             ? Math::GMPz::Rmpz_sqrt($x, $x)
6603             : Math::GMPz::Rmpz_root($x, $x, $pow);
6604             bless \$x;
6605             }
6606              
6607             sub perfect_power {
6608             __PACKAGE__->_set_uint(Math::Prime::Util::GMP::is_power(&_big2istr // return ONE) || return ONE);
6609             }
6610              
6611             sub next_pow2 {
6612             my ($x) = @_;
6613              
6614             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
6615              
6616             Math::MPFR::Rmpfr_log2($r, _any2mpfr($$x), $round_z);
6617             Math::MPFR::Rmpfr_ceil($r, $r);
6618              
6619             my $z = Math::GMPz::Rmpz_init_set_ui(1);
6620             my $ui = Math::MPFR::Rmpfr_get_ui($r, $ROUND);
6621             Math::GMPz::Rmpz_mul_2exp($z, $z, $ui);
6622             bless \$z;
6623             }
6624              
6625             *next_power2 = \&next_pow2;
6626              
6627             sub next_pow {
6628             my ($x, $y) = @_;
6629              
6630             _valid(\$y);
6631              
6632             my $f1 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
6633             my $f2 = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
6634              
6635             Math::MPFR::Rmpfr_log($f1, _any2mpfr($$x), $round_z);
6636             Math::MPFR::Rmpfr_log($f2, _any2mpfr($$y), $round_z);
6637              
6638             Math::MPFR::Rmpfr_div($f1, $f1, $f2, $ROUND);
6639             Math::MPFR::Rmpfr_ceil($f1, $f1);
6640              
6641             my $r = Math::GMPz::Rmpz_init();
6642             my $ui = Math::MPFR::Rmpfr_get_ui($f1, $ROUND);
6643             Math::GMPz::Rmpz_pow_ui($r, (_any2mpz($$y) // goto &nan), $ui);
6644             bless \$r;
6645             }
6646              
6647             *next_power = \&next_pow;
6648              
6649             sub shift_left {
6650             my ($x, $y) = @_;
6651              
6652             _valid(\$y);
6653              
6654             $y = _any2si($$y) // (goto &nan);
6655             $x = _any2mpz($$x) // (goto &nan);
6656              
6657             my $r = Math::GMPz::Rmpz_init();
6658              
6659             $y < 0
6660             ? Math::GMPz::Rmpz_div_2exp($r, $x, -$y)
6661             : Math::GMPz::Rmpz_mul_2exp($r, $x, $y);
6662              
6663             bless \$r;
6664             }
6665              
6666             *lsft = \&shift_left;
6667              
6668             sub shift_right {
6669             my ($x, $y) = @_;
6670              
6671             _valid(\$y);
6672              
6673             $y = _any2si($$y) // (goto &nan);
6674             $x = _any2mpz($$x) // (goto &nan);
6675              
6676             my $r = Math::GMPz::Rmpz_init();
6677              
6678             $y < 0
6679             ? Math::GMPz::Rmpz_mul_2exp($r, $x, -$y)
6680             : Math::GMPz::Rmpz_div_2exp($r, $x, $y);
6681              
6682             bless \$r;
6683             }
6684              
6685             *rsft = \&shift_right;
6686              
6687             #
6688             ## Rational specific
6689             #
6690              
6691             sub numerator {
6692             my ($x) = @_;
6693              
6694             my $r = $$x;
6695             while (1) {
6696             my $ref = ref($r);
6697             ref($r) eq 'Math::GMPz' && return $x; # is an integer
6698              
6699             if (ref($r) eq 'Math::GMPq') {
6700             my $z = Math::GMPz::Rmpz_init();
6701             Math::GMPq::Rmpq_get_num($z, $r);
6702             return bless \$z;
6703             }
6704              
6705             $r = _any2mpq($r) // (goto &nan);
6706             }
6707             }
6708              
6709             *nu = \&numerator;
6710              
6711             sub denominator {
6712             my ($x) = @_;
6713              
6714             my $r = $$x;
6715             while (1) {
6716             my $ref = ref($r);
6717             ref($r) eq 'Math::GMPz' && return ONE; # is an integer
6718              
6719             if (ref($r) eq 'Math::GMPq') {
6720             my $z = Math::GMPz::Rmpz_init();
6721             Math::GMPq::Rmpq_get_den($z, $r);
6722             return bless \$z;
6723             }
6724              
6725             $r = _any2mpq($r) // (goto &nan);
6726             }
6727             }
6728              
6729             *de = \&denominator;
6730              
6731             sub nude {
6732             ($_[0]->numerator, $_[0]->denominator);
6733             }
6734              
6735             #
6736             ## Conversion/Miscellaneous
6737             #
6738              
6739             sub chr {
6740             my ($x) = @_;
6741             Sidef::Types::String::String->new(CORE::chr(__numify__($$x)));
6742             }
6743              
6744             sub __round__ {
6745             my ($x, $prec) = @_;
6746              
6747             goto(ref($x) =~ tr/:/_/rs);
6748              
6749             Math_MPFR: {
6750             my $nth = -CORE::int($prec);
6751              
6752             my $p = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
6753             Math::MPFR::Rmpfr_set_str($p, '1e' . CORE::abs($nth), 10, $ROUND);
6754              
6755             my $r = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
6756              
6757             if ($nth < 0) {
6758             Math::MPFR::Rmpfr_div($r, $x, $p, $ROUND);
6759             }
6760             else {
6761             Math::MPFR::Rmpfr_mul($r, $x, $p, $ROUND);
6762             }
6763              
6764             Math::MPFR::Rmpfr_round($r, $r);
6765              
6766             if ($nth < 0) {
6767             Math::MPFR::Rmpfr_mul($r, $r, $p, $ROUND);
6768             }
6769             else {
6770             Math::MPFR::Rmpfr_div($r, $r, $p, $ROUND);
6771             }
6772              
6773             return $r;
6774             }
6775              
6776             Math_MPC: {
6777             my $real = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
6778             my $imag = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
6779              
6780             Math::MPC::RMPC_RE($real, $x);
6781             Math::MPC::RMPC_IM($imag, $x);
6782              
6783             $real = __SUB__->($real, $prec);
6784             $imag = __SUB__->($imag, $prec);
6785              
6786             if (Math::MPFR::Rmpfr_zero_p($imag)) {
6787             return $real;
6788             }
6789              
6790             my $r = Math::MPC::Rmpc_init2(CORE::int($PREC));
6791             Math::MPC::Rmpc_set_fr_fr($r, $real, $imag, $ROUND);
6792             return $r;
6793             }
6794              
6795             Math_GMPq: {
6796             my $nth = -CORE::int($prec);
6797              
6798             my $r = Math::GMPq::Rmpq_init();
6799             Math::GMPq::Rmpq_set($r, $x);
6800              
6801             my $sgn = Math::GMPq::Rmpq_sgn($r);
6802              
6803             if ($sgn < 0) {
6804             Math::GMPq::Rmpq_neg($r, $r);
6805             }
6806              
6807             my $p = Math::GMPz::Rmpz_init_set_str('1' . ('0' x CORE::abs($nth)), 10);
6808              
6809             if ($nth < 0) {
6810             Math::GMPq::Rmpq_div_z($r, $r, $p);
6811             }
6812             else {
6813             Math::GMPq::Rmpq_mul_z($r, $r, $p);
6814             }
6815              
6816             state $half = do {
6817             my $q = Math::GMPq::Rmpq_init_nobless();
6818             Math::GMPq::Rmpq_set_ui($q, 1, 2);
6819             $q;
6820             };
6821              
6822             Math::GMPq::Rmpq_add($r, $r, $half);
6823              
6824             my $z = Math::GMPz::Rmpz_init();
6825             Math::GMPz::Rmpz_set_q($z, $r);
6826              
6827             if (Math::GMPz::Rmpz_odd_p($z) and Math::GMPq::Rmpq_integer_p($r)) {
6828             Math::GMPz::Rmpz_sub_ui($z, $z, 1);
6829             }
6830              
6831             Math::GMPq::Rmpq_set_z($r, $z);
6832              
6833             if ($nth < 0) {
6834             Math::GMPq::Rmpq_mul_z($r, $r, $p);
6835             }
6836             else {
6837             Math::GMPq::Rmpq_div_z($r, $r, $p);
6838             }
6839              
6840             if ($sgn < 0) {
6841             Math::GMPq::Rmpq_neg($r, $r);
6842             }
6843              
6844             if (Math::GMPq::Rmpq_integer_p($r)) {
6845             Math::GMPz::Rmpz_set_q($z, $r);
6846             return $z;
6847             }
6848              
6849             return $r;
6850             }
6851              
6852             Math_GMPz: {
6853             $x = _mpz2mpq($x);
6854             goto Math_GMPq;
6855             }
6856             }
6857              
6858             sub round {
6859             my ($x, $prec) = @_;
6860              
6861             my $nth = (
6862             defined($prec)
6863             ? do {
6864             _valid(\$prec);
6865             _any2si($$prec) // (goto &nan);
6866             }
6867             : 0
6868             );
6869              
6870             bless \__round__($$x, $nth);
6871             }
6872              
6873             *roundf = \&round;
6874              
6875             sub to {
6876             my ($from, $to, $step) = @_;
6877             Sidef::Types::Range::RangeNumber->new($from, $to, $step // ONE);
6878             }
6879              
6880             *upto = \&to;
6881              
6882             sub downto {
6883             my ($from, $to, $step) = @_;
6884             Sidef::Types::Range::RangeNumber->new($from, $to, defined($step) ? $step->neg : MONE);
6885             }
6886              
6887             sub xto {
6888             my ($from, $to, $step) = @_;
6889              
6890             $to =
6891             defined($step)
6892             ? $to->sub($step)
6893             : $to->dec;
6894              
6895             Sidef::Types::Range::RangeNumber->new($from, $to, $step // ONE);
6896             }
6897              
6898             *xupto = \&xto;
6899              
6900             sub xdownto {
6901             my ($from, $to, $step) = @_;
6902              
6903             $from =
6904             defined($step)
6905             ? $from->sub($step)
6906             : $from->dec;
6907              
6908             Sidef::Types::Range::RangeNumber->new($from, $to, defined($step) ? $step->neg : MONE);
6909             }
6910              
6911             sub range {
6912             my ($from, $to, $step) = @_;
6913              
6914             defined($to)
6915             ? $from->to($to, $step)
6916             : (ZERO)->to($from->dec);
6917             }
6918              
6919             {
6920             my $srand = srand();
6921              
6922             {
6923             state $state = Math::MPFR::Rmpfr_randinit_mt_nobless();
6924             Math::MPFR::Rmpfr_randseed_ui($state, $srand);
6925              
6926             sub rand {
6927             my ($x, $y) = @_;
6928              
6929             my $rand = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
6930              
6931             if (defined($y)) {
6932             _valid(\$y);
6933             Math::MPFR::Rmpfr_urandom($rand, $state, $ROUND);
6934             $rand = __mul__($rand, __sub__($$y, $$x));
6935             $rand = __add__($rand, $$x);
6936             }
6937             else {
6938             Math::MPFR::Rmpfr_urandom($rand, $state, $ROUND);
6939             $rand = __mul__($rand, $$x);
6940             }
6941             bless \$rand;
6942             }
6943              
6944             sub seed {
6945             my ($x) = @_;
6946             my $z = _any2mpz($$x) // die "[ERROR] Number.seed(): invalid seed value <<$x>> (expected an integer)";
6947             Math::MPFR::Rmpfr_randseed($state, $z);
6948             bless \$z;
6949             }
6950             }
6951              
6952             {
6953             state $state = Math::GMPz::zgmp_randinit_mt_nobless();
6954             Math::GMPz::zgmp_randseed_ui($state, $srand);
6955              
6956             sub irand {
6957             my ($x, $y) = @_;
6958              
6959             if (defined($y)) {
6960             _valid(\$y);
6961              
6962             $x = _any2mpz($$x) // goto &nan;
6963             $y = _any2mpz($$y) // goto &nan;
6964              
6965             my $cmp = Math::GMPz::Rmpz_cmp($y, $x);
6966              
6967             if ($cmp == 0) {
6968             return $_[0];
6969             }
6970             elsif ($cmp < 0) {
6971             ($x, $y) = ($y, $x);
6972             }
6973              
6974             my $r = Math::GMPz::Rmpz_init();
6975             Math::GMPz::Rmpz_sub($r, $y, $x);
6976             Math::GMPz::Rmpz_add_ui($r, $r, 1);
6977             Math::GMPz::Rmpz_urandomm($r, $state, $r, 1);
6978             Math::GMPz::Rmpz_add($r, $r, $x);
6979             return bless \$r;
6980             }
6981              
6982             $x = Math::GMPz::Rmpz_init_set(_any2mpz($$x) // goto &nan);
6983              
6984             my $sgn = Math::GMPz::Rmpz_sgn($x)
6985             || return ZERO;
6986              
6987             if ($sgn < 0) {
6988             Math::GMPz::Rmpz_sub_ui($x, $x, 1);
6989             }
6990             else {
6991             Math::GMPz::Rmpz_add_ui($x, $x, 1);
6992             }
6993              
6994             Math::GMPz::Rmpz_urandomm($x, $state, $x, 1);
6995             Math::GMPz::Rmpz_neg($x, $x) if $sgn < 0;
6996             bless \$x;
6997             }
6998              
6999             sub iseed {
7000             my ($x) = @_;
7001             my $z = _any2mpz($$x) // die "[ERROR] Number.iseed(): invalid seed value <<$x>> (expected an integer)";
7002             Math::GMPz::zgmp_randseed($state, $z);
7003             bless \$z;
7004             }
7005             }
7006             }
7007              
7008             sub of {
7009             my ($x, $obj) = @_;
7010              
7011             $x = CORE::int(__numify__($$x));
7012              
7013             if (ref($obj) eq 'Sidef::Types::Block::Block') {
7014             my @array;
7015             for (my $i = 0 ; $i < $x ; ++$i) {
7016             push @array,
7017             $obj->run(
7018             $i <= 8192
7019             ? __PACKAGE__->_set_uint($i)
7020             : bless \Math::GMPz::Rmpz_init_set_ui($i)
7021             );
7022             }
7023             return Sidef::Types::Array::Array->new(\@array);
7024             }
7025              
7026             Sidef::Types::Array::Array->new([($obj) x $x]);
7027             }
7028              
7029             sub defs {
7030             my ($x, $block) = @_;
7031              
7032             my @items;
7033             my $end = CORE::int(__numify__($$x));
7034              
7035             for (my ($i, $j) = (0, 0) ; $j < $end ; ++$i) {
7036             push @items,
7037             $block->run(
7038             $i <= 8192
7039             ? __PACKAGE__->_set_uint($i)
7040             : bless \Math::GMPz::Rmpz_init_set_ui($i)
7041             ) // next;
7042             ++$j;
7043             }
7044              
7045             Sidef::Types::Array::Array->new(\@items);
7046             }
7047              
7048             sub times {
7049             my ($num, $block) = @_;
7050              
7051             if (__is_inf__($$num)) {
7052             for (my $i = 0 ; ; ++$i) {
7053             $block->run(
7054             $i <= 8192
7055             ? __PACKAGE__->_set_uint($i)
7056             : bless \Math::GMPz::Rmpz_init_set_ui($i)
7057             );
7058             }
7059             return $_[0];
7060             }
7061              
7062             $num = _any2mpz($$num) // return undef;
7063              
7064             if (defined(my $ui = _any2ui($num))) {
7065             for (my $i = 0 ; $i < $ui ; ++$i) {
7066             $block->run(
7067             $i <= 8192
7068             ? __PACKAGE__->_set_uint($i)
7069             : bless \Math::GMPz::Rmpz_init_set_ui($i)
7070             );
7071             }
7072             return $_[0];
7073             }
7074              
7075             for (my $i = Math::GMPz::Rmpz_init_set_ui(0) ; Math::GMPz::Rmpz_cmp($i, $num) < 0 ; Math::GMPz::Rmpz_add_ui($i, $i, 1))
7076             {
7077             $block->run(bless(\Math::GMPz::Rmpz_init_set($i)));
7078             }
7079              
7080             $_[0];
7081             }
7082              
7083             foreach my $name (
7084             qw(
7085             permutations
7086             circular_permutations
7087             derangements
7088             )
7089             ) {
7090             no strict 'refs';
7091             *{__PACKAGE__ . '::' . $name} = sub {
7092             #<<<
7093             my ($n, $block) = @_;
7094             Sidef::Types::Array::Array->new([map { __PACKAGE__->_set_uint($_) } 0 .. __numify__($$n) - 1])->$name($block);
7095             #>>>
7096             };
7097             }
7098              
7099             *complete_permutations = \&derangements;
7100              
7101             foreach my $name (
7102             qw(
7103             subsets
7104             variations
7105             variations_with_repetition
7106             combinations
7107             combinations_with_repetition
7108             )
7109             ) {
7110             no strict 'refs';
7111             *{__PACKAGE__ . '::' . $name} = sub {
7112             #<<<
7113             my ($n, $k, $block) = @_;
7114             Sidef::Types::Array::Array->new([map { __PACKAGE__->_set_uint($_) } 0 .. __numify__($$n) - 1])->$name($k, $block);
7115             #>>>
7116             };
7117             }
7118              
7119             *tuples = \&variations;
7120             *tuples_with_repetition = \&variations_with_repetition;
7121              
7122             sub commify {
7123             my ($self) = @_;
7124              
7125             my $n = "$self";
7126              
7127             my $x = $n;
7128             my $neg = $n =~ s{^-}{};
7129             $n =~ /\.|$/;
7130              
7131             if ($-[0] > 3) {
7132              
7133             my $l = $-[0] - 3;
7134             my $i = ($l - 1) % 3 + 1;
7135              
7136             $x = substr($n, 0, $i) . ',';
7137              
7138             while ($i < $l) {
7139             $x .= substr($n, $i, 3) . ',';
7140             $i += 3;
7141             }
7142              
7143             $x .= substr($n, $i);
7144             }
7145              
7146             Sidef::Types::String::String->new(($neg ? '-' : '') . $x);
7147             }
7148              
7149             #
7150             ## Conversions
7151             #
7152              
7153             sub rad2deg {
7154             my ($x) = @_;
7155             my $f = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
7156             Math::MPFR::Rmpfr_const_pi($f, $ROUND);
7157             Math::MPFR::Rmpfr_ui_div($f, 180, $f, $ROUND);
7158             bless \__mul__($f, $$x);
7159             }
7160              
7161             sub deg2rad {
7162             my ($x) = @_;
7163             my $f = Math::MPFR::Rmpfr_init2(CORE::int($PREC));
7164             Math::MPFR::Rmpfr_const_pi($f, $ROUND);
7165             Math::MPFR::Rmpfr_div_ui($f, $f, 180, $ROUND);
7166             bless \__mul__($f, $$x);
7167             }
7168              
7169             {
7170             no strict 'refs';
7171              
7172             *{__PACKAGE__ . '::' . '/'} = \÷
7173             *{__PACKAGE__ . '::' . '÷'} = \÷
7174             *{__PACKAGE__ . '::' . '*'} = \&mul;
7175             *{__PACKAGE__ . '::' . '+'} = \&add;
7176             *{__PACKAGE__ . '::' . '-'} = \⊂
7177             *{__PACKAGE__ . '::' . '%'} = \&mod;
7178             *{__PACKAGE__ . '::' . '**'} = \&pow;
7179             *{__PACKAGE__ . '::' . '++'} = \&inc;
7180             *{__PACKAGE__ . '::' . '--'} = \&dec;
7181             *{__PACKAGE__ . '::' . '<'} = \<
7182             *{__PACKAGE__ . '::' . '>'} = \>
7183             *{__PACKAGE__ . '::' . '&'} = \∧
7184             *{__PACKAGE__ . '::' . '|'} = \∨
7185             *{__PACKAGE__ . '::' . '^'} = \&xor;
7186             *{__PACKAGE__ . '::' . '<=>'} = \&cmp;
7187             *{__PACKAGE__ . '::' . '<='} = \≤
7188             *{__PACKAGE__ . '::' . '≤'} = \≤
7189             *{__PACKAGE__ . '::' . '>='} = \≥
7190             *{__PACKAGE__ . '::' . '≥'} = \≥
7191             *{__PACKAGE__ . '::' . '=='} = \&eq;
7192             *{__PACKAGE__ . '::' . '!='} = \≠
7193             *{__PACKAGE__ . '::' . '≠'} = \≠
7194             *{__PACKAGE__ . '::' . '..'} = \&to;
7195             *{__PACKAGE__ . '::' . '..^'} = \&xto;
7196             *{__PACKAGE__ . '::' . '^..'} = \&xdownto;
7197             *{__PACKAGE__ . '::' . '!'} = \&factorial;
7198             *{__PACKAGE__ . '::' . '!!'} = \&double_factorial;
7199             *{__PACKAGE__ . '::' . '%%'} = \&is_div;
7200             *{__PACKAGE__ . '::' . '>>'} = \&shift_right;
7201             *{__PACKAGE__ . '::' . '<<'} = \&shift_left;
7202             *{__PACKAGE__ . '::' . '~'} = \¬
7203             *{__PACKAGE__ . '::' . ':'} = \&pair;
7204             *{__PACKAGE__ . '::' . '//'} = \&idiv;
7205             *{__PACKAGE__ . '::' . 'γ'} = \&Y;
7206             *{__PACKAGE__ . '::' . 'Γ'} = \γ
7207             *{__PACKAGE__ . '::' . 'Ψ'} = \ϝ
7208             *{__PACKAGE__ . '::' . 'ϕ'} = \&euler_totient;
7209             *{__PACKAGE__ . '::' . 'σ'} = \σ
7210             *{__PACKAGE__ . '::' . 'Ω'} = \&big_omega;
7211             *{__PACKAGE__ . '::' . 'ω'} = \ω
7212             *{__PACKAGE__ . '::' . 'ζ'} = \ζ
7213             *{__PACKAGE__ . '::' . 'η'} = \η
7214             *{__PACKAGE__ . '::' . 'μ'} = \&mobius;
7215             }
7216             }
7217              
7218             1