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