File Coverage

blib/lib/Math/Algebra/Symbols/Term.pm
Criterion Covered Total %
statement 346 622 55.6
branch 243 546 44.5
condition 75 207 36.2
subroutine 42 79 53.1
pod 61 72 84.7
total 767 1526 50.2


line stmt bran cond sub pod time code
1            
2             =head1 Terms
3            
4             Symbolic Algebra in Pure Perl: terms.
5            
6             See user manual L.
7            
8             A term represents a product of: variables, coefficents, divisors,
9             square roots, exponentials, and logs.
10            
11             PhilipRBrenan@yahoo.com, 2004, Perl License.
12            
13             =cut
14            
15            
16             package Math::Algebra::Symbols::Term;
17             $VERSION=1.21;
18 45     45   337 use Carp;
  45         112  
  45         8556  
19 45     45   156060 use Math::BigInt;
  45         1849931  
  45         427  
20             #HashUtil use Hash::Util qw(lock_hash);
21 45     45   1202489 use Scalar::Util qw(weaken);
  45         123  
  45         412924  
22            
23            
24             =head2 Constructors
25            
26            
27             =head3 new
28            
29             Constructor
30            
31             =cut
32            
33            
34             sub new
35 1417     1417 1 28387 {bless {c=>1, d=>1, i=>0, v=>{}, sqrt=>undef, divide=>undef, exp=>undef, log=>undef};
36             }
37            
38            
39             =head3 newFromString
40            
41             New from String
42            
43             =cut
44            
45            
46 1057     1057 1 1990 sub newFromString($)
47             {my ($a) = @_;
48 1057 100       2862 return $zero unless $a;
49 1012         2030 my $A = $a;
50            
51 1012         2909 for(;$A =~ /(\d+)\.(\d+)/;)
  2         5  
52             {my $i = $1;
53 2         4 my $j = $2;
54 2         6 my $l = '0' x length($j);
55             # carp "Replacing $i.$j with $i$j\/1$l in $A";
56 2         45 $A =~ s/$i\.$j/$i$j\/1$l/;
57             }
58            
59 1012 50       6750 if ($A =~ /^\s*([+-])?(\d+)?(?:\/(\d+))?(i)?(?:\*)?(.*)$/)
  1012         1810  
60             {my $c = '';
61 1012 100 66     4228 $c = '-'.$c if $1 and $1 eq '-';
62 1012 100       4672 $c .= $2 if $2;
63 1012 100       3379 $c = '1' if $c eq '';
64 1012 100       2453 $c = '-1' if $c eq '-';
65 1012         1387 my $d = '';
66 1012 100       2908 $d = $3 if $3;
67 1012 100       2652 $d = 1 if $d eq '';
68 1012         1314 my $i = 0;
69 1012 100       2811 $i = 1 if $4;
70            
71 1012         2559 my $z = new()->c($c)->d($d)->i($i);
72            
73 1012         3463 my $b = $5;
74 1012         5291 for (;$b =~ /^([a-z]+)(?:\*\*)?(\d+)?(?:\*)?(.*)$/i;)
  130         661  
75             {$b = $3;
76 130 100       409 $z->{v}{$1} = $2 if defined($2);
77 130 100       1004 $z->{v}{$1} = 1 unless defined($2);
78             }
79            
80 1012 50       2207 croak "Cannot parse: $a" if $A eq $b;
81 1012 50       2143 croak "Cannot parse: $b in $a" if $b;
82 1012         2560 return $z->z;
83             }
84 0         0 croak "Unable to parse $a";
85             }
86            
87            
88             =head3 n
89            
90             Short name for L
91            
92             =cut
93            
94            
95 0     0 1 0 sub n($)
96             {newFromString($_[0]);
97             }
98            
99            
100             =head3 newFromStrings
101            
102             New from Strings
103            
104             =cut
105            
106            
107 1795 100   1795 1 5688 sub newFromStrings(@)
108             {return $zero->clone() unless scalar(@_);
109 1057         1817 map {newFromString($_)} @_;
  1057         2442  
110             }
111            
112            
113             =head3 gcd
114            
115             Greatest Common Divisor.
116            
117             =cut
118            
119            
120 12874     12874 1 17442 sub gcd($$)
121             {my $x = abs($_[0]);
122 12874         26209 my $y = abs($_[1]);
123            
124 12874 100 100     62278 return 1 if $x == 1 or $y == 1;
125            
126 3142 100       78092 my ($a, $b) = ($x, $y); $a = $y, $b = $x if $y < $a;
  3142         8009  
127            
128 3142         23256 for(my $r;;)
  7635         12074  
129             {$r = $b % $a;
130 7635 100       136186 return $a if $r == 0;
131 4493         121766 ($a, $b) = ($r, $a);
132             }
133             }
134            
135            
136             =head3 lcm
137            
138             Least common multiple.
139            
140             =cut
141            
142            
143 0     0 1 0 sub lcm($$)
144             {my $x = abs($_[0]);
145 0         0 my $y = abs($_[1]);
146 0 0 0     0 return $x*$y if $x == 1 or $y == 1;
147 0         0 $x*$y / gcd($x, $y);
148             }
149            
150            
151             =head3 isTerm
152            
153             Confirm type
154            
155             =cut
156            
157            
158 0     0 1 0 sub isTerm($) {1};
159            
160            
161             =head3 intCheck
162            
163             Integer check
164            
165             =cut
166            
167            
168 21972     21972 1 102998 sub intCheck($$)
169             {my ($i, $m) = @_;
170 21972 50       52660 return $i if $i == 1;
171 21972 50       185746 $i =~ /^[\+\-]?\d+/ or die "Integer required for $m not $i";
172 21972 100       64427 return Math::BigInt->new($i) if $i > 10_000_000;
173 21529         99074 $i;
174             }
175            
176            
177             =head3 c
178            
179             Coefficient
180            
181             =cut
182            
183            
184 22242     22242 1 36488 sub c($;$)
185             {my ($t) = @_;
186 22242 100       89423 return $t->{c} unless @_ > 1;
187            
188 13585 100       47505 $t->{c} = ($_[1] == 1 ? $_[1] : intCheck($_[1], 'c'));
189 13585         55902 $t;
190             }
191            
192            
193             =head3 d
194            
195             Divisor
196            
197             =cut
198            
199            
200 13262     13262 1 23388 sub d($;$)
201             {my ($t) = @_;
202 13262 100       28452 return $t->{d} unless @_ > 1;
203            
204 13195 100       29287 $t->{d} = ($_[1] == 1 ? $_[1] : intCheck($_[1], 'd'));
205 13195         36775 $t;
206             }
207            
208            
209             =head3 timesInt
210            
211             Multiply term by integer
212            
213             =cut
214            
215            
216 2305     2305 1 4656 sub timesInt($$)
217             {my ($t) = @_;
218 2305 50       5089 my $m = ($_[1] ? $_[1] : intCheck($_[1], 'times'));
219            
220 2305         4147 $t->{c} *= $m;
221 2305 100       6041 if ($t->{d} > 1)
  468         1379  
222             {my $g = gcd($t->{c}, $t->{d});
223 468 100       1578 if ($g > 1)
  323         666  
224             {$t->{d} /= $g;
225 323         588 $t->{c} /= $g;
226             }
227             }
228 2305         5831 $t;
229             }
230            
231            
232             =head3 divideInt
233            
234             Divide term by integer
235            
236             =cut
237            
238            
239 12176     12176 1 16188 sub divideInt($$)
240             {my ($t) = @_;
241 12176 100       27726 my $d = ($_[1] == 1 ? $_[1] : intCheck($_[1], 'divide'));
242 12176 50       56819 $d != 0 or die "Cannot divide by zero";
243            
244 12176         80503 $t->{d} *= abs($d);
245 12176         110096 my $g = gcd($t->{d}, $t->{c});
246 12176 100       87566 if ($g > 1)
  1810         33885  
247             {$t->{d} /= $g;
248 1810         32707 $t->{c} /= $g;
249             }
250            
251 12176 100       66714 $t->{c} = - $t->{c} if $d < 0;
252 12176         99721 $t;
253             }
254            
255            
256             =head3 negate
257            
258             Negate term
259            
260             =cut
261            
262            
263 15     15 1 22 sub negate($)
264             {my ($t) = @_;
265 15         36 $t->{c} = -$t->{c};
266 15         53 $t;
267             }
268            
269            
270             =head3 isZero
271            
272             Zero?
273            
274             =cut
275            
276            
277 0     0 1 0 sub isZero($)
278             {my ($t) = @_;
279 0 0       0 exists $t->{z} or die "Testing unfinalized term";
280 0         0 $t->{id} == $zero->{id};
281             }
282            
283            
284             =head3 notZero
285            
286             Not Zero?
287            
288             =cut
289            
290            
291 0     0 1 0 sub notZero($) {return !isZero($_[0])}
292            
293            
294             =head3 isOne
295            
296             One?
297            
298             =cut
299            
300            
301 0     0 1 0 sub isOne($)
302             {my ($t) = @_;
303 0 0       0 exists $t->{z} or die "Testing unfinalized term";
304 0         0 $t->{id} == $one->{id};
305             }
306            
307            
308             =head3 notOne
309            
310             Not One?
311            
312             =cut
313            
314            
315 0     0 1 0 sub notOne($) {return !isOne($_[0])}
316            
317            
318             =head3 isMinusOne
319            
320             Minus One?
321            
322             =cut
323            
324            
325 0     0 1 0 sub isMinusOne($)
326             {my ($t) = @_;
327 0 0       0 exists $t->{z} or die "Testing unfinalized term";
328 0         0 $t->{id} == $mOne->{id};
329             }
330            
331            
332             =head3 notMinusOne
333            
334             Not Minus One?
335            
336             =cut
337            
338            
339 0     0 1 0 sub notMinusOne($) {return !isMinusOne($_[0])}
340            
341            
342             =head3 i
343            
344             Get/Set i - sqrt(-1)
345            
346             =cut
347            
348            
349 7903     7903 1 11937 sub i($;$)
350             {my ($t) = @_;
351            
352 7903 100       19286 return $t->{i} unless(@_) > 1;
353            
354 7345 100       17835 my $i = ($_[1] == 1 ? $_[1] : intCheck($_[1], 'i'));
355            
356 7345         11651 my $i4 = $i % 4;
357 7345         11565 $t->{i} = $i % 2;
358 7345 50 33     34569 $t->{c} = -$t->{c} if $i4 == 2 or $i4 == 3;
359 7345         13955 $t;
360             }
361            
362            
363             =head3 iby
364            
365             i by power: multiply a term by a power of i
366            
367             =cut
368            
369            
370 0     0 1 0 sub iby($$)
371             {my ($t, $p) = @_;
372            
373 0         0 $t->i($p+$t->{i});
374 0         0 $t;
375             }
376            
377            
378             =head3 Divide
379            
380             Get/Set divide by.
381            
382             =cut
383            
384            
385 9193     9193 1 13445 sub Divide($;$)
386             {my ($t, $d) = @_;
387 9193 100       31717 return $t->{divide} unless @_ > 1;
388 2500         3734 $t->{divide} = $d;
389 2500         5331 $t;
390             }
391            
392            
393             =head3 removeDivide
394            
395             Remove divide
396            
397             =cut
398            
399            
400 757     757 1 929 sub removeDivide($)
401             {my ($t) = @_;
402 757         1400 my $z = $t->clone;
403 757         1230 delete $z->{divide};
404 757         1583 $z->z;
405             }
406            
407            
408             =head3 Sqrt
409            
410             Get/Set square root.
411            
412             =cut
413            
414            
415 4463     4463 1 7109 sub Sqrt($;$)
416             {my ($t, $s) = @_;
417 4463 100       11921 return $t->{sqrt} unless @_ > 1;
418 3888         5670 $t->{sqrt} = $s;
419 3888         8184 $t;
420             }
421            
422            
423             =head3 removeSqrt
424            
425             Remove square root.
426            
427             =cut
428            
429            
430 0     0 1 0 sub removeSqrt($)
431             {my ($t) = @_;
432 0         0 my $z = $t->clone;
433 0         0 delete $z->{sqrt};
434 0         0 $z->z;
435             }
436            
437            
438             =head3 Exp
439            
440             Get/Set exp
441            
442             =cut
443            
444            
445 4422     4422 1 7070 sub Exp($;$)
446             {my ($t, $e) = @_;
447 4422 50       9489 return $t->{exp} unless @_ > 1;
448 4422         6420 $t->{exp} = $e;
449 4422         10434 $t;
450             }
451            
452            
453             =head3 Log
454            
455             # Get/Set log
456            
457             =cut
458            
459            
460 1     1 1 2 sub Log($$)
461             {my ($t, $l) = @_;
462 1 50       5 return $t->{log} unless @_ > 1;
463 1         3 $t->{log} = $l;
464 1         4 $t;
465             }
466            
467            
468             =head3 vp
469            
470             Get/Set variable power.
471            
472             On get: returns the power of a variable, or zero if the variable is not
473             present in the term.
474            
475             On set: Sets the power of a variable. If the power is zero, removes the
476             variable from the term. =cut
477            
478             =cut
479            
480            
481 2463     2463 1 3697 sub vp($$;$)
482             {my ($t, $v) = @_;
483             # $v =~ /^[a-z]+$/i or die "Bad variable name $v";
484            
485 2463 100       9960 return exists($t->{v}{$v}) ? $t->{v}{$v} : 0 if @_ == 2;
    100          
486            
487 1330 100       4867 my $p = ($_[2] == 1 ? $_[2] : intCheck($_[2], 'vp'));
488 1330 100       4159 $t->{v}{$v} = $p if $p;
489 1330 100       5818 delete $t->{v}{$v} unless $p;
490 1330         3712 $t;
491             }
492            
493            
494             =head3 v
495            
496             Get all variables mentioned in the term. Variables to power zero
497             should have been removed by L.
498            
499             =cut
500            
501            
502 754     754 1 1153 sub v($)
503             {my ($t) = @_;
504 754         848 return keys %{$t->{v}};
  754         3195  
505             }
506            
507            
508             =head3 clone
509            
510             Clone a term. The existing term must be finalized, see L: the new
511             term will not be finalized, allowing modifications to be made to it.
512            
513             =cut
514            
515            
516 26904     26904 1 33891 sub clone($)
517             {my ($t) = @_;
518 26904 50       65816 $t->{z} or die "Attempt to clone unfinalized term";
519 26904         262834 my $c = bless {%$t};
520 26904         88666 $c->{v} = {%{$t->{v}}};
  26904         73362  
521 26904         65580 delete @$c{qw(id s z)};
522 26904         61372 $c;
523             }
524            
525            
526             =head3 split
527            
528             Split a term into its components
529            
530             =cut
531            
532            
533 8204     8204 1 10413 sub split($)
534             {my ($t) = @_;
535 8204         14812 my $c = $t->clone;
536 8204         23157 my @c = @$c{qw(sqrt divide exp log)};
537 8204         22028 @$c{qw(sqrt divide exp log)} = ((undef()) x 4);
538 8204         72185 (t=>$c, s=>$c[0], d=>$c[1], e=>$c[2], l=>$c[3]);
539             }
540            
541            
542             =head3 signature
543            
544             Sign the term. Used to optimize addition.
545             Fix the problem of adding different logs
546            
547             =cut
548            
549            
550 40281     40281 1 57077 sub signature($)
551             {my ($t) = @_;
552 40281         59098 my $s = '';
553 40281         47495 $s .= sprintf("%010d", $t->{v}{$_}) . $_ for keys %{$t->{v}};
  40281         194320  
554 40281 100       138875 $s .= '(divide'. $t->{divide} .')' if defined($t->{divide});
555 40281 100       95487 $s .= '(sqrt'. $t->{sqrt} .')' if defined($t->{sqrt});
556 40281 100       125661 $s .= '(exp'. $t->{exp} .')' if defined($t->{exp});
557 40281 100       96830 $s .= '(log'. $t->{log} .')' if defined($t->{log});
558 40281 100       93963 $s .= 'i' if $t->{i} == 1;
559 40281 100       79067 $s = '1' if $s eq '';
560 40281         124269 $s;
561             }
562            
563            
564             =head3 getSignature
565            
566             Get the signature of a term
567            
568             =cut
569            
570            
571 0     0 1 0 sub getSignature($)
572             {my ($t) = @_;
573 0 0       0 exists $t->{z} ? $t->{z} : die "Attempt to get signature of unfinalized term";
574             }
575            
576            
577             =head3 add
578            
579             Add two finalized terms, return result in new term or undef.
580            
581             =cut
582            
583            
584 8525     8525 1 11884 sub add($$)
585             {my ($a, $b) = @_;
586            
587 8525 50 33     41874 $a->{z} and $b->{z} or
588             die "Attempt to add unfinalized terms";
589            
590 8525 100       37440 return undef unless $a->{z} eq $b->{z};
591 8520 100       17819 return $a->clone->timesInt(2)->z if $a == $b;
592            
593 7341         17826 my $z = $a->clone;
594 7341         20823 my $c = $a->{c} * $b->{d}
595             + $b->{c} * $a->{d};
596 7341         119336 my $d = $a->{d} * $b->{d};
597 7341 100       60085 return $zero if $c == 0;
598            
599 5848         49704 $z->c($c)->d(1)->divideInt($d)->z;
600             }
601            
602            
603             =head3 subtract
604            
605             Subtract two finalized terms, return result in new term or undef.
606            
607             =cut
608            
609            
610 0     0 1 0 sub subtract($$)
611             {my ($a, $b) = @_;
612            
613 0 0 0     0 $a->{z} and $b->{z} or
614             die "Attempt to subtract unfinalized terms";
615            
616 0 0       0 return $zero if $a == $b;
617 0 0       0 return $a if $b == $zero;
618 0 0       0 return $b->clone->negate->z if $a == $zero;
619 0 0       0 return undef unless $a->{z} eq $b->{z};
620            
621 0         0 my $z = $a->clone;
622 0         0 my $c = $a->{c} * $b->{d}
623             - $b->{c} * $a->{d};
624 0         0 my $d = $a->{d} * $b->{d};
625            
626 0         0 $z->c($c)->d(1)->divideInt($d)->z;
627             }
628            
629            
630             =head3 multiply
631            
632             Multiply two finalized terms, return the result in a new term or undef
633            
634             =cut
635            
636            
637 9821     9821 1 15773 sub multiply($$)
638             {my ($a, $b) = @_;
639            
640 9821 50 33     50785 $a->{z} and $b->{z} or
641             die "Attempt to multiply unfinalized terms";
642            
643             # Check
644             return undef if
645 9821 100 100     108140 (defined($a->{divide}) and defined($b->{divide})) or
      100        
      66        
      100        
      66        
      33        
      66        
646             (defined($a->{sqrt} ) and defined($b->{sqrt})) or
647             (defined($a->{exp} ) and defined($b->{exp})) or
648             (defined($a->{log} ) and defined($b->{log}));
649            
650             # cdi
651 5962         13287 my $c = $a->{c} * $b->{c};
652 5962         35214 my $d = $a->{d} * $b->{d};
653 5962         20019 my $i = $a->{i} + $b->{i};
654 5962 100       17027 $c = -$c, $i = 0 if $i == 2;
655 5962         13776 my $z = $a->clone->c($c)->d(1)->divideInt($d)->i($i);
656            
657             # v
658             # for my $v($b->v)
659             # {$z->vp($v, $z->vp($v)+$b->vp($v));
660             # }
661            
662 5962 100       8770 for my $v(keys(%{$b->{v}}))
  5962         19464  
  987         4978  
663             {$z->vp($v, (exists($z->{v}{$v}) ? $z->{v}{$v} : 0)+$b->{v}{$v});
664             }
665            
666             # Divide, sqrt, exp, log
667 5962 100       19013 $z->{divide} = $b->{divide} unless defined($a->{divide});
668 5962 100       22880 $z->{sqrt} = $b->{sqrt} unless defined($a->{sqrt});
669 5962 100       13599 $z->{exp} = $b->{exp} unless defined($a->{exp});
670 5962 50       14200 $z->{log} = $b->{log} unless defined($a->{log});
671            
672             # Result
673 5962         12358 $z->z;
674             }
675            
676            
677             =head3 divide2
678            
679             Divide two finalized terms, return the result in a new term or undef
680            
681             =cut
682            
683            
684 251     251 1 453 sub divide2($$)
685             {my ($a, $b) = @_;
686            
687 251 50 33     1538 $a->{z} and $b->{z} or
688             die "Attempt to divide unfinalized terms";
689            
690             # Check
691             return undef if
692 251 50 33     954 (defined($b->{divide}) and (!defined($a->{divide}) or $a->{divide}->id != $b->{divide}->id));
      66        
693             return undef if
694 247 50 66     784 (defined($b->{sqrt} ) and (!defined($a->{sqrt} ) or $a->{sqrt} ->id != $b->{sqrt} ->id));
      66        
695             return undef if
696 230 0 0     610 (defined($b->{exp} ) and (!defined($a->{exp} ) or $a->{exp} ->id != $b->{exp} ->id));
      33        
697             return undef if
698 230 0 0     600 (defined($b->{log} ) and (!defined($a->{log} ) or $a->{log} ->id != $b->{log} ->id));
      33        
699            
700             # cdi
701 230         624 my $c = $a->{c} * $b->{d};
702 230         438 my $d = $a->{d} * $b->{c};
703 230         446 my $i = $a->{i} - $b->{i};
704 230 50       553 $c = -$c, $i = 1 if $i == -1;
705 230         581 my $g = gcd($c, $d);
706 230         414 $c /= $g;
707 230         295 $d /= $g;
708 230         621 my $z = $a->clone->c($c)->d(1)->divideInt($d)->i($i);
709            
710             # v
711 230         1727 for my $v($b->v)
  100         235  
712             {$z->vp($v, $z->vp($v)-$b->vp($v));
713             }
714            
715             # Sqrt, divide, exp, log
716 230 50 33     1108 delete $z->{divide} if defined($a->{divide}) and defined($b->{divide});
717 230 50 66     935 delete $z->{sqrt } if defined($a->{sqrt }) and defined($b->{sqrt });
718 230 50 66     729 delete $z->{exp } if defined($a->{exp }) and defined($b->{exp });
719 230 50 33     711 delete $z->{log } if defined($a->{log }) and defined($b->{log });
720            
721            
722             # Result
723 230         534 $z->z;
724             }
725            
726            
727             =head3 invert
728            
729             Invert a term
730            
731             =cut
732            
733            
734 0     0 1 0 sub invert($)
735             {my ($t) = @_;
736            
737 0 0       0 $t->{z} or die "Attempt to invert unfinalized term";
738            
739             # Check
740             return undef if
741 0 0 0     0 $t->{divide} or
      0        
      0        
742             $t->{sqrt} or
743             $t->{exp} or
744             $t->{log};
745            
746             # cdi
747 0         0 my ($c, $d, $i) = ($t->{c}, $t->{d}, $t->{i});
748 0 0       0 $c = -$c if $i;
749 0         0 my $z = clone($t)->c($d)->d(1)->divideInt($c)->i($i);
750            
751             # v
752 0         0 for my $v($z->v)
  0         0  
753             {$z->vp($v, $z->vp($v));
754             }
755            
756             # Result
757 0         0 $z->z;
758             }
759            
760            
761             =head3 power
762            
763             Take power of term
764            
765             =cut
766            
767            
768 0     0 1 0 sub power($$)
769             {my ($a, $b) = @_;
770            
771 0 0 0     0 $a->{z} and $b->{z} or die "Attempt to take power of unfinalized term";
772            
773             # Check
774 0 0 0     0 return $one if $a == $one or $b == $zero;
775             return undef if
776 0 0 0     0 $a->{divide} or
      0        
      0        
777             $a->{sqrt} or
778             $a->{exp} or
779             $a->{log};
780            
781             return undef if
782 0 0 0     0 $b->{d} != 1 or
      0        
      0        
      0        
      0        
783             $b->{i} == 1 or
784             $b->{divide} or
785             $b->{sqrt} or
786             $b->{exp} or
787             $b->{log};
788            
789             # cdi
790 0         0 my ($c, $d, $i) = ($a->{c}, $a->{d}, $a->{i});
791            
792 0         0 my $p = $b->{c};
793 0 0       0 if ($p < 0)
  0         0  
794             {$a = invert($a);
795 0 0       0 return undef unless $a;
796 0         0 $p = -$p;
797 0 0       0 return $a if $p == 1;
798             }
799            
800 0         0 my $z = $a->clone->z;
801 0         0 $z = $z->multiply($a) for (2..$p);
802            
803 0         0 $i *= $p;
804 0         0 $z = $z->clone->i($i);
805            
806             # v
807             # for my $v($z->v)
808             # {$z->vp($v, $p*$z->vp($v));
809             # }
810            
811             # Result
812 0         0 $z->z;
813             }
814            
815            
816             =head3 sqrt2
817            
818             Square root of a term
819            
820             =cut
821            
822            
823 54     54 1 107 sub sqrt2($)
824             {my ($t) = @_;
825            
826 54 50       198 $t->{z} or die "Attempt to sqrt unfinalized term";
827            
828             # Check
829 54 50 33     809 return undef if $t->{i} or
      33        
      33        
      33        
830             $t->{divide} or
831             $t->{sqrt} or
832             $t->{exp} or
833             $t->{log};
834            
835             # cd
836 54         160 my ($c, $d, $i) = ($t->{c}, $t->{d}, 0);
837 54 100       150 $c = -$c, $i = 1 if $c < 0;
838            
839 54 100       358 my $c2 = sqrt($c); return undef unless $c2*$c2 == $c;
  54         255  
840 29 50       61 my $d2 = sqrt($d); return undef unless $d2*$d2 == $d;
  29         87  
841            
842 29         173 my $z = clone($t)->c($c2)->d($d2)->i($i);
843            
844             # v
845 29         196 for my $v($t->v)
  8         22  
846             {my $p = $z->vp($v);
847 8 100       43 return undef unless $p % 2 == 0;
848 5         17 $z->vp($v, $p/2);
849             }
850            
851             # Result
852 26         77 $z->z;
853             }
854            
855            
856             =head3 exp2
857            
858             Exponential of a term
859            
860             =cut
861            
862            
863 1547     1547 1 2002 sub exp2($)
864             {my ($t) = @_;
865            
866 1547 50       8465 $t->{z} or die "Attempt to use unfinalized term in exp";
867            
868 1547 100       3608 return $one if $t == $zero;
869 1446 50 33     13618 return undef if $t->{divide} or
      33        
      33        
870             $t->{sqrt} or
871             $t->{exp} or
872             $t->{log};
873 1446 100       3860 return undef unless $t->{i} == 1;
874 1096 50 66     2900 return undef unless $t->{d} == 1 or
      33        
875             $t->{d} == 2 or
876             $t->{d} == 4;
877 1096 100 100     2350 return undef unless scalar(keys(%{$t->{v}})) == 1 and
  1096   66     8216  
878             exists($t->{v}{pi}) and
879             $t->{v}{pi} == 1;
880            
881 26         53 my $c = $t->{c};
882 26         45 my $d = $t->{d};
883 26 100       61 $c *= 2 if $d == 1;
884 26         38 $c %= 4;
885            
886 26 100       62 return $one if $c == 0;
887 25 100       94 return $i if $c == 1;
888 16 100       60 return $mOne if $c == 2;
889 10 50       39 return $mI if $c == 3;
890             }
891            
892            
893             =head3 sin2
894            
895             Sine of a term
896            
897             =cut
898            
899            
900 120     120 1 171 sub sin2($)
901             {my ($t) = @_;
902            
903 120 50       400 $t->{z} or die "Attempt to use unfinalized term in sin";
904            
905 120 100       317 return $zero if $t == $zero;
906 117 50 33     1376 return undef if $t->{divide} or
      33        
      33        
907             $t->{sqrt} or
908             $t->{exp} or
909             $t->{log};
910 117 100       374 return undef unless $t->{i} == 0;
911 113 100       163 return undef unless scalar(keys(%{$t->{v}})) == 1;
  113         351  
912 111 100       512 return undef unless exists($t->{v}{pi});
913 20 50       57 return undef unless $t->{v}{pi} == 1;
914            
915 20         33 my $c = $t->{c};
916 20         32 my $d = $t->{d};
917 20 50 100     138 return undef unless $d== 1 or $d == 2 or $d == 3 or $d == 6;
      66        
      66        
918 20 100       58 $c *= 6 if $d == 1;
919 20 100       50 $c *= 3 if $d == 2;
920 20 50       41 $c *= 2 if $d == 3;
921 20         23 $c = $c % 12;
922            
923 20 100       44 return $zero if $c == 0;
924 17 100       36 return $half if $c == 1;
925 15 50       28 return undef if $c == 2;
926 15 100       36 return $one if $c == 3;
927 12 50       39 return undef if $c == 4;
928 12 100       31 return $half if $c == 5;
929 10 100       32 return $zero if $c == 6;
930 7 100       24 return $mHalf if $c == 7;
931 5 50       11 return $undef if $c == 8;
932 5 100       20 return $mOne if $c == 9;
933 2 50       6 return $undef if $c == 10;
934 2 50       12 return $mHalf if $c == 11;
935 0 0       0 return $zero if $c == 12;
936             }
937            
938            
939             =head3 cos2
940            
941             Cosine of a term
942            
943             =cut
944            
945            
946 125     125 1 223 sub cos2($)
947             {my ($t) = @_;
948            
949 125 50       390 $t->{z} or die "Attempt to use unfinalized term in cos";
950            
951 125 100       398 return $one if $t == $zero;
952 122 50 33     2049 return undef if $t->{divide} or
      33        
      33        
953             $t->{sqrt} or
954             $t->{exp} or
955             $t->{log};
956 122 100       342 return undef unless $t->{i} == 0;
957 118 100       145 return undef unless scalar(keys(%{$t->{v}})) == 1;
  118         10895  
958 116 100       524 return undef unless exists($t->{v}{pi});
959 20 50       117 return undef unless $t->{v}{pi} == 1;
960            
961 20         41 my $c = $t->{c};
962 20         46 my $d = $t->{d};
963 20 50 100     156 return undef unless $d== 1 or $d == 2 or $d == 3 or $d == 6;
      66        
      33        
964 20 100       48 $c *= 6 if $d == 1;
965 20 100       49 $c *= 3 if $d == 2;
966 20 100       48 $c *= 2 if $d == 3;
967 20         31 $c = $c % 12;
968            
969 20 100       1181 return $half if $c == 10;
970 18 50       38 return $undef if $c == 11;
971 18 50       49 return $one if $c == 12;
972 18 100       52 return $one if $c == 0;
973 15 50       30 return undef if $c == 1;
974 15 100       39 return $half if $c == 2;
975 13 100       39 return $zero if $c == 3;
976 10 100       32 return $mHalf if $c == 4;
977 8 50       24 return $undef if $c == 5;
978 8 100       30 return $mOne if $c == 6;
979 5 50       18 return $undef if $c == 7;
980 5 100       23 return $mHalf if $c == 8;
981 3 50       16 return $zero if $c == 9;
982             }
983            
984            
985             =head3 log2
986            
987             Log of a term
988            
989             =cut
990            
991            
992 1     1 1 2 sub log2($)
993             {my ($a) = @_;
994            
995 1 50       5 $a->{z} or die "Attempt to use unfinalized term in log";
996            
997 1 50       5 return $zero if $a == $one;
998 1         5 return undef;
999             }
1000            
1001            
1002             =head3 id
1003            
1004             Get Id of a term
1005            
1006             =cut
1007            
1008            
1009 0     0 1 0 sub id($)
1010             {my ($t) = @_;
1011 0 0       0 $t->{id} or die "Term $t not yet finalized";
1012 0         0 $t->{id};
1013             }
1014            
1015            
1016             =head3 zz
1017            
1018             # Check term finalized
1019            
1020             =cut
1021            
1022            
1023 0     0 1 0 sub zz($)
1024             {my ($t) = @_;
1025 0 0       0 $t->{z} or die "Term $t not yet finalized";
1026 0         0 $t;
1027             }
1028            
1029            
1030             =head3 z
1031            
1032             Finalize creation of the term. Once a term has been finalized, it
1033             becomes readonly, which allows optimization to be performed. =cut
1034            
1035             =cut
1036            
1037            
1038             my $lock = 0; # Hash locking
1039             my $z = 0; # Term counter
1040             my %z; # Terms finalized
1041            
1042 25949     25949 1 49023 sub z($)
1043             {my ($t) = @_;
1044 25949 50       60460 !exists($t->{z}) or die "Already finalized this term";
1045            
1046 25949         51961 my $p = $t->print;
1047 25949 100       124049 return $z{$p} if defined($z{$p});
1048 13841         42975 $z{$p} = $t;
1049 13841         57493 weaken($z{$p}); # Greatly reduces memory usage
1050            
1051 13841         41465 $t->{s} = $p;
1052 13841         32552 $t->{z} = $t->signature;
1053 13841         26050 $t->{id} = ++$z;
1054            
1055             #HashUtil lock_hash(%{$t->{v}}) if $lock;
1056             #HashUtil lock_hash %$t if $lock;
1057 13841         48645 $t;
1058             }
1059            
1060             #sub DESTROY($)
1061             # {my ($t) = @_;
1062             # delete $z{$t->{s}} if defined($t) and exists $t->{s};
1063             # }
1064            
1065 0     0 0 0 sub lockHashes()
1066             {my ($l) = @_;
1067             #HashUtil for my $t(values %z)
1068             #HashUtil {lock_hash(%{$t->{v}});
1069             #HashUtil lock_hash %$t;
1070             #HashUtil }
1071 0         0 $lock = 1;
1072             }
1073            
1074            
1075             =head3 print
1076            
1077             Print
1078            
1079             =cut
1080            
1081            
1082 78021     78021 1 97423 sub print($)
1083             {my ($t) = @_;
1084 78021 100       788326 return $t->{s} if defined($t->{s});
1085 25949         33736 my @k = keys %{$t->{v}};
  25949         89428  
1086 25949         46829 my $v = $t->{v};
1087 25949         35255 my $s = '';
1088 25949         56605 $s .= $t->{c};
1089 25949 100       94519 $s .= '/'.$t->{d} if $t->{d} != 1;
1090 25949 100       134134 $s .= '*i' if $t->{i} == 1;
1091 25949         62609 $s .= '*$'.$_ for grep {$v->{$_} == 1} @k;
  7883         33729  
1092 25949         51124 $s .= '/$'.$_ for grep {$v->{$_} == -1} @k;
  7883         22939  
1093 25949         48622 $s .= '*$'.$_.'**'. $v->{$_} for grep {$v->{$_} > 1} @k;
  7883         22366  
1094 25949         45921 $s .= '/$'.$_.'**'.-$v->{$_} for grep {$v->{$_} < -1} @k;
  7883         20683  
1095 25949 100       84138 $s .= '/('. $t->{divide} .')' if $t->{divide};
1096 25949 100       63476 $s .= '*sqrt('. $t->{sqrt} .')' if $t->{sqrt};
1097 25949 100       69920 $s .= '*exp('. $t->{exp} .')' if $t->{exp};
1098 25949 100       60680 $s .= '*log('. $t->{log} .')' if $t->{log};
1099 25949         70571 $s;
1100             }
1101            
1102            
1103             =head3 constants
1104            
1105             Useful constants
1106            
1107             =cut
1108            
1109            
1110 0     0 0 0 $zero = new()->c(0)->z; sub zero () {$zero}
1111 537     537 0 3573 $one = new()->z; sub one () {$one}
1112 0     0 0 0 $two = new()->c(2)->z; sub two () {$two}
1113 0     0 0 0 $mOne = new()->c(-1)->z; sub mOne () {$mOne}
1114 0     0 0 0 $i = new()->i(1)->z; sub pI () {$pI}
1115 0     0 0 0 $mI = new()->c(-1)->i(1)->z; sub mI () {$mI}
1116 0     0 0 0 $half = new()->c( 1)->d(2)->z; sub half () {$half}
1117 0     0 0 0 $mHalf = new()->c(-1)->d(2)->z; sub mHalf() {$mHalf}
1118 0     0 0 0 $pi = new()->vp('pi', 1)->z; sub pi () {$pi}
1119            
1120            
1121             =head2 import
1122            
1123             Export L to calling package with a name specifed by the
1124             caller, or as B by default. =cut
1125            
1126             =cut
1127            
1128            
1129             sub import
1130 45     45   245 {my %P = (program=>@_);
1131 45         77 my %p; $p{lc()} = $P{$_} for(keys(%P));
  45         319  
1132            
1133             #_______________________________________________________________________
1134             # New symbols term constructor - export to calling package.
1135             #_______________________________________________________________________
1136            
1137 45         213 my $s = "pack"."age XXXX;\n". <<'END';
1138             no warnings 'redefine';
1139             sub NNNN
1140             {return SSSSnewFromStrings(@_);
1141             }
1142             use warnings 'redefine';
1143             END
1144            
1145             #_______________________________________________________________________
1146             # Export to calling package.
1147             #_______________________________________________________________________
1148            
1149 45         88 my $name = 'term';
1150 45 50       209 $name = $p{term} if exists($p{term});
1151 45         137 my ($main) = caller();
1152 45         101 my $pack = __PACKAGE__.'::';
1153            
1154 45         424 $s=~ s/XXXX/$main/g;
1155 45         1343 $s=~ s/NNNN/$name/g;
1156 45         195 $s=~ s/SSSS/$pack/g;
1157 45     45 0 354 eval($s);
  45     45   170  
  45     1795   6660  
  45         6800  
  45         76  
  45         1468  
  45         4741  
  1795         6604  
1158            
1159             #_______________________________________________________________________
1160             # Check options supplied by user
1161             #_______________________________________________________________________
1162            
1163 45         174 delete @p{qw(program terms)};
1164            
1165 45 50       1231 croak "Unknown option(s) for ". __PACKAGE__ .": ". join(' ', keys(%p))."\n\n". <<'END' if keys(%p);
1166            
1167             Valid options are:
1168            
1169             terms=>'name' Desired name of the constructor routine for creating
1170             new terms. The default is 'term'.
1171             END
1172             }
1173            
1174            
1175             =head2 Operators
1176            
1177            
1178             =head3 Operator Overloads
1179            
1180             Operator Overloads
1181            
1182             =cut
1183            
1184            
1185             use overload
1186 45         1576 '+' =>\&add3,
1187             '-' =>\&negate3,
1188             '*' =>\&multiply3,
1189             '/' =>\÷3,
1190             '**' =>\&power3,
1191             '==' =>\&equals3,
1192             'sqrt' =>\&sqrt3,
1193             'exp' =>\&exp3,
1194             'log' =>\&log3,
1195             'sin' =>\&sin3,
1196             'cos' =>\&cos3,
1197             '""' =>\&print3,
1198 45     45   2086 fallback=>1;
  45         164  
