File Coverage

blib/lib/Math/Algebra/Symbols/Term.pm
Criterion Covered Total %
statement 357 632 56.4
branch 247 550 44.9
condition 77 210 36.6
subroutine 45 81 55.5
pod 61 71 85.9
total 787 1544 50.9


line stmt bran cond sub pod time code
1            
2             =head1 Terms
3            
4             Symbolic Algebra in Pure Perl: terms.
5            
6             A term represents a product of: variables, coefficents, divisors,
7             square roots, exponentials, and logs.
8            
9             PhilipRBrenan@yahoo.com, 2004, Perl License.
10             PhilipRBrenan@gmail.com, 2016, Perl License. www.appaapps.com
11            
12             =cut
13            
14            
15             package Math::Algebra::Symbols::Term;
16 45     45   153 use strict;
  45         47  
  45         1461  
17             our $VERSION=1.27;
18 45     45   136 use Carp;
  45         41  
  45         2572  
19 45     45   40914 use Math::BigInt;
  45         743244  
  45         167  
20             #HashUtil use Hash::Util qw(lock_hash);
21 45     45   450968 use Scalar::Util qw(weaken);
  45         74  
  45         23900  
22            
23            
24             =head2 Constructors
25            
26            
27             =head3 new
28            
29             Constructor
30            
31             =cut
32            
33            
34             sub new
35 1511     1511 1 8689 {bless {c=>1, d=>1, i=>0, v=>{}, sqrt=>undef, divide=>undef, exp=>undef, log=>undef};
36             }
37            
38            
39             =head3 Finalization
40            
41             Sign and lock terms
42            
43             =cut
44            
45             my $lock = 0; # Hash locking
46             my $z = 0; # Term counter
47             my %z; # Terms finalized
48            
49            
50             =head3 constants
51            
52             Useful constants
53            
54             =cut
55            
56            
57 0     0 0 0 my $zero = new()->c(0)->z; sub zero () {$zero}
58 547     547 0 730 my $one = new()->z; sub one () {$one}
59 0     0 0 0 my $two = new()->c(2)->z; sub two () {$two}
60 0     0 0 0 my $mOne = new()->c(-1)->z; sub mOne () {$mOne}
61             my $i = new()->i(1)->z; #sub pI () {$pI}
62 0     0 0 0 my $mI = new()->c(-1)->i(1)->z; sub mI () {$mI}
63 0     0 0 0 my $half = new()->c( 1)->d(2)->z; sub half () {$half}
64 0     0 0 0 my $mHalf = new()->c(-1)->d(2)->z; sub mHalf() {$mHalf}
65 0     0 0 0 my $pi = new()->vp('pi', 1)->z; sub pi () {$pi}
66            
67            
68             =head3 newFromString
69            
70             New from String
71            
72             =cut
73            
74            
75             sub newFromString($)
76 1151     1151 1 1153 {my ($a) = @_;
77 1151 100       1835 return $zero unless $a;
78 1106         1070 my $A = $a;
79            
80 1106         1971 for(;$A =~ /(\d+)\.(\d+)/;)
81 6         8 {my $i = $1;
82 6         8 my $j = $2;
83 6         9 my $l = '0' x length($j);
84             # carp "Replacing $i.$j with $i$j\/1$l in $A";
85 6         73 $A =~ s/$i\.$j/$i$j\/1$l/;
86             }
87            
88 1106 50       4525 if ($A =~ /^\s*([+-])?(\d+)?(?:\/(\d+))?(i)?(?:\*)?(.*)$/)
89 1106         983 {my $c = '';
90 1106 100 66     2873 $c = '-'.$c if $1 and $1 eq '-';
91 1106 100       2299 $c .= $2 if $2;
92 1106 100       1805 $c = '1' if $c eq '';
93 1106 100       1580 $c = '-1' if $c eq '-';
94 1106         919 my $d = '';
95 1106 100       1864 $d = $3 if $3;
96 1106 100       2945 $d = 1 if $d eq '';
97 1106         823 my $i = 0;
98 1106 100       1915 $i = 1 if $4;
99            
100 1106         1797 my $z = new()->c($c)->d($d)->i($i);
101            
102 1106         1612 my $b = $5;
103 45     45   24464 for (;$b =~ /^(\pL+)(?:\*\*)?(\d+)?(?:\*)?(.*)$/i;) # 2016/01/20 21:02:35 unicode support
  45         363  
  45         527  
  1106         2291  
104 142         218 {$b = $3;
105 142 100       321 $z->{v}{$1} = $2 if defined($2);
106 142 100       563 $z->{v}{$1} = 1 unless defined($2);
107             }
108            
109 1106 50       1652 croak "Cannot parse: $a" if $A eq $b;
110 1106 50       1440 croak "Cannot parse: $b in $a" if $b;
111 1106         1663 return $z->z;
112             }
113 0         0 croak "Unable to parse $a";
114             }
115            
116            
117             =head3 n
118            
119             Short name for L
120            
121             =cut
122            
123            
124             sub n($)
125 0     0 1 0 {newFromString($_[0]);
126             }
127            
128            
129             =head3 newFromStrings
130            
131             New from Strings
132            
133             =cut
134            
135            
136             sub newFromStrings(@)
137 1949 100   1949 1 3993 {return $zero->clone() unless scalar(@_);
138 1151         1189 map {newFromString($_)} @_;
  1151         1692  
139             }
140            
141            
142             =head3 gcd
143            
144             Greatest Common Divisor.
145            
146             =cut
147            
148            
149             sub gcd($$)
150 214602     214602 1 169465 {my $x = abs($_[0]);
151 214602         153455 my $y = abs($_[1]);
152            
153 214602 100 100     412112 return 1 if $x == 1 or $y == 1;
154            
155 2003 100       1865 my ($a, $b) = ($x, $y); $a = $y, $b = $x if $y < $a;
  2003         3044  
156            
157 2003         1710 for(my $r;;)
158 4260         2862 {$r = $b % $a;
159 4260 100       6384 return $a if $r == 0;
160 2257         2846 ($a, $b) = ($r, $a);
161             }
162             }
163            
164            
165             =head3 lcm
166            
167             Least common multiple.
168            
169             =cut
170            
171            
172             sub lcm($$)
173 0     0 1 0 {my $x = abs($_[0]);
174 0         0 my $y = abs($_[1]);
175 0 0 0     0 return $x*$y if $x == 1 or $y == 1;
176 0         0 $x*$y / gcd($x, $y);
177             }
178            
179            
180             =head3 isTerm
181            
182             Confirm type
183            
184             =cut
185            
186            
187 0     0 1 0 sub isTerm($) {1};
188            
189            
190             =head3 intCheck
191            
192             Integer check
193            
194             =cut
195            
196            
197             sub intCheck($$)
198 614026     614026 1 473446 {my ($i, $m) = @_;
199 614026 50       715901 return $i if $i == 1;
200 614026 50       1442843 $i =~ /^[\+\-]?\d+/ or die "Integer required for $m not $i";
201 614026 100       722810 return Math::BigInt->new($i) if $i > 10_000_000;
202 613632         669847 $i;
203             }
204            
205            
206             =head3 c
207            
208             Coefficient
209            
210             =cut
211            
212            
213             sub c($;$)
214 323593     323593 1 262880 {my ($t) = @_;
215 323593 100       628913 return $t->{c} unless @_ > 1;
216            
217 215497 100       377133 $t->{c} = ($_[1] == 1 ? $_[1] : intCheck($_[1], 'c'));
218 215497         342131 $t;
219             }
220            
221            
222             =head3 d
223            
224             Divisor
225            
226             =cut
227            
228            
229             sub d($;$)
230 215150     215150 1 181648 {my ($t) = @_;
231 215150 100       316024 return $t->{d} unless @_ > 1;
232            
233 215061 100       273452 $t->{d} = ($_[1] == 1 ? $_[1] : intCheck($_[1], 'd'));
234 215061         276729 $t;
235             }
236            
237            
238             =head3 timesInt
239            
240             Multiply term by integer
241            
242             =cut
243            
244            
245             sub timesInt($$)
246 5877     5877 1 4908 {my ($t) = @_;
247 5877 50       7254 my $m = ($_[1] ? $_[1] : intCheck($_[1], 'times'));
248            
249 5877         5847 $t->{c} *= $m;
250 5877 100       9523 if ($t->{d} > 1)
251 421         678 {my $g = gcd($t->{c}, $t->{d});
252 421 100       642 if ($g > 1)
253 274         313 {$t->{d} /= $g;
254 274         292 $t->{c} /= $g;
255             }
256             }
257 5877         7667 $t;
258             }
259            
260            
261             =head3 divideInt
262            
263             Divide term by integer
264            
265             =cut
266            
267            
268             sub divideInt($$)
269 213939     213939 1 145911 {my ($t) = @_;
270 213939 100       223678 my $d = ($_[1] == 1 ? $_[1] : intCheck($_[1], 'divide'));
271 213939 50       277728 $d != 0 or die "Cannot divide by zero";
272            
273 213939         209276 $t->{d} *= abs($d);
274 213939         311345 my $g = gcd($t->{d}, $t->{c});
275 213939 100       276344 if ($g > 1)
276 1165         1277 {$t->{d} /= $g;
277 1165         1177 $t->{c} /= $g;
278             }
279            
280 213939 100       252355 $t->{c} = - $t->{c} if $d < 0;
281 213939         298629 $t;
282             }
283            
284            
285             =head3 negate
286            
287             Negate term
288            
289             =cut
290            
291            
292             sub negate($)
293 18     18 1 24 {my ($t) = @_;
294 18         32 $t->{c} = -$t->{c};
295 18         32 $t;
296             }
297            
298            
299             =head3 isZero
300            
301             Zero?
302            
303             =cut
304            
305            
306             sub isZero($)
307 0     0 1 0 {my ($t) = @_;
308 0 0       0 exists $t->{z} or die "Testing unfinalized term";
309 0         0 $t->{id} == $zero->{id};
310             }
311            
312            
313             =head3 notZero
314            
315             Not Zero?
316            
317             =cut
318            
319            
320 0     0 1 0 sub notZero($) {return !isZero($_[0])}
321            
322            
323             =head3 isOne
324            
325             One?
326            
327             =cut
328            
329            
330             sub isOne($)
331 0     0 1 0 {my ($t) = @_;
332 0 0       0 exists $t->{z} or die "Testing unfinalized term";
333 0         0 $t->{id} == $one->{id};
334             }
335            
336            
337             =head3 notOne
338            
339             Not One?
340            
341             =cut
342            
343            
344 0     0 1 0 sub notOne($) {return !isOne($_[0])}
345            
346            
347             =head3 isMinusOne
348            
349             Minus One?
350            
351             =cut
352            
353            
354             sub isMinusOne($)
355 0     0 1 0 {my ($t) = @_;
356 0 0       0 exists $t->{z} or die "Testing unfinalized term";
357 0         0 $t->{id} == $mOne->{id};
358             }
359            
360            
361             =head3 notMinusOne
362            
363             Not Minus One?
364            
365             =cut
366            
367            
368 0     0 1 0 sub notMinusOne($) {return !isMinusOne($_[0])}
369            
370            
371             =head3 i
372            
373             Get/Set i - sqrt(-1)
374            
375             =cut
376            
377            
378             sub i($;$)
379 113734     113734 1 84039 {my ($t) = @_;
380            
381 113734 100       145799 return $t->{i} unless(@_) > 1;
382            
383 112902 100       173369 my $i = ($_[1] == 1 ? $_[1] : intCheck($_[1], 'i'));
384            
385 112902         102739 my $i4 = $i % 4;
386 112902         99826 $t->{i} = $i % 2;
387 112902 50 33     314089 $t->{c} = -$t->{c} if $i4 == 2 or $i4 == 3;
388 112902         108961 $t;
389             }
390            
391            
392             =head3 iby
393            
394             i by power: multiply a term by a power of i
395            
396             =cut
397            
398            
399             sub iby($$)
400 0     0 1 0 {my ($t, $p) = @_;
401            
402 0         0 $t->i($p+$t->{i});
403 0         0 $t;
404             }
405            
406            
407             =head3 Divide
408            
409             Get/Set divide by.
410            
411             =cut
412            
413            
414             sub Divide($;$)
415 16565     16565 1 11179 {my ($t, $d) = @_;
416 16565 100       31477 return $t->{divide} unless @_ > 1;
417 1989         1817 $t->{divide} = $d;
418 1989         2227 $t;
419             }
420            
421            
422             =head3 removeDivide
423            
424             Remove divide
425            
426             =cut
427            
428            
429             sub removeDivide($)
430 726     726 1 541 {my ($t) = @_;
431 726         754 my $z = $t->clone;
432 726         594 delete $z->{divide};
433 726         829 $z->z;
434             }
435            
436            
437             =head3 Sqrt
438            
439             Get/Set square root.
440            
441             =cut
442            
443            
444             sub Sqrt($;$)
445 3828     3828 1 3102 {my ($t, $s) = @_;
446 3828 100       6545 return $t->{sqrt} unless @_ > 1;
447 3111         2628 $t->{sqrt} = $s;
448 3111         3556 $t;
449             }
450            
451            
452             =head3 removeSqrt
453            
454             Remove square root.
455            
456             =cut
457            
458            
459             sub removeSqrt($)
460 0     0 1 0 {my ($t) = @_;
461 0         0 my $z = $t->clone;
462 0         0 delete $z->{sqrt};
463 0         0 $z->z;
464             }
465            
466            
467             =head3 Exp
468            
469             Get/Set exp
470            
471             =cut
472            
473            
474             sub Exp($;$)
475 3560     3560 1 3231 {my ($t, $e) = @_;
476 3560 50       5058 return $t->{exp} unless @_ > 1;
477 3560         3096 $t->{exp} = $e;
478 3560         4558 $t;
479             }
480            
481            
482             =head3 Log
483            
484             # Get/Set log
485            
486             =cut
487            
488            
489             sub Log($$)
490 1     1 1 2 {my ($t, $l) = @_;
491 1 50       2 return $t->{log} unless @_ > 1;
492 1         2 $t->{log} = $l;
493 1         2 $t;
494             }
495            
496            
497             =head3 vp
498            
499             Get/Set variable power.
500            
501             On get: returns the power of a variable, or zero if the variable is not
502             present in the term.
503            
504             On set: Sets the power of a variable. If the power is zero, removes the
505             variable from the term. =cut
506            
507             =cut
508            
509            
510             sub vp($$;$)
511 289719     289719 1 233414 {my ($t, $v) = @_;
512             # $v =~ /^[a-z]+$/i or die "Bad variable name $v";
513            
514 289719 100       359409 return exists($t->{v}{$v}) ? $t->{v}{$v} : 0 if @_ == 2;
    100          
515            
516 288524 100       384841 my $p = ($_[2] == 1 ? $_[2] : intCheck($_[2], 'vp'));
517 288524 100       416577 $t->{v}{$v} = $p if $p;
518 288524 100       312923 delete $t->{v}{$v} unless $p;
519 288524         294321 $t;
520             }
521            
522            
523             =head3 v
524            
525             Get all variables mentioned in the term. Variables to power zero
526             should have been removed by L.
527            
528             =cut
529            
530            
531             sub v($)
532 838     838 1 662 {my ($t) = @_;
533 838         588 return keys %{$t->{v}};
  838         1822  
534             }
535            
536            
537             =head3 clone
538            
539             Clone a term. The existing term must be finalized, see L: the new
540             term will not be finalized, allowing modifications to be made to it.
541            
542             =cut
543            
544            
545             sub clone($)
546 233048     233048 1 166725 {my ($t) = @_;
547 233048 50       290927 $t->{z} or die "Attempt to clone unfinalized term";
548 233048         1164340 my $c = bless {%$t};
549 233048         261802 $c->{v} = {%{$t->{v}}};
  233048         538222  
550 233048         343963 delete @$c{qw(id s z)};
551 233048         292599 $c;
552             }
553            
554            
555             =head3 split
556            
557             Split a term into its components
558            
559             =cut
560            
561            
562             sub split($)
563 6935     6935 1 5087 {my ($t) = @_;
564 6935         7299 my $c = $t->clone;
565 6935         10135 my @c = @$c{qw(sqrt divide exp log)};
566 6935         9470 @$c{qw(sqrt divide exp log)} = ((undef()) x 4);
567 6935         20938 (t=>$c, s=>$c[0], d=>$c[1], e=>$c[2], l=>$c[3]);
568             }
569            
570            
571             =head3 signature
572            
573             Sign the term. Used to optimize addition.
574             Fix the problem of adding different logs
575            
576             =cut
577            
578            
579             sub signature($)
580 338185     338185 1 240242 {my ($t) = @_;
581 338185         221065 my $s = '';
582 338185         213805 $s .= sprintf("%010d", $t->{v}{$_}) . $_ for sort keys %{$t->{v}};
  338185         1757314  
583 338185 100       536822 $s .= '(divide'. $t->{divide} .')' if defined($t->{divide});
584 338185 100       437240 $s .= '(sqrt'. $t->{sqrt} .')' if defined($t->{sqrt});
585 338185 100       413829 $s .= '(exp'. $t->{exp} .')' if defined($t->{exp});
586 338185 100       484426 $s .= '(log'. $t->{log} .')' if defined($t->{log});
587 338185 100       430015 $s .= 'i' if $t->{i} == 1;
588 338185 100       407144 $s = '1' if $s eq '';
589 338185         467094 $s;
590             }
591            
592            
593             =head3 getSignature
594            
595             Get the signature of a term
596            
597             =cut
598            
599            
600             sub getSignature($)
601 0     0 1 0 {my ($t) = @_;
602 0 0       0 exists $t->{z} ? $t->{z} : die "Attempt to get signature of unfinalized term";
603             }
604            
605            
606             =head3 add
607            
608             Add two finalized terms, return result in new term or undef.
609            
610             =cut
611            
612            
613             sub add($$)
614 107926     107926 1 86898 {my ($a, $b) = @_;
615            
616             $a->{z} and $b->{z} or
617 107926 50 33     281949 die "Attempt to add unfinalized terms";
618            
619 107926 50       183382 return undef unless $a->{z} eq $b->{z};
620 107926 100       151198 return $a->clone->timesInt(2)->z if $a == $b;
621            
622 105636         150311 my $z = $a->clone;
623             my $c = $a->{c} * $b->{d}
624 105636         168427 + $b->{c} * $a->{d};
625 105636         161529 my $d = $a->{d} * $b->{d};
626 105636 100       145503 return $zero if $c == 0;
627            
628 102157         150835 $z->c($c)->d(1)->divideInt($d)->z;
629             }
630            
631            
632             =head3 subtract
633            
634             Subtract two finalized terms, return result in new term or undef.
635            
636             =cut
637            
638            
639             sub subtract($$)
640 0     0 1 0 {my ($a, $b) = @_;
641            
642             $a->{z} and $b->{z} or
643 0 0 0     0 die "Attempt to subtract unfinalized terms";
644            
645 0 0       0 return $zero if $a == $b;
646 0 0       0 return $a if $b == $zero;
647 0 0       0 return $b->clone->negate->z if $a == $zero;
648 0 0       0 return undef unless $a->{z} eq $b->{z};
649            
650 0         0 my $z = $a->clone;
651             my $c = $a->{c} * $b->{d}
652 0         0 - $b->{c} * $a->{d};
653 0         0 my $d = $a->{d} * $b->{d};
654            
655 0         0 $z->c($c)->d(1)->divideInt($d)->z;
656             }
657            
658            
659             =head3 multiply
660            
661             Multiply two finalized terms, return the result in a new term or undef
662            
663             =cut
664            
665            
666             sub multiply($$)
667 114590     114590 1 85385 {my ($a, $b) = @_;
668            
669             $a->{z} and $b->{z} or
670 114590 50 33     274142 die "Attempt to multiply unfinalized terms";
671            
672             # Check
673             return undef if
674             (defined($a->{divide}) and defined($b->{divide})) or
675             (defined($a->{sqrt} ) and defined($b->{sqrt})) or
676             (defined($a->{exp} ) and defined($b->{exp})) or
677 114590 100 100     653505 (defined($a->{log} ) and defined($b->{log}));
      100        
      66        
      100        
      66        
      33        
      66        
678            
679             # cdi
680 111399         126292 my $c = $a->{c} * $b->{c};
681 111399         119284 my $d = $a->{d} * $b->{d};
682 111399         110043 my $i = $a->{i} + $b->{i};
683 111399 100       127394 $c = -$c, $i = 0 if $i == 2;
684 111399         138715 my $z = $a->clone->c($c)->d(1)->divideInt($d)->i($i);
685            
686             # v
687             # for my $v($b->v)
688             # {$z->vp($v, $z->vp($v)+$b->vp($v));
689             # }
690            
691 111399         92262 for my $v(keys(%{$b->{v}}))
  111399         229964  
692 288167 100       602024 {$z->vp($v, (exists($z->{v}{$v}) ? $z->{v}{$v} : 0)+$b->{v}{$v});
693             }
694            
695             # Divide, sqrt, exp, log
696 111399 100       205182 $z->{divide} = $b->{divide} unless defined($a->{divide});
697 111399 100       164958 $z->{sqrt} = $b->{sqrt} unless defined($a->{sqrt});
698 111399 100       166851 $z->{exp} = $b->{exp} unless defined($a->{exp});
699 111399 50       157263 $z->{log} = $b->{log} unless defined($a->{log});
700            
701             # Result
702 111399         131862 $z->z;
703             }
704            
705            
706             =head3 divide2
707            
708             Divide two finalized terms, return the result in a new term or undef
709            
710             =cut
711            
712            
713             sub divide2($$)
714 271     271 1 233 {my ($a, $b) = @_;
715            
716             $a->{z} and $b->{z} or
717 271 50 33     813 die "Attempt to divide unfinalized terms";
718            
719             # Check
720             return undef if
721 271 50 33     473 (defined($b->{divide}) and (!defined($a->{divide}) or $a->{divide}->id != $b->{divide}->id));
      66        
722             return undef if
723 267 100 100     530 (defined($b->{sqrt} ) and (!defined($a->{sqrt} ) or $a->{sqrt} ->id != $b->{sqrt} ->id));
      66        
724             return undef if
725 242 0 0     396 (defined($b->{exp} ) and (!defined($a->{exp} ) or $a->{exp} ->id != $b->{exp} ->id));
      33        
726             return undef if
727 242 0 0     368 (defined($b->{log} ) and (!defined($a->{log} ) or $a->{log} ->id != $b->{log} ->id));
      33        
728            
729             # cdi
730 242         294 my $c = $a->{c} * $b->{d};
731 242         261 my $d = $a->{d} * $b->{c};
732 242         280 my $i = $a->{i} - $b->{i};
733 242 50       380 $c = -$c, $i = 1 if $i == -1;
734 242         340 my $g = gcd($c, $d);
735 242         263 $c /= $g;
736 242         184 $d /= $g;
737 242         370 my $z = $a->clone->c($c)->d(1)->divideInt($d)->i($i);
738            
739             # v
740 242         400 for my $v($b->v)
741 107         165 {$z->vp($v, $z->vp($v)-$b->vp($v));
742             }
743            
744             # Sqrt, divide, exp, log
745 242 50 33     509 delete $z->{divide} if defined($a->{divide}) and defined($b->{divide});
746 242 100 100     497 delete $z->{sqrt } if defined($a->{sqrt }) and defined($b->{sqrt });
747 242 50 66     514 delete $z->{exp } if defined($a->{exp }) and defined($b->{exp });
748 242 50 33     438 delete $z->{log } if defined($a->{log }) and defined($b->{log });
749            
750            
751             # Result
752 242         337 $z->z;
753             }
754            
755            
756             =head3 invert
757            
758             Invert a term
759            
760             =cut
761            
762            
763             sub invert($)
764 0     0 1 0 {my ($t) = @_;
765            
766 0 0       0 $t->{z} or die "Attempt to invert unfinalized term";
767            
768             # Check
769             return undef if
770             $t->{divide} or
771             $t->{sqrt} or
772             $t->{exp} or
773 0 0 0     0 $t->{log};
      0        
      0        
774            
775             # cdi
776 0         0 my ($c, $d, $i) = ($t->{c}, $t->{d}, $t->{i});
777 0 0       0 $c = -$c if $i;
778 0         0 my $z = clone($t)->c($d)->d(1)->divideInt($c)->i($i);
779            
780             # v
781 0         0 for my $v($z->v)
782 0         0 {$z->vp($v, $z->vp($v));
783             }
784            
785             # Result
786 0         0 $z->z;
787             }
788            
789            
790             =head3 power
791            
792             Take power of term
793            
794             =cut
795            
796            
797             sub power($$)
798 0     0 1 0 {my ($a, $b) = @_;
799            
800 0 0 0     0 $a->{z} and $b->{z} or die "Attempt to take power of unfinalized term";
801            
802             # Check
803 0 0 0     0 return $one if $a == $one or $b == $zero;
804             return undef if
805             $a->{divide} or
806             $a->{sqrt} or
807             $a->{exp} or
808 0 0 0     0 $a->{log};
      0        
      0        
809            
810             return undef if
811             $b->{d} != 1 or
812             $b->{i} == 1 or
813             $b->{divide} or
814             $b->{sqrt} or
815             $b->{exp} or
816 0 0 0     0 $b->{log};
      0        
      0        
      0        
      0        
817            
818             # cdi
819 0         0 my ($c, $d, $i) = ($a->{c}, $a->{d}, $a->{i});
820            
821 0         0 my $p = $b->{c};
822 0 0       0 if ($p < 0)
823 0         0 {$a = invert($a);
824 0 0       0 return undef unless $a;
825 0         0 $p = -$p;
826 0 0       0 return $a if $p == 1;
827             }
828            
829 0         0 my $z = $a->clone->z;
830 0         0 $z = $z->multiply($a) for (2..$p);
831            
832 0         0 $i *= $p;
833 0         0 $z = $z->clone->i($i);
834            
835             # v
836             # for my $v($z->v)
837             # {$z->vp($v, $p*$z->vp($v));
838             # }
839            
840             # Result
841 0         0 $z->z;
842             }
843            
844            
845             =head3 sqrt2
846            
847             Square root of a term
848            
849             =cut
850            
851             # Return a square root guaranteed to be precise, or undef
852             # With thanks to: salvatore.bonaccorso@gmail.com
853            
854             sub _safe_sqrt
855 97     97   89 {my ($a) = @_;
856 97 50 33     324 return undef if $a >= 65536 || $a < 0;
857 97         222 my $s = int(sqrt($a)*256)/256; # $s now has at most 8+8 bits
858 97 100       172 return undef if $s*$s != $a;
859 70         79 return $s;
860             }
861            
862             sub sqrt2($)
863 62     62 1 60 {my ($t) = @_;
864            
865 62 50       117 $t->{z} or die "Attempt to sqrt unfinalized term";
866            
867             # Check
868             return undef if $t->{i} or
869             $t->{divide} or
870             $t->{sqrt} or
871             $t->{exp} or
872 62 50 33     472 $t->{log};
      33        
      33        
      33        
873            
874             # cd
875 62         98 my ($c, $d, $i) = ($t->{c}, $t->{d}, 0);
876 62 100       105 $c = -$c, $i = 1 if $c < 0;
877            
878             # my $c2 = sqrt($c); return undef unless $c2*$c2 == $c;
879             # my $d2 = sqrt($d); return undef unless $d2*$d2 == $d;
880 62 100       105 my $c2 = _safe_sqrt($c); return undef if !defined $c2;
  62         132  
881 35 50       42 my $d2 = _safe_sqrt($d); return undef if !defined $d2;
  35         71  
882            
883 35         51 my $z = clone($t)->c($c2)->d($d2)->i($i);
884            
885             # v
886 35         67 for my $v($t->v)
887 14         19 {my $p = $z->vp($v);
888 14 100       58 return undef unless $p % 2 == 0;
889 5         11 $z->vp($v, $p/2);
890             }
891            
892             # Result
893 26         42 $z->z;
894             }
895            
896            
897             =head3 exp2
898            
899             Exponential of a term
900            
901             =cut
902            
903            
904             sub exp2($)
905 1405     1405 1 1194 {my ($t) = @_;
906            
907 1405 50       2050 $t->{z} or die "Attempt to use unfinalized term in exp";
908            
909 1405 100       1982 return $one if $t == $zero;
910             return undef if $t->{divide} or
911             $t->{sqrt} or
912             $t->{exp} or
913 1302 50 33     5392 $t->{log};
      33        
      33        
914 1302 100       2120 return undef unless $t->{i} == 1;
915             return undef unless $t->{d} == 1 or
916             $t->{d} == 2 or
917 952 50 66     1742 $t->{d} == 4;
      33        
918 952         3816 return undef unless scalar(keys(%{$t->{v}})) == 1 and
919             exists($t->{v}{pi}) and
920 952 100 66     579 $t->{v}{pi} == 1;
      66        
921            
922 26         30 my $c = $t->{c};
923 26         23 my $d = $t->{d};
924 26 100       46 $c *= 2 if $d == 1;
925 26         23 $c %= 4;
926            
927 26 100       40 return $one if $c == 0;
928 25 100       44 return $i if $c == 1;
929 16 100       39 return $mOne if $c == 2;
930 10 50       27 return $mI if $c == 3;
931             }
932            
933            
934             =head3 sin2
935            
936             Sine of a term
937            
938             =cut
939            
940            
941             sub sin2($)
942 120     120 1 106 {my ($t) = @_;
943            
944 120 50       224 $t->{z} or die "Attempt to use unfinalized term in sin";
945            
946 120 100       194 return $zero if $t == $zero;
947             return undef if $t->{divide} or
948             $t->{sqrt} or
949             $t->{exp} or
950 117 50 33     623 $t->{log};
      33        
      33        
951 117 100       201 return undef unless $t->{i} == 0;
952 113 100       74 return undef unless scalar(keys(%{$t->{v}})) == 1;
  113         251  
953 111 100       265 return undef unless exists($t->{v}{pi});
954 20 50       28 return undef unless $t->{v}{pi} == 1;
955            
956 20         22 my $c = $t->{c};
957 20         16 my $d = $t->{d};
958 20 50 100     85 return undef unless $d== 1 or $d == 2 or $d == 3 or $d == 6;
      66        
      66        
959 20 100       26 $c *= 6 if $d == 1;
960 20 100       29 $c *= 3 if $d == 2;
961 20 50       25 $c *= 2 if $d == 3;
962 20         16 $c = $c % 12;
963            
964 20 100       28 return $zero if $c == 0;
965 17 100       21 return $half if $c == 1;
966 15 50       24 return undef if $c == 2;
967 15 100       24 return $one if $c == 3;
968 12 50       18 return undef if $c == 4;
969 12 100       21 return $half if $c == 5;
970 10 100       16 return $zero if $c == 6;
971 7 100       13 return $mHalf if $c == 7;
972 5 50       7 return undef if $c == 8;
973 5 100       12 return $mOne if $c == 9;
974 2 50       4 return undef if $c == 10;
975 2 50       6 return $mHalf if $c == 11;
976 0 0       0 return $zero if $c == 12;
977             }
978            
979            
980             =head3 cos2
981            
982             Cosine of a term
983            
984             =cut
985            
986            
987             sub cos2($)
988 125     125 1 104 {my ($t) = @_;
989            
990 125 50       226 $t->{z} or die "Attempt to use unfinalized term in cos";
991            
992 125 100       191 return $one if $t == $zero;
993             return undef if $t->{divide} or
994             $t->{sqrt} or
995             $t->{exp} or
996 122 50 33     673 $t->{log};
      33        
      33        
997 122 100       198 return undef unless $t->{i} == 0;
998 118 100       98 return undef unless scalar(keys(%{$t->{v}})) == 1;
  118         226  
999 116 100       275 return undef unless exists($t->{v}{pi});
1000 20 50       35 return undef unless $t->{v}{pi} == 1;
1001            
1002 20         22 my $c = $t->{c};
1003 20         18 my $d = $t->{d};
1004 20 50 100     80 return undef unless $d== 1 or $d == 2 or $d == 3 or $d == 6;
      66        
      33        
1005 20 100       25 $c *= 6 if $d == 1;
1006 20 100       41 $c *= 3 if $d == 2;
1007 20 100       27 $c *= 2 if $d == 3;
1008 20         16 $c = $c % 12;
1009            
1010 20 100       25 return $half if $c == 10;
1011 18 50       22 return undef if $c == 11;
1012 18 50       24 return $one if $c == 12;
1013 18 100       30 return $one if $c == 0;
1014 15 50       18 return undef if $c == 1;
1015 15 100       26 return $half if $c == 2;
1016 13 100       21 return $zero if $c == 3;
1017 10 100       15 return $mHalf if $c == 4;
1018 8 50       15 return undef if $c == 5;
1019 8 100       14 return $mOne if $c == 6;
1020 5 50       8 return undef if $c == 7;
1021 5 100       17 return $mHalf if $c == 8;
1022 3 50       8 return $zero if $c == 9;
1023             }
1024            
1025            
1026             =head3 log2
1027            
1028             Log of a term
1029            
1030             =cut
1031            
1032            
1033             sub log2($)
1034 1     1 1 1 {my ($a) = @_;
1035            
1036 1 50       2 $a->{z} or die "Attempt to use unfinalized term in log";
1037            
1038 1 50       3 return $zero if $a == $one;
1039 1         2 return undef;
1040             }
1041            
1042            
1043             =head3 id
1044            
1045             Get Id of a term
1046            
1047             =cut
1048            
1049            
1050             sub id($)
1051 0     0 1 0 {my ($t) = @_;
1052 0 0       0 $t->{id} or die "Term $t not yet finalized";
1053 0         0 $t->{id};
1054             }
1055            
1056            
1057             =head3 zz
1058            
1059             # Check term finalized
1060            
1061             =cut
1062            
1063            
1064             sub zz($)
1065 0     0 1 0 {my ($t) = @_;
1066 0 0       0 $t->{z} or die "Term $t not yet finalized";
1067 0         0 $t;
1068             }
1069            
1070            
1071             =head3 z
1072            
1073             Finalize creation of the term. Once a term has been finalized, it
1074             becomes readonly, which allows optimization to be performed.
1075            
1076             =cut
1077            
1078            
1079             sub z($)
1080 230125     230125 1 172471 {my ($t) = @_;
1081 230125 50       289302 !exists($t->{z}) or die "Already finalized this term";
1082            
1083 230125         249992 my $p = $t->print;
1084 230125 100       534860 return $z{$p} if defined($z{$p});
1085 191628         304247 $z{$p} = $t;
1086 191628         374759 weaken($z{$p}); # Greatly reduces memory usage
1087            
1088 191628         177263 $t->{s} = $p;
1089 191628         241894 $t->{z} = $t->signature;
1090 191628         196111 $t->{id} = ++$z;
1091            
1092             #HashUtil lock_hash(%{$t->{v}}) if $lock;
1093             #HashUtil lock_hash %$t if $lock;
1094 191628         402552 $t;
1095             }
1096            
1097             #sub DESTROY($)
1098             # {my ($t) = @_;
1099             # delete $z{$t->{s}} if defined($t) and exists $t->{s};
1100             # }
1101            
1102             sub lockHashes()
1103 0     0 0 0 {my ($l) = @_;
1104             #HashUtil for my $t(values %z)
1105             #HashUtil {lock_hash(%{$t->{v}});
1106             #HashUtil lock_hash %$t;
1107             #HashUtil }
1108 0         0 $lock = 1;
1109             }
1110            
1111            
1112             =head3 print
1113            
1114             Print
1115            
1116             =cut
1117            
1118            
1119             sub print($)
1120 750087     750087 1 495674 {my ($t) = @_;
1121 750087 100       1598580 return $t->{s} if defined($t->{s});
1122 230125         178898 my @k = sort keys %{$t->{v}}; # 2016/01/20 16:18:12 Added sort to make prints canonical
  230125         703549  
1123 230125         222389 my $v = $t->{v};
1124 230125         154961 my $s = '';
1125 230125         292264 $s .= $t->{c};
1126 230125 100       347709 $s .= '/'.$t->{d} if $t->{d} != 1;
1127 230125 100       291040 $s .= '*&i' if $t->{i} == 1; # 2016/01/20 15:55:21 &i to stop ambiguous complaints
1128 230125         208426 $s .= '*$'.$_ for grep {$v->{$_} == 1} @k;
  616937         765053  
1129 230125         191060 $s .= '/$'.$_ for grep {$v->{$_} == -1} @k;
  616937         595325  
1130 230125         178517 $s .= '*$'.$_.'**'. $v->{$_} for grep {$v->{$_} > 1} @k;
  616937         949754  
1131 230125         186552 $s .= '/$'.$_.'**'.-$v->{$_} for grep {$v->{$_} < -1} @k;
  616937         612453  
1132 230125 100       304950 $s .= '/('. $t->{divide} .')' if defined $t->{divide};
1133 230125 100       267135 $s .= '*sqrt('. $t->{sqrt} .')' if defined $t->{sqrt};
1134 230125 100       272751 $s .= '*exp('. $t->{exp} .')' if defined $t->{exp};
1135 230125 100       297683 $s .= '*log('. $t->{log} .')' if defined $t->{log};
1136 230125         314255 $s;
1137             }
1138            
1139            
1140             =head2 import
1141            
1142             Export L to calling package with a name specifed by the
1143             caller, or as B by default. =cut
1144            
1145             =cut
1146            
1147            
1148             sub import
1149 45     45   122 {my %P = (program=>@_);
1150 45         47 my %p; $p{lc()} = $P{$_} for(keys(%P));
  45         163  
1151            
1152             #_______________________________________________________________________
1153             # New symbols term constructor - export to calling package.
1154             #_______________________________________________________________________
1155            
1156 45         67 my $s = "pack"."age XXXX;\n". <<'END';
1157             no warnings 'redefine';
1158             sub NNNN
1159             {return SSSSnewFromStrings(@_);
1160             }
1161             use warnings 'redefine';
1162             END
1163            
1164             #_______________________________________________________________________
1165             # Export to calling package.
1166             #_______________________________________________________________________
1167            
1168 45         53 my $name = 'term';
1169 45 50       104 $name = $p{term} if exists($p{term});
1170 45         85 my ($main) = caller();
1171 45         60 my $pack = __PACKAGE__.'::';
1172            
1173 45         185 $s=~ s/XXXX/$main/g;
1174 45         108 $s=~ s/NNNN/$name/g;
1175 45         109 $s=~ s/SSSS/$pack/g;
1176 45     45 0 195 eval($s);
  45     45   50  
  45     1949   2887  
  45         153  
  45         48  
  45         1357  
  45         3018  
  1949         4319  
1177            
1178             #_______________________________________________________________________
1179             # Check options supplied by user
1180             #_______________________________________________________________________
1181            
1182 45         135 delete @p{qw(program terms)};
1183            
1184 45 50       966 croak "Unknown option(s) for ". __PACKAGE__ .": ". join(' ', keys(%p))."\n\n". <<'END' if keys(%p);
1185            
1186             Valid options are:
1187            
1188             terms=>'name' Desired name of the constructor routine for creating
1189             new terms. The default is 'term'.
1190             END
1191             }
1192            
1193            
1194             =head2 Operators
1195            
1196            
1197             =head3 Operator Overloads
1198            
1199             Operator Overloads
1200            
1201             =cut
1202            
1203            
1204             use overload
1205 45         624 '+' =>\&add3,
1206             '-' =>\&negate3,
1207             '*' =>\&multiply3,
1208             '/' =>\÷3,
1209             '**' =>\&power3,
1210             '==' =>\&equals3,
1211             'sqrt' =>\&sqrt3,
1212             'exp' =>\&exp3,
1213             'log' =>\&log3,
1214             'sin' =>\&sin3,
1215             'cos' =>\&cos3,
1216             '""' =>\&print3,
1217 45     45   818986 fallback=>1;
  45         73  
