File Coverage

blib/lib/Math/GComplex.pm
Criterion Covered Total %
statement 505 583 86.6
branch 182 302 60.2
condition 46 110 41.8
subroutine 95 116 81.9
pod 77 77 100.0
total 905 1188 76.1


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