1199            
1200            
1201             =head3 add3
1202            
1203             Add operator.
1204            
1205             =cut
1206            
1207            
1208             sub add3
1209 0     0 1 0 {my ($a, $b) = @_;
1210 0 0       0 $b = newFromString("$b") unless ref($b) eq __PACKAGE__;
1211 0 0 0     0 $a->{z} and $b->{z} or die "Add using unfinalized terms";
1212 0         0 $a->add($b);
1213             }
1214            
1215            
1216             =head3 negate3
1217            
1218             Negate operator.
1219            
1220             =cut
1221            
1222            
1223             sub negate3
1224 0     0 1 0 {my ($a, $b, $c) = @_;
1225            
1226 0 0       0 if (defined($b))
  0 0       0  
1227 0 0       0 {$b = newFromString("$b") unless ref($b) eq __PACKAGE__;
1228 0 0 0     0 $a->{z} and $b->{z} or die "Negate using unfinalized terms";
1229 0 0       0 return $b->subtract($a) if $c;
1230 0 0       0 return $a->subtract($b) unless $c;
1231             }
1232             else
1233             {$a->{z} or die "Negate single unfinalized terms";
1234 0         0 return $a->negate;
1235             }
1236             }
1237            
1238            
1239             =head3 multiply3
1240            
1241             Multiply operator.
1242            
1243             =cut
1244            
1245            
1246             sub multiply3
1247 0     0 1 0 {my ($a, $b) = @_;
1248 0 0       0 $b = newFromString("$b") unless ref($b) eq __PACKAGE__;
1249 0 0 0     0 $a->{z} and $b->{z} or die "Multiply using unfinalized terms";
1250 0         0 $a->multiply($b);
1251             }
1252            
1253            
1254             =head3 divide3
1255            
1256             Divide operator.
1257            
1258             =cut
1259            
1260            
1261             sub divide3
1262 0     0 1 0 {my ($a, $b, $c) = @_;
1263 0 0       0 $b = newFromString("$b") unless ref($b) eq __PACKAGE__;
1264 0 0 0     0 $a->{z} and $b->{z} or die "Divide using unfinalized terms";
1265 0 0       0 return $b->divide2($a) if $c;
1266 0 0       0 return $a->divide2($b) unless $c;
1267             }
1268            
1269            
1270             =head3 power3
1271            
1272             Power operator.
1273            
1274             =cut
1275            
1276            
1277             sub power3
1278 0     0 1 0 {my ($a, $b) = @_;
1279 0 0       0 $b = newFromString("$b") unless ref($b) eq __PACKAGE__;
1280 0 0 0     0 $a->{z} and $b->{z} or die "Power using unfinalized terms";
1281 0         0 $a->power($b);
1282             }
1283            
1284            
1285             =head3 equals3
1286            
1287             Equals operator.
1288            
1289             =cut
1290            
1291            
1292             sub equals3
1293 10313     10313 1 13784 {my ($a, $b) = @_;
1294 10313 50 33     23834 if (ref($b) eq __PACKAGE__)
  10313 50       47400  
1295 0 0       0 {$a->{z} and $b->{z} or die "Equals using unfinalized terms";
1296 10313         43350 return $a->{id} == $b->{id};
1297             }
1298             else
1299             {$a->{z} or die "Equals using unfinalized terms";
1300 0         0 return $a->print eq "$b";
1301             }
1302             }
1303            
1304            
1305             =head3 print3
1306            
1307             Print operator.
1308            
1309             =cut
1310            
1311            
1312             sub print3
1313 28306     28306 1 36378 {my ($a) = @_;
1314 28306 50       66067 $a->{z} or die "Print of unfinalized term";
1315 28306         65605 $a->print();
1316             }
1317            
1318            
1319             =head3 sqrt3
1320            
1321             Square root operator.
1322            
1323             =cut
1324            
1325            
1326             sub sqrt3
1327 0     0 1   {my ($a) = @_;
1328 0 0         $a->{z} or die "Sqrt of unfinalized term";
1329 0           $a->sqrt2();
1330             }
1331            
1332            
1333             =head3 exp3
1334            
1335             Exponential operator.
1336            
1337             =cut
1338            
1339            
1340             sub exp3
1341 0     0 1   {my ($a) = @_;
1342 0 0         $a->{z} or die "Exp of unfinalized term";
1343 0           $a->exp2();
1344             }
1345            
1346            
1347             =head3 sin3
1348            
1349             Sine operator.
1350            
1351             =cut
1352            
1353            
1354             sub sin3
1355 0     0 1   {my ($a) = @_;
1356 0 0         $a->{z} or die "Sin of unfinalized term";
1357 0           $a->sin2();
1358             }
1359            
1360            
1361             =head3 cos3
1362            
1363             Cosine operator.
1364            
1365             =cut
1366            
1367            
1368             sub cos3
1369 0     0 1   {my ($a) = @_;
1370 0 0         $a->{z} or die "Cos of unfinalized term";
1371 0           $a->cos2();
1372             }
1373            
1374            
1375             =head3 log3
1376            
1377             Log operator.
1378            
1379             =cut
1380            
1381            
1382             sub log3
1383 0     0 1   {my ($a) = @_;
1384 0 0         $a->{z} or die "Log of unfinalized term";
1385 0           $a->log2();
1386             }
1387            
1388            
1389             =head2 test
1390            
1391             Tests
1392            
1393             =cut
1394            
1395            
1396 0     0 1   sub test()
1397             {my ($a, $b, $c);
1398             # lockHashes();
1399 0 0         $a = n(0); $a == $zero or die "100";
  0            
1400 0 0         $a = n(1); $a == $one or die "101";
  0            
1401 0 0         $a = n(2); $a == $two or die "102";
  0            
1402 0 0         $b = n(3); $b == 3 or die "103";
  0            
1403 0 0         $c = $a+$a; $c == 4 or die "104";
  0            
1404 0 0         $c = $a+$b; $c == 5 or die "105";
  0            
1405 0 0         $c = $a+$b+$a+$b; $c == 10 or die "106";
  0            
1406 0 0         $c = $a+1; $c == 3 or die "107";
  0            
1407 0 0         $c = $a+2; $c == 4 or die "108";
  0            
1408 0 0         $c = $b-1; $c == 2 or die "109";
  0            
1409 0 0         $c = $b-2; $c == 1 or die "110";
  0            
1410 0 0         $c = $b-9; $c == -6 or die "111";
  0            
1411 0 0         $c = $a/2; $c == $one or die "112";
  0            
1412 0 0         $c = $a/4; $c == '1/2' or die "113";
  0            
1413 0 0         $c = $a*2/2; $c == $two or die "114";
  0            
1414 0 0         $c = $a*2/4; $c == $one or die "115";
  0            
1415 0 0         $c = $a**2; $c == 4 or die "116";
  0            
1416 0 0         $c = $a**10; $c == 1024 or die "117";
  0            
1417 0 0         $c = sqrt($a**2); $c == $a or die "118";
  0            
1418 0 0         $d = n(-1); $d == -1 or die "119";
  0            
1419 0 0         $c = sqrt($d); $c == '1*i' or die "120";
  0            
1420 0 0         $d = n(4); $d == 4 or die "121";
  0            
1421 0 0         $c = sqrt($d); $c == 2 or die "122";
  0            
1422 0 0         $c = n('x*y2')/n('a*b2'); $c == '1*$x/$a*$y**2/$b**2' or die "122";
  0            
1423            
1424 0 0         $a = n('x'); $a == '1*$x' or die "21";
  0            
1425 0 0         $b = n('2*x**2'); $b == '2*$x**2' or die "22";
  0            
1426 0 0         $c = $a+$a; $c == '2*$x' or die "23";
  0            
1427 0 0         $c = $a+$a+$a; $c == '3*$x' or die "24";
  0            
1428 0 0         $c = $a-$a; $c == $zero or die "25";
  0            
1429 0 0         $c = $a-$a-$a; $c == '-1*$x' or die "26";
  0            
1430 0 0         $c = $a*$b; $c == '2*$x**3' or die "27";
  0            
1431 0 0         $c = $a*$b*$a*$b; $c == '4*$x**6' or die "28";
  0            
1432 0 0         $c = $b/$a; $c == '2*$x' or die "29";
  0            
1433 0           $c = $a**2/$b;
1434            
1435 0 0         $c == '1/2' or die "29";
1436 0 0         $c = sqrt($a**4/($b/2)); $c == $a or die "29";
  0            
1437            
1438 0 0         $a = sin($zero); $a == -0 or die "301";
  0            
1439 0 0         $a = sin($pi/6); $a == $half or die "302";
  0            
1440 0 0         $a = sin($pi/2); $a == 1 or die "303";
  0            
1441 0 0         $a = sin(5*$pi/6); $a == $half or die "304";
  0            
1442 0 0         $a = sin(120*$pi/120); $a == $zero or die "305";
  0            
1443 0 0         $a = sin(7*$pi/6); $a == -$half or die "306";
  0            
1444 0 0         $a = sin(3*$pi/2); $a == -1 or die "307";
  0            
1445 0 0         $a = sin(110*$pi/ 60); $a == '-1/2' or die "308";
  0            
1446 0 0         $a = sin(2*$pi); $a == $zero or die "309";
  0            
1447 0 0         $a = sin(-$zero); $a == $zero or die "311";
  0            
1448 0 0         $a = sin(-$pi/6); $a == -$half or die "312";
  0            
1449 0 0         $a = sin(-$pi/2); $a == -$one or die "313";
  0            
1450 0 0         $a = sin(-5*$pi/6); $a == -$half or die "314";
  0            
1451 0 0         $a = sin(-120*$pi/120); $a == -$zero or die "315";
  0            
1452 0 0         $a = sin(-7*$pi/6); $a == $half or die "316";
  0            
1453 0 0         $a = sin(-3*$pi/2); $a == $one or die "317";
  0            
1454 0 0         $a = sin(-110*$pi/ 60); $a == $half or die "318";
  0            
1455 0 0         $a = sin(-2*$pi); $a == $zero or die "319";
  0            
1456 0 0         $a = cos($zero); $a == $one or die "321";
  0            
1457 0 0         $a = cos($pi/3); $a == $half or die "322";
  0            
1458 0 0         $a = cos($pi/2); $a == $zero or die "323";
  0            
1459 0 0         $a = cos(4*$pi/6); $a == -$half or die "324";
  0            
1460 0 0         $a = cos(120*$pi/120); $a == -$one or die "325";
  0            
1461 0 0         $a = cos(8*$pi/6); $a == -$half or die "326";
  0            
1462 0 0         $a = cos(3*$pi/2); $a == $zero or die "327";
  0            
1463 0 0         $a = cos(100*$pi/ 60); $a == $half or die "328";
  0            
1464 0 0         $a = cos(2*$pi); $a == $one or die "329";
  0            
1465 0 0         $a = cos(-$zero); $a == $one or die "331";
  0            
1466 0 0         $a = cos(-$pi/3); $a == +$half or die "332";
  0            
1467 0 0         $a = cos(-$pi/2); $a == $zero or die "333";
  0            
1468 0 0         $a = cos(-4*$pi/6); $a == -$half or die "334";
  0            
1469 0 0         $a = cos(-120*$pi/120); $a == -$one or die "335";
  0            
1470 0 0         $a = cos(-8*$pi/6); $a == -$half or die "336";
  0            
1471 0 0         $a = cos(-3*$pi/2); $a == $zero or die "337";
  0            
1472 0 0         $a = cos(-100*$pi/ 60); $a == $half or die "338";
  0            
1473 0 0         $a = cos(-2*$pi); $a == $one or die "339";
  0            
1474 0 0         $a = exp($zero); $a == $one or die "340";
  0            
1475 0 0         $a = exp($i*$pi/2); $a == $i or die "341";
  0            
1476 0 0         $a = exp($i*$pi); $a == -$one or die "342";
  0            
1477 0 0         $a = exp(3*$i*$pi/2); $a == -$i or die "343";
  0            
1478 0 0         $a = exp(4*$i*$pi/2); $a == $one or die "344";
  0            
1479             }
1480            
1481             test unless caller;
1482            
1483             #_______________________________________________________________________
1484             # Package installed successfully
1485             #_______________________________________________________________________
1486            
1487             1;
1488            
1489             __DATA__