1218            
1219            
1220             =head3 add3
1221            
1222             Add operator.
1223            
1224             =cut
1225            
1226            
1227             sub add3
1228 0     0 1 0 {my ($a, $b) = @_;
1229 0 0       0 $b = newFromString("$b") unless ref($b) eq __PACKAGE__;
1230 0 0 0     0 $a->{z} and $b->{z} or die "Add using unfinalized terms";
1231 0         0 $a->add($b);
1232             }
1233            
1234            
1235             =head3 negate3
1236            
1237             Negate operator.
1238            
1239             =cut
1240            
1241            
1242             sub negate3
1243 0     0 1 0 {my ($a, $b, $c) = @_;
1244            
1245 0 0       0 if (defined($b))
1246 0 0       0 {$b = newFromString("$b") unless ref($b) eq __PACKAGE__;
1247 0 0 0     0 $a->{z} and $b->{z} or die "Negate using unfinalized terms";
1248 0 0       0 return $b->subtract($a) if $c;
1249 0 0       0 return $a->subtract($b) unless $c;
1250             }
1251             else
1252 0 0       0 {$a->{z} or die "Negate single unfinalized terms";
1253 0         0 return $a->negate;
1254             }
1255             }
1256            
1257            
1258             =head3 multiply3
1259            
1260             Multiply operator.
1261            
1262             =cut
1263            
1264            
1265             sub multiply3
1266 0     0 1 0 {my ($a, $b) = @_;
1267 0 0       0 $b = newFromString("$b") unless ref($b) eq __PACKAGE__;
1268 0 0 0     0 $a->{z} and $b->{z} or die "Multiply using unfinalized terms";
1269 0         0 $a->multiply($b);
1270             }
1271            
1272            
1273             =head3 divide3
1274            
1275             Divide operator.
1276            
1277             =cut
1278            
1279            
1280             sub divide3
1281 0     0 1 0 {my ($a, $b, $c) = @_;
1282 0 0       0 $b = newFromString("$b") unless ref($b) eq __PACKAGE__;
1283 0 0 0     0 $a->{z} and $b->{z} or die "Divide using unfinalized terms";
1284 0 0       0 return $b->divide2($a) if $c;
1285 0 0       0 return $a->divide2($b) unless $c;
1286             }
1287            
1288            
1289             =head3 power3
1290            
1291             Power operator.
1292            
1293             =cut
1294            
1295            
1296             sub power3
1297 0     0 1 0 {my ($a, $b) = @_;
1298 0 0       0 $b = newFromString("$b") unless ref($b) eq __PACKAGE__;
1299 0 0 0     0 $a->{z} and $b->{z} or die "Power using unfinalized terms";
1300 0         0 $a->power($b);
1301             }
1302            
1303            
1304             =head3 equals3
1305            
1306             Equals operator.
1307            
1308             =cut
1309            
1310            
1311             sub equals3
1312 109577     109577 1 83136 {my ($a, $b) = @_;
1313 109577 50       134338 if (ref($b) eq __PACKAGE__)
1314 109577 50 33     203644 {$a->{z} and $b->{z} or die "Equals using unfinalized terms";
1315 109577         228619 return $a->{id} == $b->{id};
1316             }
1317             else
1318 0 0       0 {$a->{z} or die "Equals using unfinalized terms";
1319 0         0 return $a->print eq "$b";
1320             }
1321             }
1322            
1323            
1324             =head3 print3
1325            
1326             Print operator.
1327            
1328             =cut
1329            
1330            
1331             sub print3
1332 458510     458510 1 325027 {my ($a) = @_;
1333 458510 50       568702 $a->{z} or die "Print of unfinalized term";
1334 458510         450271 $a->print();
1335             }
1336            
1337            
1338             =head3 sqrt3
1339            
1340             Square root operator.
1341            
1342             =cut
1343            
1344            
1345             sub sqrt3
1346 0     0 1   {my ($a) = @_;
1347 0 0         $a->{z} or die "Sqrt of unfinalized term";
1348 0           $a->sqrt2();
1349             }
1350            
1351            
1352             =head3 exp3
1353            
1354             Exponential operator.
1355            
1356             =cut
1357            
1358            
1359             sub exp3
1360 0     0 1   {my ($a) = @_;
1361 0 0         $a->{z} or die "Exp of unfinalized term";
1362 0           $a->exp2();
1363             }
1364            
1365            
1366             =head3 sin3
1367            
1368             Sine operator.
1369            
1370             =cut
1371            
1372            
1373             sub sin3
1374 0     0 1   {my ($a) = @_;
1375 0 0         $a->{z} or die "Sin of unfinalized term";
1376 0           $a->sin2();
1377             }
1378            
1379            
1380             =head3 cos3
1381            
1382             Cosine operator.
1383            
1384             =cut
1385            
1386            
1387             sub cos3
1388 0     0 1   {my ($a) = @_;
1389 0 0         $a->{z} or die "Cos of unfinalized term";
1390 0           $a->cos2();
1391             }
1392            
1393            
1394             =head3 log3
1395            
1396             Log operator.
1397            
1398             =cut
1399            
1400            
1401             sub log3
1402 0     0 1   {my ($a) = @_;
1403 0 0         $a->{z} or die "Log of unfinalized term";
1404 0           $a->log2();
1405             }
1406            
1407            
1408             =head2 test
1409            
1410             Tests
1411            
1412             =cut
1413            
1414            
1415             sub test()
1416 0     0 1   {my ($a, $b, $c, $d);
1417             # lockHashes();
1418 0 0         $a = n(0); $a == $zero or die "100";
  0            
1419 0 0         $a = n(1); $a == $one or die "101";
  0            
1420 0 0         $a = n(2); $a == $two or die "102";
  0            
1421 0 0         $b = n(3); $b == 3 or die "103";
  0            
1422 0 0         $c = $a+$a; $c == 4 or die "104";
  0            
1423 0 0         $c = $a+$b; $c == 5 or die "105";
  0            
1424 0 0         $c = $a+$b+$a+$b; $c == 10 or die "106";
  0            
1425 0 0         $c = $a+1; $c == 3 or die "107";
  0            
1426 0 0         $c = $a+2; $c == 4 or die "108";
  0            
1427 0 0         $c = $b-1; $c == 2 or die "109";
  0            
1428 0 0         $c = $b-2; $c == 1 or die "110";
  0            
1429 0 0         $c = $b-9; $c == -6 or die "111";
  0            
1430 0 0         $c = $a/2; $c == $one or die "112";
  0            
1431 0 0         $c = $a/4; $c == '1/2' or die "113";
  0            
1432 0 0         $c = $a*2/2; $c == $two or die "114";
  0            
1433 0 0         $c = $a*2/4; $c == $one or die "115";
  0            
1434 0 0         $c = $a**2; $c == 4 or die "116";
  0            
1435 0 0         $c = $a**10; $c == 1024 or die "117";
  0            
1436 0 0         $c = sqrt($a**2); $c == $a or die "118";
  0            
1437 0 0         $d = n(-1); $d == -1 or die "119";
  0            
1438 0 0         $c = sqrt($d); $c == '1*i' or die "120";
  0            
1439 0 0         $d = n(4); $d == 4 or die "121";
  0            
1440 0 0         $c = sqrt($d); $c == 2 or die "122";
  0            
1441 0 0         $c = n('x*y2')/n('a*b2'); $c == '1*$x/$a*$y**2/$b**2' or die "122";
  0            
1442            
1443 0 0         $a = n('x'); $a == '1*$x' or die "21";
  0            
1444 0 0         $b = n('2*x**2'); $b == '2*$x**2' or die "22";
  0            
1445 0 0         $c = $a+$a; $c == '2*$x' or die "23";
  0            
1446 0 0         $c = $a+$a+$a; $c == '3*$x' or die "24";
  0            
1447 0 0         $c = $a-$a; $c == $zero or die "25";
  0            
1448 0 0         $c = $a-$a-$a; $c == '-1*$x' or die "26";
  0            
1449 0 0         $c = $a*$b; $c == '2*$x**3' or die "27";
  0            
1450 0 0         $c = $a*$b*$a*$b; $c == '4*$x**6' or die "28";
  0            
1451 0 0         $c = $b/$a; $c == '2*$x' or die "29";
  0            
1452 0           $c = $a**2/$b;
1453            
1454 0 0         $c == '1/2' or die "29";
1455 0 0         $c = sqrt($a**4/($b/2)); $c == $a or die "29";
  0            
1456            
1457 0 0         $a = sin($zero); $a == -0 or die "301";
  0            
1458 0 0         $a = sin($pi/6); $a == $half or die "302";
  0            
1459 0 0         $a = sin($pi/2); $a == 1 or die "303";
  0            
1460 0 0         $a = sin(5*$pi/6); $a == $half or die "304";
  0            
1461 0 0         $a = sin(120*$pi/120); $a == $zero or die "305";
  0            
1462 0 0         $a = sin(7*$pi/6); $a == -$half or die "306";
  0            
1463 0 0         $a = sin(3*$pi/2); $a == -1 or die "307";
  0            
1464 0 0         $a = sin(110*$pi/ 60); $a == '-1/2' or die "308";
  0            
1465 0 0         $a = sin(2*$pi); $a == $zero or die "309";
  0            
1466 0 0         $a = sin(-$zero); $a == $zero or die "311";
  0            
1467 0 0         $a = sin(-$pi/6); $a == -$half or die "312";
  0            
1468 0 0         $a = sin(-$pi/2); $a == -$one or die "313";
  0            
1469 0 0         $a = sin(-5*$pi/6); $a == -$half or die "314";
  0            
1470 0 0         $a = sin(-120*$pi/120); $a == -$zero or die "315";
  0            
1471 0 0         $a = sin(-7*$pi/6); $a == $half or die "316";
  0            
1472 0 0         $a = sin(-3*$pi/2); $a == $one or die "317";
  0            
1473 0 0         $a = sin(-110*$pi/ 60); $a == $half or die "318";
  0            
1474 0 0         $a = sin(-2*$pi); $a == $zero or die "319";
  0            
1475 0 0         $a = cos($zero); $a == $one or die "321";
  0            
1476 0 0         $a = cos($pi/3); $a == $half or die "322";
  0            
1477 0 0         $a = cos($pi/2); $a == $zero or die "323";
  0            
1478 0 0         $a = cos(4*$pi/6); $a == -$half or die "324";
  0            
1479 0 0         $a = cos(120*$pi/120); $a == -$one or die "325";
  0            
1480 0 0         $a = cos(8*$pi/6); $a == -$half or die "326";
  0            
1481 0 0         $a = cos(3*$pi/2); $a == $zero or die "327";
  0            
1482 0 0         $a = cos(100*$pi/ 60); $a == $half or die "328";
  0            
1483 0 0         $a = cos(2*$pi); $a == $one or die "329";
  0            
1484 0 0         $a = cos(-$zero); $a == $one or die "331";
  0            
1485 0 0         $a = cos(-$pi/3); $a == +$half or die "332";
  0            
1486 0 0         $a = cos(-$pi/2); $a == $zero or die "333";
  0            
1487 0 0         $a = cos(-4*$pi/6); $a == -$half or die "334";
  0            
1488 0 0         $a = cos(-120*$pi/120); $a == -$one or die "335";
  0            
1489 0 0         $a = cos(-8*$pi/6); $a == -$half or die "336";
  0            
1490 0 0         $a = cos(-3*$pi/2); $a == $zero or die "337";
  0            
1491 0 0         $a = cos(-100*$pi/ 60); $a == $half or die "338";
  0            
1492 0 0         $a = cos(-2*$pi); $a == $one or die "339";
  0            
1493 0 0         $a = exp($zero); $a == $one or die "340";
  0            
1494 0 0         $a = exp($i*$pi/2); $a == $i or die "341";
  0            
1495 0 0         $a = exp($i*$pi); $a == -$one or die "342";
  0            
1496 0 0         $a = exp(3*$i*$pi/2); $a == -$i or die "343";
  0            
1497 0 0         $a = exp(4*$i*$pi/2); $a == $one or die "344";
  0            
1498             }
1499            
1500             test unless caller;
1501            
1502             #_______________________________________________________________________
1503             # Package installed successfully
1504             #_______________________________________________________________________
1505            
1506             1;