File Coverage

blib/lib/Math/BigSym.pm
Criterion Covered Total %
statement 9 11 81.8
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 13 15 86.6


line stmt bran cond sub pod time code
1             package Math::BigSym;
2              
3 1     1   13178 use 5.014;
  1         2  
4 1     1   4 use strict;
  1         1  
  1         16  
5 1     1   2 use warnings;
  1         4  
  1         26  
6              
7 1     1   212 use Math::GMPq qw();
  0            
  0            
8             use Math::GMPz qw();
9             use Scalar::Util qw();
10              
11             use Math::Algebra::Symbols (symbols => '_sym');
12              
13             our $VERSION = '0.01';
14              
15             =encoding utf8
16              
17             =head1 NAME
18              
19             Math::BigSym - Fast symbolic calculations with arbitrary large rationals.
20              
21             =head1 VERSION
22              
23             Version 0.01
24              
25             =head1 SYNOPSIS
26              
27             use 5.014;
28             use Math::BigSym qw(:constant);
29              
30             # Rational operations
31             my $x = 2/3;
32             say $x * 3; # => 2
33             say 2 / $x; # => 3
34             say $x; # => "2/3"
35             say 1 + 4.5**(-3); # => "737/729"
36              
37             # Floating-point operations
38             say "equal" if (1.1 + 2.2 == 3.3); # => "equal"
39              
40             # Symbolic operations
41             say log(-5) / 2; # => "1/2*log(-5)"
42             say sqrt(exp(-1)); # => "sqrt(exp(-1))"
43              
44             =head1 DESCRIPTION
45              
46             Math::BigSym provides a transparent interface to L and L,
47             focusing on performance and easy-to-use.
48              
49             =head1 HOW IT WORKS
50              
51             Math::BigSym tries really hard to do the right thing and as efficiently as possible.
52             For example, if you say C<$x**$y>, it first checks to see if C<$x> and C<$y> are integers,
53             so it can optimize the operation to integer exponentiation, by calling the corresponding
54             I function. Otherwise, it will check to see if C<$y> is an integer and will do rational
55             exponentiation, by multiplying C<$x> by itself C<$y> times. If both conditions fail, it will
56             do symbolic exponentiation, using the relation: C.
57              
58             All numbers in Math::BigSym are stored as rational L objects. Each operation
59             outside the functions provided by L, is done symbolically, calling the corresponding
60             L functions.
61              
62             =head1 IMPORT/EXPORT
63              
64             Math::BigSym does not export anything by default, but it recognizes the following list of words:
65              
66             :constant # will make any number a Math::BigSym object
67             i # "i" number (sqrt(-1))
68             e # "e" constant (2.7182...)
69             pi # "pi" constant (3.1415...)
70             tau # "tau" constant (2*pi)
71             phi # Golden ratio constant (1.618...)
72             ln2 # Natural logarithm of two (log(2))
73              
74             The syntax for importing something, is:
75              
76             use Math::BigSym qw(:constant pi);
77             say cos(2*pi);
78              
79             B C<:constant> is lexical to the current scope only.
80              
81             =head1 SUBROUTINES/METHODS
82              
83             =cut
84              
85             use overload
86             '""' => \&stringify,
87             '0+' => \&numify,
88             bool => \&boolify,
89              
90             '+' => sub { $_[0]->add($_[1]) },
91             '*' => sub { $_[0]->mul($_[1]) },
92              
93             '==' => sub { $_[0]->eq($_[1]) },
94             '!=' => sub { $_[0]->ne($_[1]) },
95              
96             #'&' => sub { $_[0]->and($_[1]) },
97             #'|' => sub { $_[0]->ior($_[1]) },
98             #'^' => sub { $_[0]->xor($_[1]) },
99             '~' => \&conjugate,
100              
101             #'++' => \&binc,
102             #'--' => \&bdec,
103              
104             '>' => sub { Math::BigSym::gt($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
105             '>=' => sub { Math::BigSym::ge($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
106             '<' => sub { Math::BigSym::lt($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
107             '<=' => sub { Math::BigSym::le($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
108             '<=>' => sub { Math::BigSym::cmp($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
109              
110             #'>>' => sub { Math::BigSym::rsft($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
111             #'<<' => sub { Math::BigSym::lsft($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
112              
113             '**' => sub { Math::BigSym::pow($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
114             '-' => sub { Math::BigSym::sub($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
115             '/' => sub { Math::BigSym::div($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
116              
117             #'%' => sub { Math::BigSym::mod($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
118             #atan2 => sub { Math::BigSym::atan2($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
119              
120             eq => sub { "$_[0]" eq "$_[1]" },
121             ne => sub { "$_[0]" ne "$_[1]" },
122              
123             cmp => sub { $_[2] ? "$_[1]" cmp $_[0]->stringify : $_[0]->stringify cmp "$_[1]" },
124              
125             neg => \&neg,
126             sin => \&sin,
127             cos => \&cos,
128             exp => \&exp,
129             log => \&ln,
130              
131             #int => \&int,
132             abs => \&abs,
133             sqrt => \&sqrt;
134              
135             {
136             my %constants = (
137             e => \&e,
138             i => \&i,
139             phi => \&phi,
140             ln2 => \&ln2,
141             tau => \&tau,
142             pi => \&pi,
143             );
144              
145             sub import {
146             shift;
147              
148             my $caller = caller(0);
149              
150             foreach my $name (@_) {
151             if ($name eq ':constant') {
152             overload::constant
153             integer => sub { _new_int(shift, 10) },
154             float => sub { _new_float(shift) },
155             binary => sub {
156             my ($const) = @_;
157             my $prefix = substr($const, 0, 2);
158             $prefix eq '0x' ? _new_int(substr($const, 2), 16)
159             : $prefix eq '0b' ? _new_int(substr($const, 2), 2)
160             : _new_int(substr($const, 1), 8);
161             },
162             ;
163             }
164             elsif (exists $constants{$name}) {
165             no strict 'refs';
166             my $caller_sub = $caller . '::' . $name;
167             if (!defined &$caller_sub) {
168             my $sub = $constants{$name};
169             my $value = Math::BigSym->$sub;
170             *$caller_sub = sub() { $value }
171             }
172             }
173             else {
174             die "unknown import: <<$name>>";
175             }
176             }
177             return;
178             }
179             }
180              
181             # Convert any mpz object to mpq
182             sub _mpz2mpq {
183             my $r = Math::GMPq::Rmpq_init();
184             Math::GMPq::Rmpq_set_z($r, $_[0]);
185             $r;
186             }
187              
188             # Return the numerator of an mpq integer object as mpz
189             sub _int2mpz {
190             my $z = Math::GMPz::Rmpz_init();
191             Math::GMPq::Rmpq_get_num($z, $_[0]);
192             $z;
193             }
194              
195             sub _either {
196              
197             my $same = 1;
198             my ($ref, @args);
199              
200             foreach my $val (@_) {
201             if (ref($val) eq __PACKAGE__) {
202             push @args, $$val;
203             }
204             else {
205             push @args, _str2mpq($val);
206             }
207              
208             if ($same) {
209             my $arg = $args[-1];
210             if (defined($ref)) {
211             if (ref($arg) eq $ref) {
212             $same = ref($arg);
213             }
214             else {
215             $same = 0;
216             }
217             }
218             else {
219             $ref = ref($arg);
220             }
221             }
222             }
223              
224             $same ? @args : (map { ref($_) eq 'Math::GMPq' ? _sym($_) : $_ } @args);
225             }
226              
227             sub _symbols {
228             map {
229             my $val = ref($_) eq __PACKAGE__ ? $$_ : $_;
230             index(ref($val), 'Math::Algebra::Symbols') == 0 ? $val : _sym($val);
231             } @_;
232             }
233              
234             sub _str2rat {
235             my $str = lc($_[0] || "0");
236              
237             my $sign = substr($str, 0, 1);
238             if ($sign eq '-') {
239             substr($str, 0, 1, '');
240             $sign = '-';
241             }
242             else {
243             substr($str, 0, 1, '') if ($sign eq '+');
244             $sign = '';
245             }
246              
247             my $i;
248             if (($i = index($str, 'e')) != -1) {
249              
250             my $exp = substr($str, $i + 1);
251             my ($before, $after) = split(/\./, substr($str, 0, $i));
252              
253             if (!defined($after)) { # return faster for numbers like "13e2"
254             if ($exp >= 0) {
255             return ("$sign$before" . ('0' x $exp));
256             }
257             else {
258             $after = '';
259             }
260             }
261              
262             my $numerator = "$before$after";
263             my $denominator = "1";
264              
265             if ($exp < 1) {
266             $denominator .= '0' x (CORE::abs($exp) + length($after));
267             }
268             else {
269             my $diff = ($exp - length($after));
270             if ($diff >= 0) {
271             $numerator .= '0' x $diff;
272             }
273             else {
274             my $s = "$before$after";
275             substr($s, $exp + length($before), 0, '.');
276             return _str2rat("$sign$s");
277             }
278             }
279              
280             "$sign$numerator/$denominator";
281             }
282             elsif (($i = index($str, '.')) != -1) {
283             my ($before, $after) = (substr($str, 0, $i), substr($str, $i + 1));
284             if ($after =~ tr/0// == length($after)) {
285             return "$sign$before";
286             }
287             $sign . ("$before$after/1" =~ s/^0+//r) . ('0' x length($after));
288             }
289             else {
290             "$sign$str";
291             }
292             }
293              
294             # Converts a string into an mpq object
295             sub _str2mpq {
296             my $r = Math::GMPq::Rmpq_init();
297              
298             $_[0] || do {
299             Math::GMPq::Rmpq_set_ui($r, 0, 1);
300             return $r;
301             };
302              
303             my $rat = $_[0] =~ tr/.Ee// ? _str2rat($_[0] =~ tr/_//dr) : ($_[0] =~ tr/_+//dr);
304             if ($rat !~ m{^\s*[-+]?[0-9]+(?>\s*/\s*[1-9]+[0-9]*)?\s*\z}) {
305             require Carp;
306             Carp::confess("Not a base-10 numerical value: <<$_[0]>>");
307             }
308             Math::GMPq::Rmpq_set_str($r, $rat, 10);
309             Math::GMPq::Rmpq_canonicalize($r) if (index($rat, '/') != -1);
310              
311             $r;
312             }
313              
314             #
315             ## Constants
316             #
317              
318             my $ZERO = _new_int(0);
319             my $ONE = _new_int(1);
320             my $INF = _new(-Math::Algebra::Symbols::Sum::zero()->Log);
321              
322             =head2 pi
323              
324             BigSym->pi # => BigSym
325              
326             Returns a symbolic object to represent the number B.
327              
328             =cut
329              
330             {
331             my $pi = _new(Math::Algebra::Symbols::Sum::pi());
332             ##my $pi = _new(CORE::log(Math::Algebra::Symbols::Sum::mOne()) / Math::Algebra::Symbols::Sum::i());
333             sub pi { $pi }
334             }
335              
336             =head2 tau
337              
338             BigSym->tau # => BigSym
339              
340             Returns a symbolic object to represent the number B (which is C<2*PI>).
341              
342             =cut
343              
344             {
345             my $tau = _new(Math::Algebra::Symbols::Sum::pi()->multiply(Math::Algebra::Symbols::Sum::two()));
346             sub tau { $tau }
347             }
348              
349             =head2 i
350              
351             BigSym->i # => BigSym
352              
353             Returns a symbolic object to represent the number B.
354              
355             =cut
356              
357             {
358             my $i = _new(Math::Algebra::Symbols::Sum::i());
359             sub i { $i }
360             }
361              
362             =head2 e
363              
364             BigSym->e # => BigSym
365              
366             Returns a symbolic object to represent the B mathematical constant.
367              
368             =cut
369              
370             {
371             my $e = _new(Math::Algebra::Symbols::Sum::one()->Exp);
372             sub e { $e }
373             }
374              
375             =head2 ln2
376              
377             BigSym->ln2 # => BigSym
378              
379             Returns a symbolic object to represent the natural logarithm of two (C).
380              
381             =cut
382              
383             {
384             my $ln2 = _new(Math::Algebra::Symbols::Sum::two()->Log);
385             sub ln2 { $ln2 }
386             }
387              
388             =head2 phi
389              
390             BigSym->phi # => BigSym
391              
392             Returns a symbolic object to represent the Golden Ratio constant (C<(sqrt(5)+1)/2>).
393              
394             =cut
395              
396             {
397             my $phi = _new(Math::Algebra::Symbols::Sum::one()->add(_sym(5)->Sqrt)->divide(Math::Algebra::Symbols::Sum::two()));
398             sub phi { $phi }
399             }
400              
401             #
402             ## Initialization
403             #
404              
405             sub _new {
406             bless \$_[0], __PACKAGE__;
407             }
408              
409             =head2 new
410              
411             BigSym->new(Scalar) # => BigSym
412             BigSym->new(Scalar, Scalar) # => BigSym
413              
414             Returns a new BigSym object with the value specified in the first argument,
415             which can be a Perl numerical value, a string representing a number in a
416             rational form, such as C<"1/2">, a string holding a floating-point number,
417             such as C<"0.5">, or a string holding an integer, such as C<"255">, or a symbol.
418              
419             The second argument specifies the base of the number, which can range from 2
420             to 36 inclusive and defaults to 10.
421              
422             This sets a symbol:
423              
424             my $x = Math::BigSym->new('x');
425              
426             This sets an hexadecimal number:
427              
428             my $y = Math::BigSym->new("deadbeef", 16);
429              
430             B no prefix, such as C<"0x"> or C<"0b">, is allowed as part of the number.
431              
432             =cut
433              
434             sub new {
435             my ($class, $str, $base) = @_;
436              
437             $str || return $ZERO;
438             $str =~ tr/_//d;
439              
440             if (defined($base)) {
441             if ($base < 2 or $base > 36) {
442             require Carp;
443             Carp::croak("base must be between 2 and 36, got $base");
444             }
445             }
446             else {
447             $base = 10;
448             }
449              
450             my $obj;
451             if ($base == 10 and Scalar::Util::looks_like_number($str)) {
452             if ((~$str & $str) eq '0' and CORE::int($str) eq $str) {
453             $obj = Math::GMPq::Rmpq_init();
454             if ($str >= 0) {
455             Math::GMPq::Rmpq_set_ui($obj, $str, 1);
456             }
457             else {
458             Math::GMPq::Rmpq_set_si($obj, $str, 1);
459             }
460             }
461             else {
462             $obj = _str2mpq($str);
463             }
464             }
465             elsif ($base != 10 or $str =~ m{^\s*[-+]?[0-9]+(?>\s*/\s*[1-9]+[0-9]*)?\s*\z}) {
466             $obj = Math::GMPq::Rmpq_init();
467             Math::GMPq::Rmpq_set_str($obj, $str, $base);
468             Math::GMPq::Rmpq_canonicalize($obj) if index($str, '/') != -1;
469             }
470             else {
471             $obj = _sym($str);
472             }
473              
474             bless \$obj, $class;
475             }
476              
477             sub _new_int {
478             my ($int, $base) = @_;
479              
480             my $r = Math::GMPq::Rmpq_init();
481             Math::GMPq::Rmpq_set_str($r, "$int/1" =~ tr/_//rd, $base // 10);
482              
483             bless \$r, __PACKAGE__;
484             }
485              
486             sub _new_float {
487             my ($float) = @_;
488             bless \_str2mpq($float), __PACKAGE__;
489             }
490              
491             #
492             ## Conversions
493             #
494              
495             =head2 stringify
496              
497             $x->stringify # => Scalar
498              
499             Returns a string representing the value of C<$x>.
500              
501             =cut
502              
503             sub stringify {
504             ${$_[0]};
505             }
506              
507             =head2 numify
508              
509             $x->numify # => Scalar
510              
511             If C<$x> is a rational number, it returns a Perl numerical scalar with
512             the value of C<$x>, truncated if needed. Otherwise, it just returns the
513             symbolic value stored inside C<$x>.
514              
515             =cut
516              
517             sub numify {
518             my $x = ${$_[0]};
519             ref($x) eq 'Math::GMPq' ? Math::GMPq::Rmpq_get_d($x) : $x;
520             }
521              
522             =head2 boolify
523              
524             $x->boolify # => Bool
525              
526             Returns a true value when the number is not zero. False otherwise.
527              
528             =cut
529              
530             sub boolify {
531             my $x = ${$_[0]};
532             ref($x) eq 'Math::GMPq' ? !!Math::GMPq::Rmpq_sgn($x) : $x;
533             }
534              
535             #
536             ## Arithmetic operations
537             #
538              
539             =head2 neg
540              
541             $x->neg # => BigSym
542             -$x # => BigSym
543              
544             Returns the negated value of C<$x>.
545              
546             =cut
547              
548             sub neg {
549             my ($x) = _either(@_);
550             _new(-$x);
551             }
552              
553             =head2 abs
554              
555             $x->abs # => BigSym
556             abs($x) # => BigSym
557              
558             Absolute value of C<$x>.
559              
560             =cut
561              
562             sub abs {
563             my ($x) = _either(@_);
564             _new(CORE::abs($x));
565             }
566              
567             =head2 add
568              
569             $x->add(BigSym) # => BigSym
570             $x->add(Scalar) # => BigSym
571              
572             BigSym + BigSym # => BigSym
573             BigSym + Scalar # => BigSym
574             Scalar + BigSym # => BigSym
575              
576             Adds C<$y> to C<$x> and returns the result.
577              
578             =cut
579              
580             sub add {
581             my ($x, $y) = _either(@_);
582             _new($x + $y);
583             }
584              
585             =head2 sub
586              
587             $x->sub(BigSym) # => BigSym
588             $x->sub(Scalar) # => BigSym
589              
590             BigSym - BigSym # => BigSym
591             BigSym - Scalar # => BigSym
592             Scalar - BigSym # => BigSym
593              
594             Subtracts C<$y> from C<$x> and returns the result.
595              
596             =cut
597              
598             sub sub {
599             my ($x, $y) = _either(@_);
600             _new($x - $y);
601             }
602              
603             =head2 mul
604              
605             $x->mul(BigSym) # => BigSym
606             $x->mul(Scalar) # => BigSym
607              
608             BigSym * BigSym # => BigSym
609             BigSym * Scalar # => BigSym
610             Scalar * BigSym # => BigSym
611              
612             Multiplies C<$x> by C<$y> and returns the result.
613              
614             =cut
615              
616             sub mul {
617             my ($x, $y) = _either(@_);
618             _new($x * $y);
619             }
620              
621             =head2 div
622              
623             $x->div(BigSym) # => BigSym
624             $x->div(Scalar) # => BigSym
625              
626             BigSym / BigSym # => BigSym
627             BigSym / Scalar # => BigSym
628             Scalar / BigSym # => BigSym
629              
630             Divides C<$x> by C<$y> and returns the result.
631             Returns C when C<$y> is zero.
632              
633             =cut
634              
635             sub div {
636             my ($x, $y) = _either(@_);
637              
638             # Handle division by zero
639             if (ref($y) eq 'Math::GMPq' and !Math::GMPq::Rmpq_sgn($y)) {
640             return $INF * Math::GMPq::Rmpq_sgn($x);
641             }
642              
643             _new($x / $y);
644             }
645              
646             =head2 pow
647              
648             $x->pow(BigSym) # => BigSym
649             $x->pow(Scalar) # => BigSym
650              
651             BigSym ** BigSym # => BigSym
652             BigSym ** Scalar # => BigSym
653             Scalar ** BigSym # => BigSym
654              
655             Raises C<$x> to power C<$y> symbolically, based on the relation:
656             C. When C<$x> and C<$y> are both integers,
657             or when C<$x> is a rational and C<$y> is an integer smaller than 2^12,
658             it will perform the actual calculation.
659              
660             =cut
661              
662             sub pow {
663             my ($x, $y) = _either(@_);
664              
665             # Do integer exponentiation when both are integers
666             if (ref($x) eq 'Math::GMPq' and ref($y) eq 'Math::GMPq') {
667              
668             my $ysgn = Math::GMPq::Rmpq_sgn($y);
669              
670             if (!$ysgn) {
671             return $ONE;
672             }
673             elsif ($ysgn > 0 and !Math::GMPq::Rmpq_sgn($x)) {
674             return $ZERO;
675             }
676              
677             my $xint = Math::GMPq::Rmpq_integer_p($x);
678             my $yint = Math::GMPq::Rmpq_integer_p($y);
679              
680             if ($xint and $yint) {
681             my $pow = Math::GMPq::Rmpq_get_d($y);
682              
683             my $z = _int2mpz($x);
684             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
685              
686             my $q = Math::GMPq::Rmpq_init();
687             Math::GMPq::Rmpq_set_z($q, $z);
688              
689             if ($pow < 0) {
690             if (!Math::GMPq::Rmpq_sgn($q)) {
691             return $INF;
692             }
693             Math::GMPq::Rmpq_inv($q, $q);
694             }
695              
696             return _new($q);
697             }
698              
699             # When $y is an integer, multiply $x by itself $y times
700             elsif ($yint) {
701             my $pow = Math::GMPq::Rmpq_get_d($y);
702             $pow = -$pow if $ysgn < 0;
703              
704             if ($pow <= 0xFFF) {
705             my $r = Math::GMPq::Rmpq_init();
706             Math::GMPq::Rmpq_set_ui($r, 1, 1);
707              
708             for (1 .. $pow) {
709             Math::GMPq::Rmpq_mul($r, $r, $x);
710             }
711              
712             Math::GMPq::Rmpq_inv($r, $r) if $ysgn < 0;
713             return _new($r);
714             }
715             }
716              
717             $x = _sym($x);
718             $y = _sym($y);
719             }
720              
721             _new($x->Log->multiply($y)->Exp);
722             }
723              
724             =head2 root
725              
726             $x->root(BigSym) # => BigSym
727             $x->root(Scalar) # => BigSym
728              
729             Returns a symbolic representation for the Ith root of C<$x>,
730             based on the relation: C.
731              
732             =cut
733              
734             sub root {
735             my ($x, $y) = _symbols(@_);
736             _new($x->Log->divide($y)->Exp);
737             }
738              
739             =head2 sqrt
740              
741             $x->sqrt # => BigSym
742             sqrt($x) # => BigSym
743              
744             Returns a symbolic representation for the square root of C<$x>.
745             When C<$x> is an integer that is a perfect square, it will perform
746             the actual calculation.
747              
748             =cut
749              
750             sub sqrt {
751             my ($x) = _either(@_);
752              
753             if (ref($x) eq 'Math::GMPq') {
754              
755             # Check for perfect squares
756             if (Math::GMPq::Rmpq_integer_p($x)) {
757             my $nz = _int2mpz($x);
758             if (Math::GMPz::Rmpz_perfect_square_p($nz)) {
759             Math::GMPz::Rmpz_sqrt($nz, $nz);
760             return _new(_mpz2mpq($nz));
761             }
762             }
763              
764             $x = _sym($x);
765             }
766              
767             _new($x->Sqrt);
768             }
769              
770             =head2 ln
771              
772             $x->ln # => BigSym
773              
774             Returns a symbolic representation for the logarithm of C<$x> in base I.
775              
776             =cut
777              
778             sub ln {
779             my ($x) = _symbols(@_);
780             _new($x->Log);
781             }
782              
783             =head2 log
784              
785             $x->log # => BigSym
786             $x->log(BigSym) # => BigSym
787             $x->log(Scalar) # => BigSym
788             log(BigSym) # => BigSym
789              
790             Returns a symbolic representation for the logarithm of C<$x> in base C<$y>.
791             When C<$y> is not specified, it defaults to base I.
792              
793             =cut
794              
795             sub log {
796             my ($x, $y) = _symbols(@_);
797             _new(defined($y) ? $x->Log / $y->Log : $x->Log);
798             }
799              
800             =head2 exp
801              
802             $x->exp # => BigSym
803              
804             Returns a symbolic representation for the exponential of C<$x> in base e. (C)
805              
806             =cut
807              
808             sub exp {
809             my ($x) = _symbols(@_);
810             _new($x->Exp);
811             }
812              
813             #<<<
814             #~ sub mod {
815             #~ my ($x, $y) = _either(@_);
816              
817             #~ if (ref($x) eq 'Math::GMPq') {
818             #~ if (Math::GMPq::Rmpq_integer_p($x) and Math::GMPq::Rmpq_integer_p($y)) {
819              
820             #~ my $yz = _int2mpz($y);
821             #~ my $sign_y = Math::GMPz::Rmpz_sgn($yz);
822              
823             #~ # Probably, this should be an exception.
824             #~ return $ZERO if !$sign_y;
825              
826             #~ my $r = _int2mpz($x);
827             #~ Math::GMPz::Rmpz_mod($r, $r, $yz);
828             #~ if (!Math::GMPz::Rmpz_sgn($r)) {
829             #~ return $ZERO; # return faster
830             #~ }
831             #~ elsif ($sign_y < 0) {
832             #~ Math::GMPz::Rmpz_add($r, $r, $yz);
833             #~ }
834              
835             #~ return _new(_mpz2mpq($r));
836             #~ }
837              
838             #~ $x = _sym($x);
839             #~ $y = _sym($y);
840             #~ }
841              
842             #~ _new($x % $y);
843             #~ }
844             #>>>
845              
846             #
847             ## Trigonometry
848             #
849              
850             =head2 tan
851              
852             $x->tan # => BigSym
853              
854             Returns a symbolic representation for the tangent of C<$x>.
855              
856             =cut
857              
858             sub tan {
859             my ($x) = _symbols(@_);
860             _new($x->tan);
861             }
862              
863             =head2 sec
864              
865             $x->sec # => BigSym
866              
867             Returns a symbolic representation for the secant of C<$x>.
868              
869             =cut
870              
871             sub sec {
872             my ($x) = _symbols(@_);
873             _new($x->sec);
874             }
875              
876             =head2 csc
877              
878             $x->csc # => BigSym
879              
880             Returns a symbolic representation for the cosecant of C<$x>.
881              
882             =cut
883              
884             sub csc {
885             my ($x) = _symbols(@_);
886             _new($x->csc);
887             }
888              
889             =head2 cot
890              
891             $x->cot # => BigSym
892              
893             Returns a symbolic representation for the cotangent of C<$x>.
894              
895             =cut
896              
897             sub cot {
898             my ($x) = _symbols(@_);
899             _new($x->cot);
900             }
901              
902             =head2 sin
903              
904             $x->sin # => BigSym
905              
906             Returns a symbolic representation for the sine of C<$x>.
907              
908             =cut
909              
910             sub sin {
911             my ($x) = _symbols(@_);
912             _new($x->Sin);
913             }
914              
915             =head2 cos
916              
917             $x->cos # => BigSym
918              
919             Returns a symbolic representation for the cosine of C<$x>.
920              
921             =cut
922              
923             sub cos {
924             my ($x) = _symbols(@_);
925             _new($x->Cos);
926             }
927              
928             #
929             ## Hyperbolic operations
930             #
931              
932             =head2 sinh
933              
934             $x->sinh # => BigSym
935              
936             Returns a symbolic representation for the hyperbolic sine of C<$x>.
937              
938             =cut
939              
940             sub sinh {
941             my ($x) = _symbols(@_);
942             _new($x->sinh);
943             }
944              
945             =head2 cosh
946              
947             $x->cosh # => BigSym
948              
949             Returns a symbolic representation for the hyperbolic cosine of C<$x>.
950              
951             =cut
952              
953             sub cosh {
954             my ($x) = _symbols(@_);
955             _new($x->cosh);
956             }
957              
958             =head2 tanh
959              
960             $x->tanh # => BigSym
961              
962             Returns a symbolic representation for the hyperbolic tangent of C<$x>.
963              
964             =cut
965              
966             sub tanh {
967             my ($x) = _symbols(@_);
968             _new($x->tanh);
969             }
970              
971             =head2 sech
972              
973             $x->sech # => BigSym
974              
975             Returns a symbolic representation for the hyperbolic secant of C<$x>.
976              
977             =cut
978              
979             sub sech {
980             my ($x) = _symbols(@_);
981             _new($x->sech);
982             }
983              
984             =head2 csch
985              
986             $x->csch # => BigSym
987              
988             Returns a symbolic representation for the hyperbolic cosecant of C<$x>.
989              
990             =cut
991              
992             sub csch {
993             my ($x) = _symbols(@_);
994             _new($x->csch);
995             }
996              
997             =head2 coth
998              
999             $x->coth # => BigSym
1000              
1001             Returns a symbolic representation for the hyperbolic cotangent of C<$x>.
1002              
1003             =cut
1004              
1005             sub coth {
1006             my ($x) = _symbols(@_);
1007             _new($x->coth);
1008             }
1009              
1010             #
1011             ## Complex operations
1012             #
1013              
1014             =head2 conjugate
1015              
1016             ~$x # => BigSym
1017             $x->conjugate # => BigSym
1018              
1019             Returns the complex conjugate of C<$x>.
1020              
1021             =cut
1022              
1023             sub conjugate {
1024             my ($x) = _symbols(@_);
1025             _new($x->conjugate);
1026             }
1027              
1028             =head2 cross
1029              
1030             $x->cross(BigSym) # => BigSym
1031              
1032             Returns the complex cross product of C<$x> and C<$y>.
1033              
1034             =cut
1035              
1036             sub cross {
1037             my ($x, $y) = _symbols(@_);
1038             _new($x->cross($y));
1039             }
1040              
1041             =head2 dot
1042              
1043             $x->dot(BigSym) # => BigSym
1044              
1045             Returns the complex dot product of C<$x> and C<$y>.
1046              
1047             =cut
1048              
1049             sub dot {
1050             my ($x, $y) = _symbols(@_);
1051             _new($x->dot($y));
1052             }
1053              
1054             =head2 unit
1055              
1056             $x->unit # => BigSym
1057              
1058             Returns a complex number of unit length pointing in the same direction as C<$x>.
1059              
1060             =cut
1061              
1062             sub unit {
1063             my ($x) = _symbols(@_);
1064             _new($x->unit);
1065             }
1066              
1067             =head2 re
1068              
1069             $x->re # => BigSym
1070              
1071             Returns the real part of the complex number C<$x>.
1072              
1073             =cut
1074              
1075             sub re {
1076             my ($x) = _symbols(@_);
1077             _new($x->re);
1078             }
1079              
1080             =head2 im
1081              
1082             $x->im # => BigSym
1083              
1084             Returns the imaginary part of the complex number C<$x>.
1085              
1086             =cut
1087              
1088             sub im {
1089             my ($x) = _symbols(@_);
1090             _new($x->im);
1091             }
1092              
1093             #
1094             ## Comparisons
1095             #
1096              
1097             =head2 eq
1098              
1099             $x->eq(BigSym) # => Bool
1100             $x->eq(Scalar) # => Bool
1101              
1102             $x == $y # => Bool
1103              
1104             Equality check: returns a true value when C<$x> and C<$y> are equal.
1105              
1106             B expects C<$x> and C<$y> to have rational values.
1107             Symbolic representations, such as C, are treated literally.
1108              
1109             =cut
1110              
1111             sub eq {
1112             my ($x, $y) = _either(@_);
1113             ref($x) eq 'Math::GMPq' ? $x == $y : "$x" eq "$y";
1114             }
1115              
1116             =head2 ne
1117              
1118             $x->ne(BigSym) # => Bool
1119             $x->ne(Scalar) # => Bool
1120              
1121             $x != $y # => Bool
1122              
1123             Inequality check: returns a true value when C<$x> and C<$y> are not equal.
1124              
1125             B expects C<$x> and C<$y> to have rational values.
1126             Symbolic representations, such as C, are treated literally.
1127              
1128             =cut
1129              
1130             sub ne {
1131             my ($x, $y) = _either(@_);
1132             ref($x) eq 'Math::GMPq' ? $x != $y : "$x" ne "$y";
1133             }
1134              
1135             =head2 gt
1136              
1137             $x->gt(BigSym) # => Bool
1138             $x->gt(Scalar) # => Bool
1139              
1140             BigSym > BigSym # => Bool
1141             BigSym > Scalar # => Bool
1142             Scalar > BigSym # => Bool
1143              
1144             Returns a true value when C<$x> is greater than C<$y>.
1145              
1146             B expects C<$x> and C<$y> to have rational values.
1147             Symbolic representations, such as C, are treated literally.
1148              
1149             =cut
1150              
1151             sub gt {
1152             my ($x, $y) = _either(@_);
1153             ref($x) eq 'Math::GMPq' ? $x > $y : "$x" gt "$y";
1154             }
1155              
1156             =head2 ge
1157              
1158             $x->ge(BigSym) # => Bool
1159             $x->ge(Scalar) # => Bool
1160              
1161             BigSym >= BigSym # => Bool
1162             BigSym >= Scalar # => Bool
1163             Scalar >= BigSym # => Bool
1164              
1165             Returns a true value when C<$x> is equal or greater than C<$y>.
1166              
1167             B expects C<$x> and C<$y> to have rational values.
1168             Symbolic representations, such as C, are treated literally.
1169              
1170             =cut
1171              
1172             sub ge {
1173             my ($x, $y) = _either(@_);
1174             ref($x) eq 'Math::GMPq' ? $x >= $y : "$x" ge "$y";
1175             }
1176              
1177             =head2 lt
1178              
1179             $x->lt(BigSym) # => Bool
1180             $x->lt(Scalar) # => Bool
1181              
1182             BigSym < BigSym # => Bool
1183             BigSym < Scalar # => Bool
1184             Scalar < BigSym # => Bool
1185              
1186             Returns a true value when C<$x> is less than C<$y>.
1187              
1188             B expects C<$x> and C<$y> to have rational values.
1189             Symbolic representations, such as C, are treated literally.
1190              
1191             =cut
1192              
1193             sub lt {
1194             my ($x, $y) = _either(@_);
1195             ref($x) eq 'Math::GMPq' ? $x < $y : "$x" lt "$y";
1196             }
1197              
1198             =head2 le
1199              
1200             $x->le(BigSym) # => Bool
1201             $x->le(Scalar) # => Bool
1202              
1203             BigSym <= BigSym # => Bool
1204             BigSym <= Scalar # => Bool
1205             Scalar <= BigSym # => Bool
1206              
1207             Returns a true value when C<$x> is equal or less than C<$y>.
1208              
1209             B expects C<$x> and C<$y> to have rational values.
1210             Symbolic representations, such as C, are treated literally.
1211              
1212             =cut
1213              
1214             sub le {
1215             my ($x, $y) = _either(@_);
1216             ref($x) eq 'Math::GMPq' ? $x <= $y : "$x" le "$y";
1217             }
1218              
1219             =head2 cmp
1220              
1221             $x->cmp(BigSym) # => Scalar
1222             $x->cmp(Scalar) # => Scalar
1223              
1224             BigSym <=> BigSym # => Scalar
1225             BigSym <=> Scalar # => Scalar
1226             Scalar <=> BigSym # => Scalar
1227              
1228             Compares C<$x> to C<$y> and returns a negative value when C<$x> is less than C<$y>,
1229             0 when C<$x> and C<$y> are equal, and a positive value when C<$x> is greater than C<$y>.
1230              
1231             B expects C<$x> and C<$y> to have rational values.
1232             Symbolic representations, such as C, are treated literally.
1233              
1234             =cut
1235              
1236             sub cmp {
1237             my ($x, $y) = _either(@_);
1238             ref($x) eq 'Math::GMPq' ? $x <=> $y : "$x" cmp "$y";
1239             }
1240              
1241             =head1 AUTHOR
1242              
1243             Daniel Șuteu, C<< >>
1244              
1245             =head1 BUGS and LIMITATIONS
1246              
1247             Please report any bugs or feature requests to C, or through
1248             the web interface at L. I will be notified, and then you'll
1249             automatically be notified of progress on your bug as I make changes.
1250              
1251             The currently known issues are:
1252              
1253             =over 4
1254              
1255             =item * multiplication of logarithms is not currently supported by L.
1256              
1257             =item * there are some "division by zero" exceptions raised by L in some trigonometric functions.
1258              
1259             =item * integer operations, such as C<|>, C<&>, C<^>, C<<E>>>, C<<E>>>, are not supported.
1260              
1261             =item * the modulo operator (C<%>) is also not supported.
1262              
1263             =back
1264              
1265             =head1 SUPPORT
1266              
1267             You can find documentation for this module with the perldoc command.
1268              
1269             perldoc Math::BigSym
1270              
1271              
1272             You can also look for information at:
1273              
1274             =over 4
1275              
1276             =item * RT: CPAN's request tracker (report bugs here)
1277              
1278             L
1279              
1280             =item * AnnoCPAN: Annotated CPAN documentation
1281              
1282             L
1283              
1284             =item * CPAN Ratings
1285              
1286             L
1287              
1288             =item * Search CPAN
1289              
1290             L
1291              
1292             =item * GitHub
1293              
1294             L
1295              
1296             =back
1297              
1298              
1299             =head1 SEE ALSO
1300              
1301             L, L.
1302              
1303             =head1 LICENSE AND COPYRIGHT
1304              
1305             Copyright 2016 Daniel Șuteu.
1306              
1307             This program is free software; you can redistribute it and/or modify it
1308             under the terms of the the Artistic License (2.0). You may obtain a
1309             copy of the full license at:
1310              
1311             L
1312              
1313             Any use, modification, and distribution of the Standard or Modified
1314             Versions is governed by this Artistic License. By using, modifying or
1315             distributing the Package, you accept this license. Do not use, modify,
1316             or distribute the Package, if you do not accept this license.
1317              
1318             If your Modified Version has been derived from a Modified Version made
1319             by someone other than you, you are nevertheless required to ensure that
1320             your Modified Version complies with the requirements of this license.
1321              
1322             This license does not grant you the right to use any trademark, service
1323             mark, tradename, or logo of the Copyright Holder.
1324              
1325             This license includes the non-exclusive, worldwide, free-of-charge
1326             patent license to make, have made, use, offer to sell, sell, import and
1327             otherwise transfer the Package with respect to any patent claims
1328             licensable by the Copyright Holder that are necessarily infringed by the
1329             Package. If you institute patent litigation (including a cross-claim or
1330             counterclaim) against any party alleging that the Package constitutes
1331             direct or contributory patent infringement, then this Artistic License
1332             to you shall terminate on the date that such litigation is filed.
1333              
1334             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
1335             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
1336             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
1337             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
1338             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
1339             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
1340             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
1341             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1342              
1343              
1344             =cut
1345              
1346             1; # End of Math::BigSym