File Coverage

blib/lib/Math/Algebra/Symbols/Term.pm
Criterion Covered Total %
statement 354 630 56.1
branch 247 550 44.9
condition 77 210 36.6
subroutine 44 81 54.3
pod 61 72 84.7
total 783 1543 50.7


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