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