File Coverage

blib/lib/Math/GComplex.pm
Criterion Covered Total %
statement 505 586 86.1
branch 182 302 60.2
condition 46 110 41.8
subroutine 95 117 81.2
pod 78 78 100.0
total 906 1193 75.9


line stmt bran cond sub pod time code
1             package Math::GComplex;
2              
3 3     3   193845 use 5.010;
  3         27  
4 3     3   16 use strict;
  3         6  
  3         66  
5 3     3   13 use warnings;
  3         4  
  3         2019  
6              
7             our $VERSION = '0.13';
8              
9             use overload
10             '""' => \&stringify,
11             '0+' => \&numify,
12             bool => \&boolify,
13              
14             '+' => \&add,
15             '*' => \&mul,
16              
17             '==' => \&eq,
18             '!=' => \&ne,
19              
20             '~' => \&conj,
21             '&' => \&and,
22             '|' => \&or,
23             '^' => \&xor,
24              
25             '>>' => \&rsft,
26             '<<' => \&lsft,
27              
28 0 0   0   0 '>' => sub { $_[2] ? (goto <) : (goto >) },
29 0 0   0   0 '>=' => sub { $_[2] ? (goto &le) : (goto &ge) },
30 29 50   29   106 '<' => sub { $_[2] ? (goto >) : (goto <) },
31 2 50   2   9 '<=' => sub { $_[2] ? (goto &ge) : (goto &le) },
32              
33 0 0 0 0   0 '<=>' => sub { $_[2] ? -(&cmp($_[0], $_[1]) // return undef) : &cmp($_[0], $_[1]) },
34              
35 240 100   240   677 '/' => sub { @_ = ($_[1], $_[0]) if $_[2]; goto &div },
  240         594  
36 233 100   233   553 '-' => sub { @_ = ($_[1], $_[0]) if $_[2]; goto &sub },
  233         532  
37              
38 105 100   105   3754 '**' => sub { @_ = $_[2] ? @_[1, 0] : @_[0, 1]; goto &pow },
  105         264  
39 0 0   0   0 '%' => sub { @_ = $_[2] ? @_[1, 0] : @_[0, 1]; goto &mod },
  0         0  
40              
41 4 50   4   21 atan2 => sub { @_ = $_[2] ? @_[1, 0] : @_[0, 1]; goto &atan2 },
  4         15  
42              
43 29     29   6312 eq => sub { "$_[0]" eq "$_[1]" },
44 0     0   0 ne => sub { "$_[0]" ne "$_[1]" },
45              
46 0 0   0   0 cmp => sub { $_[2] ? ("$_[1]" cmp $_[0]->stringify) : ($_[0]->stringify cmp "$_[1]") },
47              
48 3         96 neg => \&neg,
49             sin => \&sin,
50             cos => \&cos,
51             exp => \&exp,
52             log => \&log,
53             int => \&int,
54             abs => \&abs,
55 3     3   3541 sqrt => \&sqrt;
  3         2770  
56              
57             {
58              
59             my %const = ( # prototypes are assigned in import()
60             i => \&i,
61             );
62              
63             my %trig = (
64 10     10   955 sin => sub (_) { goto &sin }, # built-in function
65             sinh => \&sinh,
66             asin => \&asin,
67             asinh => \&asinh,
68              
69 10     10   946 cos => sub (_) { goto &cos }, # built-in function
70             cosh => \&cosh,
71             acos => \&acos,
72             acosh => \&acosh,
73              
74             tan => \&tan,
75             tanh => \&tanh,
76             atan => \&atan,
77             atanh => \&atanh,
78              
79             cot => \&cot,
80             coth => \&coth,
81             acot => \&acot,
82             acoth => \&acoth,
83              
84             sec => \&sec,
85             sech => \&sech,
86             asec => \&asec,
87             asech => \&asech,
88              
89             csc => \&csc,
90             csch => \&csch,
91             acsc => \&acsc,
92             acsch => \&acsch,
93              
94 5     5   302 atan2 => sub ($$) { goto &atan2 }, # built-in function
95              
96             deg2rad => \°2rad,
97             rad2deg => \&rad2deg,
98             );
99              
100             my %special = (
101              
102 24     24   57 exp => sub (_) { goto &exp }, # built-in function
103 30     30   70 log => sub (_) { goto &log }, # built-in function
104 15     15   35 sqrt => sub (_) { goto &sqrt }, # built-in function
105              
106             cbrt => \&cbrt,
107             logn => \&logn,
108             root => \&root,
109             pow => \&pow,
110             pown => \&pown,
111              
112             gcd => \&gcd,
113             invmod => \&invmod,
114             powmod => \&powmod,
115             );
116              
117             my %misc = (
118              
119             acmp => \&acmp,
120             cplx => \&cplx,
121             polar => \&polar,
122              
123             abs => sub (_) { goto &abs }, # built-in function
124              
125             inv => \&inv,
126             sgn => \&sgn,
127             conj => \&conj,
128             norm => \&norm,
129              
130             real => \&real,
131             imag => \&imag,
132              
133             floor => \&floor,
134             ceil => \&ceil,
135             round => \&round,
136              
137             reals => \&reals,
138             );
139              
140             sub import {
141 3     3   23 shift;
142              
143 3         8 my $caller = caller(0);
144              
145 3         12 while (@_) {
146 46         67 my $name = shift(@_);
147              
148 46 100 100     159 if ($name eq ':overload') {
    100 66        
    100          
    100          
    50          
    50          
    0          
149             overload::constant
150 159     159   360 integer => sub { __PACKAGE__->new($_[0], 0) },
151 1     3   6 float => sub { __PACKAGE__->new($_[0], 0) };
  3         9  
152              
153             # Export the 'i' constant
154 1         37 foreach my $pair (['i', i()]) {
155 1         3 my $sub = $caller . '::' . $pair->[0];
156 3     3   2901 no strict 'refs';
  3         6  
  3         104  
157 3     3   18 no warnings 'redefine';
  3         4  
  3         256  
158 1         2 my $value = $pair->[1];
159 1     0   16 *$sub = sub () { $value };
  0         0  
160             }
161             }
162             elsif (exists $const{$name}) {
163 3     3   21 no strict 'refs';
  3         7  
  3         114  
164 3     3   18 no warnings 'redefine';
  3         6  
  3         341  
165 1         2 my $caller_sub = $caller . '::' . $name;
166 1         2 my $sub = $const{$name};
167 1         3 my $value = $sub->();
168 0     0   0 *$caller_sub = sub() { $value }
169 1         14 }
170             elsif ( exists($trig{$name})
171             or exists($special{$name})
172             or exists($misc{$name})) {
173 3     3   28 no strict 'refs';
  3         6  
  3         83  
174 3     3   30 no warnings 'redefine';
  3         7  
  3         22038  
175 42         71 my $caller_sub = $caller . '::' . $name;
176 42   66     219 *$caller_sub = $trig{$name} // $misc{$name} // $special{$name};
      33        
177             }
178             elsif ($name eq ':trig') {
179 1         12 push @_, keys(%trig);
180             }
181             elsif ($name eq ':misc') {
182 0         0 push @_, keys(%misc);
183             }
184             elsif ($name eq ':special') {
185 1         6 push @_, keys(%special);
186             }
187             elsif ($name eq ':all') {
188 0         0 push @_, keys(%const), keys(%trig), keys(%special), keys(%misc);
189             }
190             else {
191 0         0 die "unknown import: <<$name>>";
192             }
193             }
194 3         1022 return;
195             }
196              
197             sub unimport {
198 0     0   0 overload::remove_constant(float => '',
199             integer => '',);
200             }
201             }
202              
203             #
204             ## Be somewhat compatible with Math::Complex
205             #
206              
207             sub _cartesian {
208 0     0   0 my ($self) = @_;
209 0   0     0 $self->{cartesian} //= [$self->{a}, $self->{b}];
210             }
211              
212             sub _polar {
213 0     0   0 my ($self) = @_;
214 0   0     0 $self->{polar} //= [CORE::sqrt($self->{a} * $self->{a} + $self->{b} * $self->{b}), CORE::atan2($self->{b}, $self->{a})];
215             }
216              
217             #
218             ## Return the polar form
219             #
220              
221             sub polar {
222 0     0 1 0 my ($self) = @_;
223 0         0 @{$self->_polar};
  0         0  
224             }
225              
226             #
227             ## Create a new Math::GComplex object
228             #
229              
230             sub new {
231 4070     4070 1 7884 my ($class, $x, $y) = @_;
232              
233 4070   50     21605 bless {
      100        
234             a => $x // 0,
235             b => $y // 0,
236             }, $class;
237             }
238              
239             *make = \&new;
240              
241             #
242             ## cplx(a, b) = a + b*i
243             #
244              
245             sub cplx {
246 0     0 1 0 my ($x, $y) = @_;
247              
248 0   0     0 bless {
      0        
249             a => $x // 0,
250             b => $y // 0,
251             },
252             __PACKAGE__;
253             }
254              
255             sub emake {
256 0     0 1 0 my ($class, $r, $theta) = @_;
257              
258 0   0     0 bless {
      0        
      0        
      0        
259             a => ($r // 0) * CORE::cos($theta // 0),
260             b => ($r // 0) * CORE::sin($theta // 0),
261             }, $class;
262             }
263              
264             #
265             ## cplxe(r, theta) = r*cos(theta) + r*sin(theta)*i
266             #
267              
268             sub cplxe {
269 0     0 1 0 my ($r, $theta) = @_;
270              
271 0   0     0 bless {
      0        
      0        
      0        
272             a => ($r // 0) * CORE::cos($theta // 0),
273             b => ($r // 0) * CORE::sin($theta // 0),
274             },
275             __PACKAGE__;
276             }
277              
278             #
279             ## i = sqrt(-1)
280             #
281              
282             sub i {
283 2     2 1 6 __PACKAGE__->new(0, 1);
284             }
285              
286             #
287             ## (a + b*i) + (x + y*i) = (a + x) + (b + y)*i
288             #
289              
290             sub add {
291 131     131 1 5621 my ($x, $y) = @_;
292              
293 131 50       286 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
294 131 100       277 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
295              
296 131         358 __PACKAGE__->new($x->{a} + $y->{a}, $x->{b} + $y->{b});
297             }
298              
299             #
300             ## (a + b*i) - (x + y*i) = (a - x) + (b - y)*i
301             #
302              
303             sub sub {
304 468     468 1 770 my ($x, $y) = @_;
305              
306 468 100       900 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
307 468 100       927 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
308              
309 468         1130 __PACKAGE__->new($x->{a} - $y->{a}, $x->{b} - $y->{b});
310             }
311              
312             #
313             ## (a + b*i) * (x + y*i) = i*(a*y + b*x) + a*x - b*y
314             #
315              
316             sub mul {
317 640     640 1 4667 my ($x, $y) = @_;
318              
319 640 50       1211 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
320 640 100       1119 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
321              
322 640         1798 __PACKAGE__->new($x->{a} * $y->{a} - $x->{b} * $y->{b}, $x->{a} * $y->{b} + $x->{b} * $y->{a});
323             }
324              
325             #
326             ## (a + b*i) / (x + y*i) = (a*x + b*y)/(x*x + y*y) + (b*x - a*y)/(x*x + y*y) * i
327             #
328              
329             sub div {
330 563     563 1 1364 my ($x, $y) = @_;
331              
332 563 100       1103 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
333 563 100       1101 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
334              
335 563         1159 my $d = $y->{a} * $y->{a} + $y->{b} * $y->{b};
336              
337 563 50       992 if ($d == 0) {
338 0         0 return $x->log->sub($y->log)->exp;
339             }
340              
341 563         1726 __PACKAGE__->new(($x->{a} * $y->{a} + $x->{b} * $y->{b}) / $d, ($x->{b} * $y->{a} - $x->{a} * $y->{b}) / $d);
342             }
343              
344             #
345             ## mod(x, y) = x - y*floor(x/y)
346             #
347              
348             sub mod {
349 139     139 1 226 my ($x, $y) = @_;
350              
351 139 50       248 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
352 139 50       236 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
353              
354 139         236 $x->sub($x->div($y)->floor->mul($y));
355             }
356              
357             #
358             ## inv(x) = 1/x
359             #
360              
361             sub inv ($) {
362 37     37 1 76 my ($x) = @_;
363              
364 37         56 state $one = __PACKAGE__->new(1, 0);
365              
366 37         94 $one->div($x);
367             }
368              
369             #
370             ## abs(a + b*i) = sqrt(a^2 + b^2)
371             #
372              
373             sub abs {
374 203     203 1 391 my ($x) = @_;
375              
376 203 50       441 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
377              
378 203         695 CORE::sqrt($x->{a} * $x->{a} + $x->{b} * $x->{b});
379             }
380              
381             #
382             ## sgn(a + b*i) = (a + b*i) / abs(a + b*i)
383             #
384              
385             sub sgn ($) {
386 0     0 1 0 my ($x) = @_;
387              
388 0 0       0 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
389              
390 0 0 0     0 if ($x->{a} == 0 and $x->{b} == 0) {
391 0         0 return __PACKAGE__->new(0, 0);
392             }
393              
394 0         0 $x->div($x->abs);
395             }
396              
397             #
398             ## neg(a + b*i) = -a - b*i
399             #
400              
401             sub neg {
402 38     38 1 78 my ($x) = @_;
403              
404 38 50       88 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
405              
406 38         93 __PACKAGE__->new(-$x->{a}, -$x->{b});
407             }
408              
409             #
410             ## conj(a + b*i) = a - b*i
411             #
412              
413             sub conj ($) {
414 6     6 1 11 my ($x) = @_;
415              
416 6 50       13 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
417              
418 6         15 __PACKAGE__->new($x->{a}, -$x->{b});
419             }
420              
421             #
422             ## norm(a + b*i) = a**2 + b**2
423             #
424              
425             sub norm ($) {
426 0     0 1 0 my ($x) = @_;
427              
428 0 0       0 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
429              
430 0         0 $x->{a} * $x->{a} + $x->{b} * $x->{b};
431             }
432              
433             #
434             ## (a+b*i) AND (x+y*i) = (a AND x) + (b AND y)*i
435             #
436              
437             sub and {
438 1     1 1 3 my ($x, $y) = @_;
439              
440 1 50       5 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
441 1 50       4 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
442              
443 1         5 __PACKAGE__->new($x->{a} & $y->{a}, $x->{b} & $y->{b});
444             }
445              
446             #
447             ## (a+b*i) OR (x+y*i) = (a OR x) + (b OR y)*i
448             #
449              
450             sub or {
451 1     1 1 4 my ($x, $y) = @_;
452              
453 1 50       4 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
454 1 50       4 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
455              
456 1         6 __PACKAGE__->new($x->{a} | $y->{a}, $x->{b} | $y->{b});
457             }
458              
459             #
460             ## (a+b*i) XOR (x+y*i) = (a XOR x) + (b XOR y)*i
461             #
462              
463             sub xor {
464 1     1 1 3 my ($x, $y) = @_;
465              
466 1 50       5 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
467 1 50       4 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
468              
469 1         5 __PACKAGE__->new($x->{a} ^ $y->{a}, $x->{b} ^ $y->{b});
470             }
471              
472             #
473             ## (a+b*i) << n = (a << n) + (b << n)*i
474             ## (a+b*i) << (x+y*i) = int((a+b*i) * 2^(x+y*i))
475             #
476              
477             sub lsft {
478 1     1 1 4 my ($x, $y) = @_;
479              
480 1 50       4 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
481 1 50       4 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
482              
483 1 50       4 if ($y->{b} == 0) {
484 1         4 return __PACKAGE__->new($x->{a} << $y->{a}, $x->{b} << $y->{a});
485             }
486              
487 0         0 state $two = __PACKAGE__->new(2, 0);
488 0         0 $x->mul($two->pow($y))->int;
489             }
490              
491             #
492             ## (a+b*i) >> n = (a >> n) + (b >> n)*i
493             ## (a+b*i) >> (x+y*i) = int((a+b*i) / 2^(x+y*i))
494             #
495              
496             sub rsft {
497 1     1 1 308 my ($x, $y) = @_;
498              
499 1 50       5 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
500 1 50       4 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
501              
502 1 50       4 if ($y->{b} == 0) {
503 1         4 return __PACKAGE__->new($x->{a} >> $y->{a}, $x->{b} >> $y->{a});
504             }
505              
506 0         0 state $two = __PACKAGE__->new(2, 0);
507 0         0 $x->div($two->pow($y))->int;
508             }
509              
510             #
511             ## log(a + b*i) = log(a^2 + b^2)/2 + atan2(b, a)*i -- where a,b are real
512             #
513              
514             sub log {
515 409     409 1 662 my ($x) = @_;
516              
517 409 50       783 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
518              
519 409         808 my $t = $x->{a} * $x->{a} + $x->{b} * $x->{b};
520              
521 409 50 66     1334 if (!ref($t) and $t == 0) {
522 0         0 return __PACKAGE__->new(0 + '-Inf', 0);
523             }
524              
525 409         1230 __PACKAGE__->new(CORE::log($t) / 2, CORE::atan2($x->{b}, $x->{a}));
526             }
527              
528             #
529             ## logn(x, n) = log(x) / log(n)
530             #
531              
532             sub logn ($$) {
533 3     3 1 8 my ($x, $n) = @_;
534              
535 3 50       11 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
536 3 50       7 $n = __PACKAGE__->new($n) if ref($n) ne __PACKAGE__;
537              
538 3         8 $x->log->div($n->log);
539             }
540              
541             #
542             ## exp(a + b*i) = exp(a)*cos(b) + exp(a)*sin(b)*i
543             #
544              
545             sub exp {
546 486     486 1 818 my ($x) = @_;
547              
548 486 50       933 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
549              
550 486         971 my $exp = CORE::exp($x->{a});
551              
552 486         1400 __PACKAGE__->new($exp * CORE::cos($x->{b}), $exp * CORE::sin($x->{b}));
553             }
554              
555             #
556             ## x^y = exp(log(x) * y)
557             #
558              
559             sub pow ($$) {
560 108     108 1 188 my ($x, $y) = @_;
561              
562 108 100       239 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
563 108 100       232 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
564              
565 108 50 66     257 if ($x->{a} == 0 and $x->{b} == 0) {
566              
567 0 0       0 if ($y->{a} < 0) {
568 0         0 return $x->inv;
569             }
570              
571 0 0 0     0 if ($y->{a} == 0 and $y->{b} == 0) {
572 0         0 return __PACKAGE__->new($x->{a} + 1, $x->{b});
573             }
574              
575 0         0 return $x;
576             }
577              
578 108         242 $x->log->mul($y)->exp;
579             }
580              
581             #
582             ## x^n using the exponentiation by squaring method
583             #
584              
585             sub pown ($$) {
586 17     17 1 541 my ($x, $y) = @_;
587              
588 17 50       44 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
589              
590 17         40 $y = CORE::int($y);
591 17         36 my $neg = $y < 0;
592 17         40 $y = CORE::int(CORE::abs($y));
593              
594 17 100 100     75 if ($x->{a} == 0 and $x->{b} == 0) {
595              
596 2 50       5 if ($neg) {
597 0         0 return $x->inv;
598             }
599              
600 2 100       5 if ($y == 0) {
601 1         4 return __PACKAGE__->new($x->{a} + 1, $x->{b});
602             }
603              
604 1         5 return $x;
605             }
606              
607 15         25 my ($rx, $ry) = (1, 0);
608 15         22 my ($ax, $bx) = (@{$x}{qw(a b)});
  15         33  
609              
610 15         19 while (1) {
611 42 100       94 ($rx, $ry) = ($rx * $ax - $ry * $bx, $rx * $bx + $ry * $ax) if ($y & 1);
612 42 100       73 ($y >>= 1) or last;
613 27         53 ($ax, $bx) = ($ax * $ax - $bx * $bx, $ax * $bx + $bx * $ax);
614             }
615              
616 15 100       38 $neg ? __PACKAGE__->new($rx, $ry)->inv : __PACKAGE__->new($rx, $ry);
617             }
618              
619             #
620             ## Greatest common divisor
621             #
622              
623             sub gcd ($$) {
624 8     8 1 15 my ($n, $k) = @_;
625              
626 8 50       18 $n = __PACKAGE__->new($n) if ref($n) ne __PACKAGE__;
627 8 50       15 $k = __PACKAGE__->new($k) if ref($k) ne __PACKAGE__;
628              
629 8         22 my $norm_n = $n->{a} * $n->{a} + $n->{b} * $n->{b};
630 8         19 my $norm_k = $k->{a} * $k->{a} + $k->{b} * $k->{b};
631              
632 8 100       18 if ($norm_n > $norm_k) {
633 2         4 ($n, $k) = ($k, $n);
634             }
635              
636 8   100     23 while (!($k->{a} == 0 and $k->{b} == 0)) {
637              
638 38         70 my $q = $n->div($k)->round;
639 38         97 my $r = $n->sub($q->mul($k));
640              
641 38         160 ($n, $k) = ($k, $r);
642             }
643              
644 8         22 $n;
645             }
646              
647             #
648             ## Modular multiplicative inverse: 1/x (mod m)
649             #
650              
651             sub invmod ($$) {
652 6     6 1 354 my ($x, $m) = @_;
653              
654 6 50       20 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
655 6 50       14 $m = __PACKAGE__->new($m) if ref($m) ne __PACKAGE__;
656              
657 6         13 my $g = $x->gcd($m);
658              
659 6 50       15 $g->abs == 1 or return undef;
660              
661 6         10 state $zero = __PACKAGE__->new(0, 0);
662              
663             my $inverse = sub {
664 6     6   12 my ($x, $m, $k) = @_;
665              
666 6         10 my ($u, $w) = ($k, $zero);
667 6         8 my ($q, $r);
668              
669 6         10 my $c = $m;
670              
671 6   100     14 while (!($c->{a} == 0 and $c->{b} == 0)) {
672              
673 29         49 $q = $x->div($c)->round;
674 29         65 $r = $x->sub($q->mul($c));
675              
676 29         62 ($x, $c) = ($c, $r);
677 29         50 ($u, $w) = ($w, $u->sub($q->mul($w)));
678             }
679              
680 6         16 return $u;
681 6         33 };
682              
683 6         11 state $one = __PACKAGE__->new(1, 0);
684 6         10 state $mone = __PACKAGE__->new(-1, 0);
685              
686 6         9 state $i = __PACKAGE__->new(0, 1);
687 6         24 state $mi = __PACKAGE__->new(0, -1);
688              
689 6         13 foreach my $k ($g->conj, $one, $mone, $i, $mi) {
690              
691 6         13 my $inv = $inverse->($x, $m, $k);
692 6         13 my $t = $x->mul($inv)->mod($m);
693              
694 6 50 33     43 if ($t->{a} == 1 and $t->{b} == 0) {
695 6         15 return $inv->mod($m);
696             }
697             }
698              
699 0         0 return undef;
700             }
701              
702             #
703             ## x^n mod m using the exponentiation by squaring method
704             #
705              
706             sub powmod ($$$) {
707 13     13 1 338 my ($x, $y, $m) = @_;
708              
709 13 50       38 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
710 13 50       40 $m = __PACKAGE__->new($m) if ref($m) ne __PACKAGE__;
711              
712 13         36 $y = CORE::int($y);
713 13         28 my $neg = $y < 0;
714 13         29 $y = CORE::int(CORE::abs($y));
715              
716 13 50 66     48 if ($x->{a} == 0 and $x->{b} == 0) {
717              
718 0 0       0 if ($neg) {
719 0         0 return $x->invmod($m);
720             }
721              
722 0 0       0 if ($y == 0) {
723 0         0 return __PACKAGE__->new($x->{a} + 1, $x->{b})->mod($m);
724             }
725              
726 0         0 return $x->mod($m);
727             }
728              
729 13 100       26 $x = $x->invmod($m) if $neg;
730 13   50     25 $x // return undef;
731              
732 13         31 my $r = __PACKAGE__->new(1, 0);
733              
734 13         19 while (1) {
735 83 100       196 $r = $r->mul($x)->mod($m) if ($y & 1);
736 83 100       193 ($y >>= 1) or last;
737 70         113 $x = $x->mul($x)->mod($m);
738             }
739              
740 13         23 $r->mod($m);
741             }
742              
743             #
744             ## root(x, y) = exp(log(x) / y)
745             #
746              
747             sub root ($$) {
748 3     3 1 8 my ($x, $y) = @_;
749              
750 3 50       9 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
751 3 50       10 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
752              
753 3         12 $x->pow($y->inv);
754             }
755              
756             #
757             ## sqrt(a + b*i) = exp(log(a + b*i) / 2)
758             #
759              
760             sub sqrt {
761 133     133 1 246 my ($x) = @_;
762              
763 133 50       270 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
764              
765 133         242 my $r = $x->log;
766              
767 133         254 $r->{a} /= 2;
768 133         183 $r->{b} /= 2;
769              
770 133         254 $r->exp;
771             }
772              
773             #
774             ## cbrt(a + b*i) = exp(log(a + b*i) / 3)
775             #
776              
777             sub cbrt ($) {
778 6     6 1 1773 my ($x) = @_;
779              
780 6 50       18 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
781              
782 6 50 33     21 if ($x->{a} == 0 and $x->{b} == 0) {
783 0         0 return __PACKAGE__->new(0, 0);
784             }
785              
786 6         14 my $r = $x->log;
787              
788 6         15 $r->{a} /= 3;
789 6         12 $r->{b} /= 3;
790              
791 6         13 $r->exp;
792             }
793              
794             #
795             ## int(a + b*i) = int(a) + int(b)*i
796             #
797              
798             sub int {
799 29     29 1 50 my ($x) = @_;
800              
801 29 50       67 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
802              
803 29         66 my $t1 = CORE::int($x->{a});
804 29         37 my $t2 = CORE::int($x->{b});
805              
806 29         67 __PACKAGE__->new($t1, $t2);
807             }
808              
809             #
810             ## round to the nearest Gaussian integer
811             #
812              
813             sub _round ($) {
814 134     134   221 my ($n) = @_;
815 134 100       316 CORE::int(($n + $n + (($n < 0) ? -1 : 1)) / 2);
816             }
817              
818             sub round ($) {
819 67     67 1 98 my ($x) = @_;
820 67 50       123 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
821 67         102 __PACKAGE__->new(_round($x->{a}), _round($x->{b}));
822             }
823              
824             #
825             ## floor(a + b*i) = floor(a) + floor(b)*i
826             #
827              
828             sub floor ($) {
829 139     139 1 209 my ($x) = @_;
830              
831 139 50       248 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
832              
833 139         222 my $t1 = CORE::int($x->{a});
834 139 100 100     425 $t1 -= 1 if ($x->{a} != $t1 and $x->{a} < 0);
835              
836 139         191 my $t2 = CORE::int($x->{b});
837 139 100 100     355 $t2 -= 1 if ($x->{b} != $t2 and $x->{b} < 0);
838              
839 139         220 __PACKAGE__->new($t1, $t2);
840             }
841              
842             #
843             ## ceil(a + b*i) = -floor(-(a + b*i))
844             #
845              
846             sub ceil ($) {
847 0     0 1 0 my ($x) = @_;
848              
849 0 0       0 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
850              
851 0         0 my $t = $x->neg->floor;
852              
853 0         0 $t->{a} = -$t->{a};
854 0         0 $t->{b} = -$t->{b};
855              
856 0         0 $t;
857             }
858              
859             ########################################################################
860             # SIN / SINH / ASIN / ASINH
861             ########################################################################
862              
863             #
864             ## sin(a + b*i) = i*(exp(b - i*a) - exp(-b + i*a))/2
865             #
866              
867             sub sin {
868 11     11 1 22 my ($x) = @_;
869              
870 11 100       41 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
871              
872 11         64 my $t1 = __PACKAGE__->new(+$x->{b}, -$x->{a})->exp;
873 11         40 my $t2 = __PACKAGE__->new(-$x->{b}, +$x->{a})->exp;
874              
875 11         30 $t1->{a} -= $t2->{a};
876 11         18 $t1->{b} -= $t2->{b};
877              
878 11         22 $t1->{a} /= 2;
879 11         42 $t1->{b} /= 2;
880              
881 11         38 @{$t1}{qw(a b)} = (-$t1->{b}, $t1->{a});
  11         27  
882              
883 11         72 $t1;
884             }
885              
886             #
887             ## sinh(a + b*i) = (exp(2 * (a + b*i)) - 1) / (2*exp(a + b*i))
888             #
889              
890             sub sinh ($) {
891 13     13 1 595 my ($x) = @_;
892              
893 13 100       44 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
894              
895 13         42 my $t1 = __PACKAGE__->new($x->{a} * 2, $x->{b} * 2)->exp;
896              
897 13         33 $t1->{a} -= 1;
898              
899 13         26 my $t2 = $x->exp;
900              
901 13         26 $t2->{a} *= 2;
902 13         18 $t2->{b} *= 2;
903              
904 13         27 $t1->div($t2);
905             }
906              
907             #
908             ## asin(a + b*i) = -i*log(sqrt(1 - (a + b*i)^2) + i*a - b)
909             #
910              
911             sub asin ($) {
912 12     12 1 306 my ($x) = @_;
913              
914 12 100       31 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
915              
916 12         51 my $r = __PACKAGE__->new(1 - ($x->{a} * $x->{a} - $x->{b} * $x->{b}), -($x->{a} * $x->{b} + $x->{b} * $x->{a}))->sqrt;
917              
918 12         27 $r->{a} -= $x->{b};
919 12         20 $r->{b} += $x->{a};
920              
921 12         26 $r = $r->log;
922 12         26 @{$r}{qw(a b)} = ($r->{b}, -$r->{a});
  12         21  
923 12         44 $r;
924             }
925              
926             #
927             ## asinh(a + b*i) = log(sqrt((a + b*i)^2 + 1) + (a + b*i))
928             #
929              
930             sub asinh ($) {
931 12     12 1 300 my ($x) = @_;
932              
933 12 100       29 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
934              
935 12         50 my $r = __PACKAGE__->new($x->{a} * $x->{a} - $x->{b} * $x->{b} + 1, $x->{a} * $x->{b} + $x->{b} * $x->{a})->sqrt;
936              
937 12         26 $r->{a} += $x->{a};
938 12         17 $r->{b} += $x->{b};
939              
940 12         22 $r->log;
941             }
942              
943             ########################################################################
944             # COS / COSH / ACOS / ACOSH
945             ########################################################################
946              
947             #
948             ## cos(a + b*i) = (exp(-b + i*a) + exp(b - i*a))/2
949             #
950              
951             sub cos {
952 20     20 1 43 my ($x) = @_;
953              
954 20 100       48 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
955              
956 20         51 my $t1 = __PACKAGE__->new(-$x->{b}, +$x->{a})->exp;
957 20         61 my $t2 = __PACKAGE__->new(+$x->{b}, -$x->{a})->exp;
958              
959 20         43 $t1->{a} += $t2->{a};
960 20         34 $t1->{b} += $t2->{b};
961              
962 20         34 $t1->{a} /= 2;
963 20         32 $t1->{b} /= 2;
964              
965 20         61 $t1;
966             }
967              
968             #
969             ## cosh(a + b*i) = (exp(2 * (a + b*i)) + 1) / (2*exp(a + b*i))
970             #
971              
972             sub cosh ($) {
973 21     21 1 923 my ($x) = @_;
974              
975 21 100       56 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
976              
977 21         59 my $t1 = __PACKAGE__->new($x->{a} * 2, $x->{b} * 2)->exp;
978              
979 21         53 $t1->{a} += 1;
980              
981 21         47 my $t2 = $x->exp;
982              
983 21         36 $t2->{a} *= 2;
984 21         34 $t2->{b} *= 2;
985              
986 21         44 $t1->div($t2);
987             }
988              
989             #
990             ## acos(a + b*i) = -2*i*log(i*sqrt((1 - (a + b*i))/2) + sqrt((1 + (a + b*i))/2))
991             #
992              
993             sub acos ($) {
994 20     20 1 4247 my ($x) = @_;
995              
996 20 50       54 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
997              
998 20         74 my $t1 = __PACKAGE__->new((1 - $x->{a}) / 2, $x->{b} / -2)->sqrt;
999 20         79 my $t2 = __PACKAGE__->new((1 + $x->{a}) / 2, $x->{b} / +2)->sqrt;
1000              
1001 20         54 @{$t1}{qw(a b)} = (-$t1->{b}, $t1->{a});
  20         46  
1002              
1003 20         39 $t1->{a} += $t2->{a};
1004 20         30 $t1->{b} += $t2->{b};
1005              
1006 20         38 my $r = $t1->log;
1007              
1008 20         37 $r->{a} *= -2;
1009 20         31 $r->{b} *= -2;
1010              
1011 20         36 @{$r}{qw(a b)} = (-$r->{b}, $r->{a});
  20         40  
1012              
1013 20         82 $r;
1014             }
1015              
1016             #
1017             ## acosh(a + b*i) = log((a + b*i) + sqrt((a + b*i) - 1) * sqrt((a + b*i) + 1))
1018             #
1019              
1020             sub acosh ($) {
1021 10     10 1 35 my ($x) = @_;
1022              
1023 10 50       28 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1024              
1025 10         32 my $t1 = __PACKAGE__->new($x->{a} - 1, $x->{b})->sqrt;
1026 10         30 my $t2 = __PACKAGE__->new($x->{a} + 1, $x->{b})->sqrt;
1027              
1028 10         28 my $t3 = $t1->mul($t2);
1029              
1030 10         20 $t3->{a} += $x->{a};
1031 10         17 $t3->{b} += $x->{b};
1032              
1033 10         30 $t3->log;
1034             }
1035              
1036             ########################################################################
1037             # TAN / TANH / ATAN / ATANH
1038             ########################################################################
1039              
1040             #
1041             ## tan(a + b*i) = (2*i)/(exp(2*i*(a + b*i)) + 1) - i
1042             #
1043              
1044             sub tan ($) {
1045 10     10 1 1170 my ($x) = @_;
1046              
1047 10 100       33 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1048              
1049 10         34 my $r = __PACKAGE__->new(-2 * $x->{b}, 2 * $x->{a})->exp;
1050              
1051 10         30 $r->{a} += 1;
1052              
1053 10         24 my $den = $r->{a} * $r->{a} + $r->{b} * $r->{b};
1054              
1055 10         16 $r->{a} *= 2;
1056 10         16 $r->{b} *= 2;
1057              
1058 10 50 33     43 if (!ref($den) and $den == 0) {
1059 0         0 $r = $r->div($den);
1060             }
1061             else {
1062 10         17 $r->{a} /= $den;
1063 10         16 $r->{b} /= $den;
1064             }
1065              
1066 10         18 $r->{a} -= 1;
1067              
1068 10         18 @{$r}{qw(a b)} = ($r->{b}, $r->{a});
  10         22  
1069              
1070 10         65 $r;
1071             }
1072              
1073             #
1074             ## tanh(a + b*i) = (exp(2 * (a + b*i)) - 1) / (exp(2 * (a + b*i)) + 1)
1075             #
1076              
1077             sub tanh ($) {
1078 13     13 1 884 my ($x) = @_;
1079              
1080 13 100       43 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1081              
1082 13         47 my $t1 = __PACKAGE__->new($x->{a} * 2, $x->{b} * 2)->exp;
1083              
1084 13         45 my $t2 = __PACKAGE__->new($t1->{a} - 1, $t1->{b});
1085 13         33 my $t3 = __PACKAGE__->new($t1->{a} + 1, $t1->{b});
1086              
1087 13         32 $t2->div($t3);
1088             }
1089              
1090             #
1091             ## atan(a + b*i) = i * (log(1 - i*(a + b*i)) - log(1 + i*(a + b*i))) / 2
1092             #
1093              
1094             sub atan ($) {
1095 16     16 1 696 my ($x) = @_;
1096              
1097 16 100       46 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1098              
1099 16         47 my $t1 = __PACKAGE__->new(+$x->{b} + 1, -$x->{a})->log;
1100 16         91 my $t2 = __PACKAGE__->new(-$x->{b} + 1, +$x->{a})->log;
1101              
1102 16         41 $t1->{a} -= $t2->{a};
1103 16         24 $t1->{b} -= $t2->{b};
1104              
1105 16         25 $t1->{a} /= 2;
1106 16         25 $t1->{b} /= 2;
1107              
1108 16         31 @{$t1}{qw(a b)} = (-$t1->{b}, $t1->{a});
  16         31  
1109              
1110 16         60 $t1;
1111             }
1112              
1113             #
1114             ## atan2(a, b) = -i * log((b + a*i) / sqrt(a^2 + b^2))
1115             #
1116              
1117             sub atan2 {
1118 9     9 1 17 my ($x, $y) = @_;
1119              
1120 9 100       33 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1121 9 100       35 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
1122              
1123 9         34 my $t = __PACKAGE__->new($y->{a} - $x->{b}, $x->{a} + $y->{b});
1124              
1125 9         27 $t = $t->div($x->mul($x)->add($y->mul($y))->sqrt)->log;
1126              
1127 9         38 @{$t}{qw(a b)} = ($t->{b}, -$t->{a});
  9         24  
1128              
1129 9         151 $t;
1130             }
1131              
1132             #
1133             ## atanh(a + b*i) = (log(1 + (a + b*i)) - log(1 - (a + b*i))) / 2
1134             #
1135              
1136             sub atanh ($) {
1137 14     14 1 313 my ($x) = @_;
1138              
1139 14 100       38 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1140              
1141 14         36 my $t1 = __PACKAGE__->new(1 + $x->{a}, +$x->{b})->log;
1142 14         49 my $t2 = __PACKAGE__->new(1 - $x->{a}, -$x->{b})->log;
1143              
1144 14         46 $t1->{a} -= $t2->{a};
1145 14         21 $t1->{b} -= $t2->{b};
1146              
1147 14         21 $t1->{a} /= 2;
1148 14         22 $t1->{b} /= 2;
1149              
1150 14         47 $t1;
1151             }
1152              
1153             ########################################################################
1154             # COT / COTH / ACOT / ACOTH
1155             ########################################################################
1156              
1157             #
1158             ## cot(a + b*i) = (2*i)/(exp(2*i*(a + b*i)) - 1) + i
1159             #
1160              
1161             sub cot ($) {
1162 6     6 1 604 my ($x) = @_;
1163              
1164 6 100       22 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1165              
1166 6         26 my $r = __PACKAGE__->new(-2 * $x->{b}, 2 * $x->{a})->exp;
1167              
1168 6         59 $r->{a} -= 1;
1169              
1170 6         16 my $den = $r->{a} * $r->{a} + $r->{b} * $r->{b};
1171              
1172 6         11 $r->{a} *= 2;
1173 6         9 $r->{b} *= 2;
1174              
1175 6 50 33     30 if (!ref($den) and $den == 0) {
1176 0         0 $r = $r->div($den);
1177             }
1178             else {
1179 6         10 $r->{a} /= $den;
1180 6         11 $r->{b} /= $den;
1181             }
1182              
1183 6         11 $r->{a} += 1;
1184              
1185 6         12 @{$r}{qw(a b)} = ($r->{b}, $r->{a});
  6         15  
1186              
1187 6         22 $r;
1188             }
1189              
1190             #
1191             ## coth(a + b*i) = (exp(2 * (a + b*i)) + 1) / (exp(2 * (a + b*i)) - 1)
1192             #
1193              
1194             sub coth ($) {
1195 7     7 1 869 my ($x) = @_;
1196              
1197 7 100       32 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1198              
1199 7         24 my $t1 = __PACKAGE__->new($x->{a} * 2, $x->{b} * 2)->exp;
1200              
1201 7         27 my $t2 = __PACKAGE__->new($t1->{a} + 1, $t1->{b});
1202 7         19 my $t3 = __PACKAGE__->new($t1->{a} - 1, $t1->{b});
1203              
1204 7         20 $t2->div($t3);
1205             }
1206              
1207             #
1208             ## acot(a + b*i) = atan(1/(a + b*i))
1209             #
1210              
1211             sub acot ($) {
1212 8     8 1 305 my ($x) = @_;
1213              
1214 8 100       29 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1215              
1216 8         22 $x->inv->atan;
1217             }
1218              
1219             #
1220             ## acoth(a + b*i) = atanh(1 / (a + b*i))
1221             #
1222              
1223             sub acoth ($) {
1224 7     7 1 291 my ($x) = @_;
1225              
1226 7 100       23 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1227              
1228 7         23 $x->inv->atanh;
1229             }
1230              
1231             ########################################################################
1232             # SEC / SECH / ASEC / ASECH
1233             ########################################################################
1234              
1235             #
1236             ## sec(a + b*i) = 2/(exp(-i*(a + b*i)) + exp(i*(a + b*i)))
1237             #
1238              
1239             sub sec ($) {
1240 5     5 1 614 my ($x) = @_;
1241              
1242 5 100       20 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1243              
1244 5         19 my $t1 = __PACKAGE__->new(+$x->{b}, -$x->{a})->exp;
1245 5         21 my $t2 = __PACKAGE__->new(-$x->{b}, +$x->{a})->exp;
1246              
1247 5         15 $t1->{a} += $t2->{a};
1248 5         10 $t1->{b} += $t2->{b};
1249              
1250 5         27 my $den = $t1->{a} * $t1->{a} + $t1->{b} * $t1->{b};
1251              
1252 5         8 $t1->{a} *= +2;
1253 5         10 $t1->{b} *= -2;
1254              
1255 5 50 33     31 if (!ref($den) and $den == 0) {
1256 0         0 $t1 = $t1->div($den);
1257             }
1258             else {
1259 5         9 $t1->{a} /= $den;
1260 5         8 $t1->{b} /= $den;
1261             }
1262              
1263 5         18 $t1;
1264             }
1265              
1266             #
1267             ## sech(a + b*i) = (2 * exp(a + b*i)) / (exp(2 * (a + b*i)) + 1)
1268             #
1269              
1270             sub sech ($) {
1271 7     7 1 1131 my ($x) = @_;
1272              
1273 7 100       28 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1274              
1275 7         20 my $t1 = $x->exp;
1276 7         22 my $t2 = __PACKAGE__->new($x->{a} * 2, $x->{b} * 2)->exp;
1277              
1278 7         18 $t1->{a} *= 2;
1279 7         13 $t1->{b} *= 2;
1280              
1281 7         12 $t2->{a} += 1;
1282              
1283 7         17 $t1->div($t2);
1284             }
1285              
1286             #
1287             ## asec(a + b*i) = acos(1/(a + b*i))
1288             #
1289              
1290             sub asec ($) {
1291 4     4 1 10 my ($x) = @_;
1292              
1293 4 50       14 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1294              
1295 4         22 $x->inv->acos;
1296             }
1297              
1298             #
1299             ## asech(a + b*i) = acosh(1/(a + b*i))
1300             #
1301              
1302             sub asech ($) {
1303 4     4 1 312 my ($x) = @_;
1304              
1305 4 100       18 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1306              
1307 4         10 $x->inv->acosh;
1308             }
1309              
1310             ########################################################################
1311             # CSC / CSCH / ACSC / ACSCH
1312             ########################################################################
1313              
1314             #
1315             ## csc(a + b*i) = -(2*i)/(exp(-i * (a + b*i)) - exp(i * (a + b*i)))
1316             #
1317              
1318             sub csc ($) {
1319 5     5 1 590 my ($x) = @_;
1320              
1321 5 100       23 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1322              
1323 5         19 my $t1 = __PACKAGE__->new(+$x->{b}, -$x->{a})->exp;
1324 5         22 my $t2 = __PACKAGE__->new(-$x->{b}, +$x->{a})->exp;
1325              
1326 5         17 $t1->{a} -= $t2->{a};
1327 5         15 $t1->{b} -= $t2->{b};
1328              
1329 5         13 my $den = $t1->{a} * $t1->{a} + $t1->{b} * $t1->{b};
1330              
1331 5         9 $t1->{a} *= -2;
1332 5         9 $t1->{b} *= -2;
1333              
1334 5 50 33     45 if (!ref($den) and $den == 0) {
1335 0         0 $t1 = $t1->div($den);
1336             }
1337             else {
1338 5         11 $t1->{a} /= $den;
1339 5         10 $t1->{b} /= $den;
1340             }
1341              
1342 5         10 @{$t1}{qw(a b)} = ($t1->{b}, $t1->{a});
  5         12  
1343              
1344 5         21 $t1;
1345             }
1346              
1347             #
1348             ## csch(a + b*i) = (2*exp(a + b*i)) / (exp(2 * (a + b*i)) - 1)
1349             #
1350              
1351             sub csch ($) {
1352 7     7 1 860 my ($x) = @_;
1353              
1354 7 100       30 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1355              
1356 7         29 my $t1 = $x->exp;
1357 7         26 my $t2 = __PACKAGE__->new($x->{a} * 2, $x->{b} * 2)->exp;
1358              
1359 7         20 $t1->{a} *= 2;
1360 7         12 $t1->{b} *= 2;
1361              
1362 7         14 $t2->{a} -= 1;
1363              
1364 7         17 $t1->div($t2);
1365             }
1366              
1367             #
1368             ## acsc(a + b*i) = asin(1/(a + b*i))
1369             #
1370              
1371             sub acsc ($) {
1372 4     4 1 9 my ($x) = @_;
1373              
1374 4 50       14 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1375              
1376 4         11 $x->inv->asin;
1377             }
1378              
1379             #
1380             ## acsch(a + b*i) = asinh(1/(a + b*i))
1381             #
1382              
1383             sub acsch ($) {
1384 5     5 1 571 my ($x) = @_;
1385              
1386 5 100       19 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1387              
1388 5         14 $x->inv->asinh;
1389             }
1390              
1391             #
1392             ## deg2rad(x) = x / 180 * atan2(0, -abs(x))
1393             #
1394              
1395             sub deg2rad ($) {
1396 7     7 1 852 my ($x) = @_;
1397              
1398 7 100       24 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1399              
1400 7         24 my $t = __PACKAGE__->new($x->{a} / 180, $x->{b} / 180);
1401 7         25 my $pi = CORE::atan2(0, -($x->{a} * $x->{a} + $x->{b} * $x->{b}));
1402              
1403 7 50       15 if (!ref($pi)) {
1404 7         11 $t->{a} *= $pi;
1405 7         12 $t->{b} *= $pi;
1406 7         29 return $t;
1407             }
1408              
1409 0         0 $t->mul($pi);
1410             }
1411              
1412             #
1413             ## rad2deg(x) = x * 180 / atan2(0, -abs(x))
1414             #
1415              
1416             sub rad2deg ($) {
1417 7     7 1 292 my ($x) = @_;
1418              
1419 7 100       25 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1420              
1421 7         20 my $r = __PACKAGE__->new($x->{a} * 180, $x->{b} * 180);
1422 7         16 my $t = $x->{a} * $x->{a} + $x->{b} * $x->{b};
1423              
1424 7 100       16 if ($t == 0) {
1425 3         14 return $r;
1426             }
1427              
1428 4         8 my $pi = CORE::atan2(0, -$t);
1429              
1430 4 50 33     16 if (!ref($pi) and $pi != 0) {
1431 4         7 $r->{a} /= $pi;
1432 4         6 $r->{b} /= $pi;
1433 4         16 return $r;
1434             }
1435              
1436 0         0 $r->div($pi);
1437             }
1438              
1439             ########################### MISC FUNCTIONS ###########################
1440              
1441             #
1442             ## real(a + b*i) = a
1443             #
1444              
1445             sub real ($) {
1446 14     14 1 50 my ($x) = @_;
1447              
1448 14 50       30 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1449              
1450 14         81 $x->{a};
1451             }
1452              
1453             #
1454             ## imag(a + b*i) = b
1455             #
1456              
1457             sub imag ($) {
1458 14     14 1 30 my ($x) = @_;
1459              
1460 14 50       37 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1461              
1462 14         48 $x->{b};
1463             }
1464              
1465             #
1466             ## reals(a + b*i) = (a, b)
1467             #
1468              
1469             sub reals ($) {
1470 14     14 1 605 my ($x) = @_;
1471              
1472 14 50       39 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1473              
1474 14         93 ($x->{a}, $x->{b});
1475             }
1476              
1477             #
1478             ## Equality
1479             #
1480              
1481             sub eq {
1482 5     5 1 661 my ($x, $y) = @_;
1483              
1484 5 50       18 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1485 5 50       28 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
1486              
1487             $x->{a} == $y->{a}
1488 5 100       72 and $x->{b} == $y->{b};
1489             }
1490              
1491             #
1492             ## Inequality
1493             #
1494              
1495             sub ne {
1496 0     0 1 0 my ($x, $y) = @_;
1497              
1498 0 0       0 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1499 0 0       0 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
1500              
1501             $x->{a} != $y->{a}
1502 0 0       0 or $x->{b} != $y->{b};
1503             }
1504              
1505             #
1506             ## Comparisons
1507             #
1508              
1509             sub cmp {
1510 31     31 1 59 my ($x, $y) = @_;
1511              
1512 31 50       68 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1513 31 50       60 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
1514              
1515             (($x->{a} <=> $y->{a}) // return undef)
1516 31 100 50     177 or (($x->{b} <=> $y->{b}) // return undef);
      50        
1517             }
1518              
1519             sub acmp ($$) {
1520 0     0 1 0 my ($x, $y) = @_;
1521              
1522 0 0       0 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1523 0 0       0 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
1524              
1525 0         0 $x->abs <=> $y->abs;
1526             }
1527              
1528             sub lt {
1529 29     29 1 55 my ($x, $y) = @_;
1530              
1531 29 50       63 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1532 29 50       76 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
1533              
1534 29   50     67 ($x->cmp($y) // return undef) < 0;
1535             }
1536              
1537             sub le {
1538 0     0 1 0 my ($x, $y) = @_;
1539              
1540 0 0       0 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1541 0 0       0 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
1542              
1543 0   0     0 ($x->cmp($y) // return undef) <= 0;
1544             }
1545              
1546             sub gt {
1547 0     0 1 0 my ($x, $y) = @_;
1548              
1549 0 0       0 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1550 0 0       0 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
1551              
1552 0   0     0 ($x->cmp($y) // return undef) > 0;
1553             }
1554              
1555             sub ge {
1556 2     2 1 5 my ($x, $y) = @_;
1557              
1558 2 50       6 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1559 2 50       7 $y = __PACKAGE__->new($y) if ref($y) ne __PACKAGE__;
1560              
1561 2   50     7 ($x->cmp($y) // return undef) >= 0;
1562             }
1563              
1564             sub stringify {
1565 68     68 1 135 my ($x) = @_;
1566              
1567 68 50       159 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1568              
1569 68         681 "($x->{a} $x->{b})";
1570             }
1571              
1572             sub boolify {
1573 207     207 1 915 my ($x) = @_;
1574              
1575 207 50       415 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1576              
1577 207   66     869 !!$x->{a} or !!$x->{b};
1578             }
1579              
1580             sub numify {
1581 13     13 1 2517 my ($x) = @_;
1582              
1583 13 50       30 $x = __PACKAGE__->new($x) if ref($x) ne __PACKAGE__;
1584              
1585 13         40 $x->{a};
1586             }
1587              
1588             1; # End of Math::GComplex