File Coverage

blib/lib/Rstats/Util.pm
Criterion Covered Total %
statement 250 503 49.7
branch 204 746 27.3
condition 54 128 42.1
subroutine 52 52 100.0
pod 0 45 0.0
total 560 1474 37.9


line stmt bran cond sub pod time code
1             package Rstats::Util;
2              
3 12     12   244504 use strict;
  12         84  
  12         285  
4 12     12   47 use warnings;
  12         18  
  12         347  
5 12     12   67 use Carp 'croak';
  12         33  
  12         1001  
6              
7             require Rstats::Element::NA;
8             require Rstats::Element::Logical;
9             require Rstats::Element::Complex;
10             require Rstats::Element::Character;
11             require Rstats::Element::Integer;
12             require Rstats::Element::Double;
13 12     12   63 use Scalar::Util ();
  12         18  
  12         180  
14 12     12   48 use B ();
  12         19  
  12         185  
15 12     12   2007 use Math::Complex ();
  12         40483  
  12         221  
16 12     12   1688 use POSIX ();
  12         20439  
  12         61769  
17              
18             # Special values
19             my $na = Rstats::Element::NA->new;
20             my $nan = Rstats::Element::Double->new(flag => 'nan');
21             my $inf = Rstats::Element::Double->new(flag => 'inf');
22             my $negative_inf = Rstats::Element::Double->new(flag => '-inf');
23             my $true = logical(1);
24             my $false = logical(0);
25              
26             # Address
27             my $true_ad = Scalar::Util::refaddr $true;
28             my $false_ad = Scalar::Util::refaddr $false;
29             my $na_ad = Scalar::Util::refaddr $na;
30             my $nan_ad = Scalar::Util::refaddr $nan;
31             my $inf_ad = Scalar::Util::refaddr $inf;
32             my $negative_inf_ad = Scalar::Util::refaddr $negative_inf;
33              
34 203     203 0 5259 sub TRUE { $true }
35 2768     2768 0 6860 sub FALSE { $false }
36 36     36 0 5188 sub NA { $na }
37 15     15 0 4288 sub NaN { $nan }
38 18     18 0 4439 sub Inf { $inf }
39 8     8 0 881 sub negativeInf { $negative_inf }
40              
41 4318 50   4318 0 16633 sub is_nan { ref $_[0] && (Scalar::Util::refaddr $_[0] == $nan_ad) }
42 14758 100   14758 0 48774 sub is_na { ref $_[0] && (Scalar::Util::refaddr $_[0] == $na_ad) }
43 4049 100   4049 0 5594 sub is_infinite { is_positive_infinite($_[0]) || is_negative_infinite($_[0]) }
44 4049 50   4049 0 12519 sub is_positive_infinite { ref $_[0] && (Scalar::Util::refaddr $_[0] == $inf_ad) }
45 4042 50   4042 0 16504 sub is_negative_infinite { ref $_[0] && (Scalar::Util::refaddr $_[0] == $negative_inf_ad) }
46             sub is_finite {
47 4   66 4 0 466 return is_integer($_[0]) || (is_double($_[0]) && defined $_[0]->value);
48             }
49              
50 23518     23518 0 52572 sub is_character { ref $_[0] eq 'Rstats::Element::Character' }
51 19334     19334 0 37424 sub is_complex { ref $_[0] eq 'Rstats::Element::Complex' }
52 23276     23276 0 49047 sub is_double { ref $_[0] eq 'Rstats::Element::Double' }
53 19614     19614 0 43272 sub is_integer { ref $_[0] eq 'Rstats::Element::Integer' }
54 10764     10764 0 20713 sub is_logical { ref $_[0] eq 'Rstats::Element::Logical' }
55              
56 171     171 0 584 sub character { Rstats::Element::Character->new(value => shift) }
57             sub complex {
58 65     65 0 8636 my ($re_value, $im_value) = @_;
59            
60 65         101 my $re = double($re_value);
61 65         370 my $im = double($im_value);
62 65         302 my $z = complex_double($re, $im);
63            
64 65         390 return $z;
65             }
66             sub complex_double {
67 87     87 0 180 my ($re, $im) = @_;
68            
69 87         162 my $z = Rstats::Element::Complex->new(re => $re, im => $im);
70             }
71 4029   50 4029 0 16019 sub double { Rstats::Element::Double->new(value => shift, flag => shift || 'normal') }
72 31     31 0 208 sub integer { Rstats::Element::Integer->new(value => int(shift)) }
73 24     24 0 70 sub logical { Rstats::Element::Logical->new(value => shift) }
74              
75             sub looks_like_number {
76 34     34 0 75 my $value = shift;
77            
78 34 50 33     85 return if !defined $value || !CORE::length $value;
79 34         44 $value =~ s/^ +//;
80 34         38 $value =~ s/ +$//;
81            
82 34 100       68 if (Scalar::Util::looks_like_number $value) {
83 30         89 return $value + 0;
84             }
85             else {
86 4         8 return;
87             }
88             }
89              
90             sub looks_like_complex {
91 13     13 0 61 my $value = shift;
92            
93 13 50 33     39 return if !defined $value || !CORE::length $value;
94 13         20 $value =~ s/^ +//;
95 13         18 $value =~ s/ +$//;
96            
97 13         15 my $re;
98             my $im;
99            
100 13 100       55 if ($value =~ /^([\+\-]?[^\+\-]+)i$/) {
    50          
101 3         4 $re = 0;
102 3         6 $im = $1;
103             }
104             elsif($value =~ /^([\+\-]?[^\+\-]+)(?:([\+\-][^\+\-i]+)i)?$/) {
105 10         17 $re = $1;
106 10         14 $im = $2;
107 10 100       16 $im = 0 unless defined $im;
108             }
109             else {
110 0         0 return;
111             }
112            
113 13 100 66     19 if (defined Rstats::Util::looks_like_number($re) && defined Rstats::Util::looks_like_number($im)) {
114 11         39 return {re => $re + 0, im => $im + 0};
115             }
116             else {
117 2         4 return;
118             }
119             }
120              
121             sub element {
122 27     27 0 32 my $value = shift;
123            
124 27 50       37 if (!ref $value) {
125 27 50       34 if (is_perl_number($value)) {
126 27         38 return double($value);
127             }
128             else {
129 0         0 return character($value);
130             }
131             }
132             else {
133 0         0 return $value;
134             }
135 0 0 0     0 if (is_character($value) || is_integer($value) || is_double($value)) {
      0        
136 0         0 return $value->value;
137             }
138             else {
139 0         0 return $value;
140             }
141             }
142              
143             sub value {
144 8933     8933 0 15685 my $element = shift;
145            
146 8933 100 100     11627 if (is_character($element)
    100 100        
      100        
      100        
147             || is_integer($element)
148             || (is_double($element) && !is_nan($element) && !is_infinite($element))
149             ) {
150 4115         57565 return $element->value;
151             }
152             elsif (is_complex($element)) {
153             return {
154 82         1235 re => value($element->re),
155             im => value($element->im)
156             };
157             }
158             else {
159 4736         10696 return $element;
160             }
161             }
162              
163             sub is_perl_number {
164 3757     3757 0 5010 my ($value) = @_;
165            
166 3757 50       5159 return unless defined $value;
167            
168 3757   66     22058 return B::svref_2object(\$value)->FLAGS & (B::SVp_IOK | B::SVp_NOK)
169             && 0 + $value eq $value
170             && $value * 0 == 0
171             }
172              
173             sub to_string {
174 345     345 0 1506 my $element = shift;
175            
176 345 100       487 if (is_na($element)) {
    100          
    100          
    100          
    50          
    50          
177 2         9 return 'NA';
178             }
179             elsif (is_character($element)) {
180 24         332 return $element->value . "";
181             }
182             elsif (is_complex($element)) {
183 5         89 my $re = to_string($element->re);
184 5         89 my $im = to_string($element->im);
185            
186 5         29 my $str = "$re";
187 5 100       15 $str .= '+' if $im >= 0;
188 5         17 $str .= $im . 'i';
189             }
190             elsif (is_double($element)) {
191            
192 308         4045 my $flag = $element->flag;
193            
194 308 100       4841 if (defined $element->value) {
    100          
    100          
    50          
195 303         4541 return $element->value . "";
196             }
197             elsif ($flag eq 'nan') {
198 2         18 return 'NaN';
199             }
200             elsif ($flag eq 'inf') {
201 2         21 return 'Inf';
202             }
203             elsif ($flag eq '-inf') {
204 1         10 return '-Inf';
205             }
206             }
207             elsif (is_integer($element)) {
208 0         0 return $element->value . "";
209             }
210             elsif (is_logical($element)) {
211 6 100       94 return $element->value ? 'TRUE' : 'FALSE'
212             }
213             else {
214 0         0 croak "Invalid type";
215             }
216             }
217              
218             sub negation {
219 16     16 0 106 my $element1 = shift;
220            
221 16 100 33     33 if (is_na($element1)) {
    50          
    100          
    100          
    50          
222 1         4 return NA;
223             }
224             elsif (is_character($element1)) {
225 0         0 croak 'argument is not interpretable as logical'
226             }
227             elsif (is_complex($element1)) {
228 1         21 return complex_double(negation($element1->re), negation($element1->im));
229             }
230             elsif (is_double($element1)) {
231            
232 12         192 my $flag = $element1->flag;
233 12 100       217 if (defined $element1->value) {
    100          
    100          
    50          
234 7         109 return double(-$element1->value);
235             }
236             elsif ($flag eq 'nan') {
237 1         9 return NaN;
238             }
239             elsif ($flag eq 'inf') {
240 3         23 return negativeInf;
241             }
242             elsif ($flag eq '-inf') {
243 1         19 return Inf;
244             }
245             }
246             elsif (is_integer($element1) || is_logical($element1)) {
247 2         39 return integer(-$element1->value);
248             }
249             else {
250 0         0 croak "Invalid type";
251             }
252             }
253              
254             sub bool {
255 4145     4145 0 4592 my $element1 = shift;
256            
257 4145 100 33     5436 if (is_na($element1)) {
    50 33        
    100          
    50          
258 1         165 croak "Error in bool context (a) { : missing value where TRUE/FALSE needed"
259             }
260             elsif (is_character($element1) || is_complex($element1)) {
261 0         0 croak 'Error in -a : invalid argument to unary operator ';
262             }
263             elsif (is_double($element1)) {
264              
265 6 100       89 if (defined $element1->value) {
266 5         90 return $element1->value;
267             }
268             else {
269 1 50       8 if (is_infinite($element1)) {
270 0         0 1;
271             }
272             # NaN
273             else {
274 1         156 croak 'argument is not interpretable as logical'
275             }
276             }
277             }
278             elsif (is_integer($element1) || is_logical($element1)) {
279 4138         56715 return $element1->value;
280             }
281             else {
282 0         0 croak "Invalid type";
283             }
284             }
285              
286             sub add {
287 24     24 0 150 my ($element1, $element2) = @_;
288            
289 24 50 33     30 return NA if is_na($element1) || is_na($element2);
290            
291 24 100       36 if (is_character($element1)) {
    100          
    100          
    50          
    0          
292 1         121 croak "Error in a + b : non-numeric argument to binary operator";
293             }
294             elsif (is_complex($element1)) {
295 3         15 my $re = add($element1->{re}, $element2->{re});
296 3         21 my $im = add($element1->{im}, $element2->{im});
297            
298 3         61 return complex($re->value, $im->value);
299             }
300             elsif (is_double($element1)) {
301 18 50 33     23 return NaN if is_nan($element1) || is_nan($element2);
302 18 50       246 if (defined $element1->value) {
    0          
    0          
303 18 50       93 if (defined $element2) {
    0          
    0          
304 18         211 return double($element1->value + $element2->value);
305             }
306             elsif (is_positive_infinite($element2)) {
307 0         0 return Inf;
308             }
309             elsif (is_negative_infinite($element2)) {
310 0         0 return negativeInf;
311             }
312             }
313             elsif (is_positive_infinite($element1)) {
314 0 0       0 if (defined $element2) {
    0          
    0          
315 0         0 return Inf;
316             }
317             elsif (is_positive_infinite($element2)) {
318 0         0 return Inf;
319             }
320             elsif (is_negative_infinite($element2)) {
321 0         0 return NaN;
322             }
323             }
324             elsif (is_negative_infinite($element1)) {
325 0 0       0 if (defined $element2) {
    0          
    0          
326 0         0 return negativeInf;
327             }
328             elsif (is_positive_infinite($element2)) {
329 0         0 return NaN;
330             }
331             elsif (is_negative_infinite($element2)) {
332 0         0 return negativeInf;
333             }
334             }
335             }
336             elsif (is_integer($element1)) {
337 2         27 return integer($element1->value + $element2->value);
338             }
339             elsif (is_logical($element1)) {
340 0         0 return integer($element1->value + $element2->value);
341             }
342             else {
343 0         0 croak "Invalid type";
344             }
345             }
346              
347             sub subtract {
348 18     18 0 128 my ($element1, $element2) = @_;
349            
350 18 50 33     28 return NA if is_na($element1) || is_na($element2);
351            
352 18 100       26 if (is_character($element1)) {
    100          
    50          
    0          
    0          
353 1         71 croak "Error in a + b : non-numeric argument to binary operator";
354             }
355             elsif (is_complex($element1)) {
356 1         5 my $re = subtract($element1->{re}, $element2->{re});
357 1         8 my $im = subtract($element1->{im}, $element2->{im});
358            
359 1         7 return complex_double($re, $im);
360             }
361             elsif (is_double($element1)) {
362 16 50 33     27 return NaN if is_nan($element1) || is_nan($element2);
363 16 50       232 if (defined $element1->value) {
    0          
    0          
364 16 50       93 if (defined $element2) {
    0          
    0          
365 16         195 return double($element1->value - $element2->value);
366             }
367             elsif (is_positive_infinite($element2)) {
368 0         0 return negativeInf;
369             }
370             elsif (is_negative_infinite($element2)) {
371 0         0 return Inf;
372             }
373             }
374             elsif (is_positive_infinite($element1)) {
375 0 0       0 if (defined $element2) {
    0          
    0          
376 0         0 return Inf;
377             }
378             elsif (is_positive_infinite($element2)) {
379 0         0 return NaN;
380             }
381             elsif (is_negative_infinite($element2)) {
382 0         0 return Inf;
383             }
384             }
385             elsif (is_negative_infinite($element1)) {
386 0 0       0 if (defined $element2) {
    0          
    0          
387 0         0 return negativeInf;
388             }
389             elsif (is_positive_infinite($element2)) {
390 0         0 return negativeInf;
391             }
392             elsif (is_negative_infinite($element2)) {
393 0         0 return NaN;
394             }
395             }
396             }
397             elsif (is_integer($element1)) {
398 0         0 return integer($element1->value + $element2->value);
399             }
400             elsif (is_logical($element1)) {
401 0         0 return integer($element1->value + $element2->value);
402             }
403             else {
404 0         0 croak "Invalid type";
405             }
406             }
407              
408             sub multiply {
409 9     9 0 66 my ($element1, $element2) = @_;
410            
411 9 50 33     15 return NA if is_na($element1) || is_na($element2);
412            
413 9 100       13 if (is_character($element1)) {
    100          
    50          
    0          
    0          
414 1         80 croak "Error in a + b : non-numeric argument to binary operator";
415             }
416             elsif (is_complex($element1)) {
417 2         32 my $re = double($element1->re->value * $element2->re->value - $element1->im->value * $element2->im->value);
418 2         35 my $im = double($element1->re->value * $element2->im->value + $element1->im->value * $element2->re->value);
419            
420 2         12 return complex_double($re, $im);
421             }
422             elsif (is_double($element1)) {
423 6 50 33     8 return NaN if is_nan($element1) || is_nan($element2);
424 6 50       80 if (defined $element1->value) {
    0          
    0          
425 6 50       28 if (defined $element2) {
    0          
    0          
426 6         71 return double($element1->value * $element2->value);
427             }
428             elsif (is_positive_infinite($element2)) {
429 0 0       0 if ($element1->value == 0) {
    0          
    0          
430 0         0 return NaN;
431             }
432             elsif ($element1->value > 0) {
433 0         0 return Inf;
434             }
435             elsif ($element1->value < 0) {
436 0         0 return negativeInf;
437             }
438             }
439             elsif (is_negative_infinite($element2)) {
440 0 0       0 if ($element1->value == 0) {
    0          
    0          
441 0         0 return NaN;
442             }
443             elsif ($element1->value > 0) {
444 0         0 return negativeInf;
445             }
446             elsif ($element1->value < 0) {
447 0         0 return Inf;
448             }
449             }
450             }
451             elsif (is_positive_infinite($element1)) {
452 0 0       0 if (defined $element2) {
    0          
    0          
453 0 0       0 if ($element2->value == 0) {
    0          
    0          
454 0         0 return NaN;
455             }
456             elsif ($element2->value > 0) {
457 0         0 return Inf;
458             }
459             elsif ($element2->value < 0) {
460 0         0 return negativeInf;
461             }
462             }
463             elsif (is_positive_infinite($element2)) {
464 0         0 return Inf;
465             }
466             elsif (is_negative_infinite($element2)) {
467 0         0 return negativeInf;
468             }
469             }
470             elsif (is_negative_infinite($element1)) {
471 0 0       0 if (defined $element2) {
    0          
    0          
472 0 0       0 if ($element2->value == 0) {
    0          
    0          
473 0         0 return NaN;
474             }
475             elsif ($element2->value > 0) {
476 0         0 return negativeInf;
477             }
478             elsif ($element2->value < 0) {
479 0         0 return Inf;
480             }
481             }
482             elsif (is_positive_infinite($element2)) {
483 0         0 return negativeInf;
484             }
485             elsif (is_negative_infinite($element2)) {
486 0         0 return Inf;
487             }
488             }
489             }
490             elsif (is_integer($element1)) {
491 0         0 return integer($element1->value * $element2->value);
492             }
493             elsif (is_logical($element1)) {
494 0         0 return integer($element1->value * $element2->value);
495             }
496             else {
497 0         0 croak "Invalid type";
498             }
499             }
500              
501             sub divide {
502 13     13 0 96 my ($element1, $element2) = @_;
503            
504 13 50 33     24 return NA if is_na($element1) || is_na($element2);
505            
506 13 100       26 if (is_character($element1)) {
    100          
    50          
    0          
    0          
507 1         71 croak "Error in a + b : non-numeric argument to binary operator";
508             }
509             elsif (is_complex($element1)) {
510 1         3 my $v3 = multiply($element1, conj($element2));
511 1         20 my $abs2 = double(value($element2->re) ** 2 + value($element2->im) ** 2);
512 1         18 my $re = divide($v3->re, $abs2);
513 1         18 my $im = divide($v3->im, $abs2);
514            
515 1         8 return complex_double($re, $im);
516             }
517             elsif (is_double($element1)) {
518 11 50 33     16 return NaN if is_nan($element1) || is_nan($element2);
519 11 50       149 if (defined $element1->value) {
    0          
    0          
520 11 50       183 if ($element1->value == 0) {
    100          
    50          
521 0 0       0 if (defined $element2) {
    0          
522 0 0       0 if ($element2->value == 0) {
523 0         0 return NaN;
524             }
525             else {
526 0         0 return double(0)
527             }
528             }
529             elsif (is_infinite($element2)) {
530 0         0 return double(0);
531             }
532             }
533             elsif ($element1->value > 0) {
534 10 50       188 if (defined $element2) {
    0          
535 10 50       119 if ($element2->value == 0) {
536 0         0 return Inf;
537             }
538             else {
539 10         152 return double($element1->value / $element2->value);
540             }
541             }
542             elsif (is_infinite($element2)) {
543 0         0 return double(0);
544             }
545             }
546             elsif ($element1->value < 0) {
547 1 50       45 if (defined $element2) {
    0          
548 1 50       16 if ($element2->value == 0) {
549 0         0 return negativeInf;
550             }
551             else {
552 1         19 return double($element1->value / $element2->value);
553             }
554             }
555             elsif (is_infinite($element2)) {
556 0         0 return double(0);
557             }
558             }
559             }
560             elsif (is_positive_infinite($element1)) {
561 0 0       0 if (defined $element2) {
    0          
562 0 0       0 if ($element2->value >= 0) {
    0          
563 0         0 return Inf;
564             }
565             elsif ($element2->value < 0) {
566 0         0 return negativeInf;
567             }
568             }
569             elsif (is_infinite($element2)) {
570 0         0 return NaN;
571             }
572             }
573             elsif (is_negative_infinite($element1)) {
574 0 0       0 if (defined $element2) {
    0          
575 0 0       0 if ($element2->value >= 0) {
    0          
576 0         0 return negativeInf;
577             }
578             elsif ($element2->value < 0) {
579 0         0 return Inf;
580             }
581             }
582             elsif (is_infinite($element2)) {
583 0         0 return NaN;
584             }
585             }
586             }
587             elsif (is_integer($element1)) {
588 0 0       0 if ($element1->value == 0) {
    0          
    0          
589 0 0       0 if ($element2->value == 0) {
590 0         0 return NaN;
591             }
592             else {
593 0         0 return double(0);
594             }
595             }
596             elsif ($element1->value > 0) {
597 0 0       0 if ($element2->value == 0) {
598 0         0 return Inf;
599             }
600             else {
601 0         0 return double($element1->value / $element2->value);
602             }
603             }
604             elsif ($element1->value < 0) {
605 0 0       0 if ($element2->value == 0) {
606 0         0 return negativeInf;
607             }
608             else {
609 0         0 return double($element1->value / $element2->value);
610             }
611             }
612             }
613             elsif (is_logical($element1)) {
614 0 0       0 if ($element1->value == 0) {
    0          
615 0 0       0 if ($element2->value == 0) {
    0          
616 0         0 return NaN;
617             }
618             elsif ($element2->value == 1) {
619 0         0 return double(0);
620             }
621             }
622             elsif ($element1->value == 1) {
623 0 0       0 if ($element2->value == 0) {
    0          
624 0         0 return Inf;
625             }
626             elsif ($element2->value == 1) {
627 0         0 return double(1);
628             }
629             }
630             }
631             else {
632 0         0 croak "Invalid type";
633             }
634             }
635              
636             sub raise {
637 13     13 0 106 my ($element1, $element2) = @_;
638            
639 13 50 33     24 return NA if is_na($element1) || is_na($element2);
640            
641 13 100       23 if (is_character($element1)) {
    100          
    50          
    0          
    0          
642 1         74 croak "Error in a + b : non-numeric argument to binary operator";
643             }
644             elsif (is_complex($element1)) {
645 1         21 my $element1_c = Math::Complex->make(Rstats::Util::value($element1->re), Rstats::Util::value($element1->im));
646 1         214 my $element2_c = Math::Complex->make(Rstats::Util::value($element2->re), Rstats::Util::value($element2->im));
647            
648 1         43 my $v3_c = $element1_c ** $element2_c;
649 1         390 my $re = Math::Complex::Re($v3_c);
650 1         12 my $im = Math::Complex::Im($v3_c);
651            
652 1         12 return complex($re, $im);
653             }
654             elsif (is_double($element1)) {
655 11 50 33     16 return NaN if is_nan($element1) || is_nan($element2);
656 11 50       152 if (defined $element1->value) {
    0          
    0          
657 11 50       188 if ($element1->value == 0) {
    100          
    50          
658 0 0       0 if (defined $element2) {
    0          
    0          
659 0 0       0 if ($element2->value == 0) {
    0          
    0          
660 0         0 return double(1);
661             }
662             elsif ($element2->value > 0) {
663 0         0 return double(0);
664             }
665             elsif ($element2->value < 0) {
666 0         0 return Inf;
667             }
668             }
669             elsif (is_positive_infinite($element2)) {
670 0         0 return double(0);
671             }
672             elsif (is_negative_infinite($element2)) {
673 0         0 return Inf
674             }
675             }
676             elsif ($element1->value > 0) {
677 8 50       151 if (defined $element2) {
    0          
    0          
678 8 50       94 if ($element2->value == 0) {
679 0         0 return double(1);
680             }
681             else {
682 8         124 return double($element1->value ** $element2->value);
683             }
684             }
685             elsif (is_positive_infinite($element2)) {
686 0 0       0 if ($element1->value < 1) {
    0          
    0          
687 0         0 return double(0);
688             }
689             elsif ($element1->value == 1) {
690 0         0 return double(1);
691             }
692             elsif ($element1->value > 1) {
693 0         0 return Inf;
694             }
695             }
696             elsif (is_negative_infinite($element2)) {
697 0 0       0 if ($element1->value < 1) {
    0          
    0          
698 0         0 return double(0);
699             }
700             elsif ($element1->value == 1) {
701 0         0 return double(1);
702             }
703             elsif ($element1->value > 1) {
704 0         0 return double(0);
705             }
706             }
707             }
708             elsif ($element1->value < 0) {
709 3 50       120 if (defined $element2) {
    0          
    0          
710 3 50       37 if ($element2->value == 0) {
711 0         0 return double(-1);
712             }
713             else {
714 3         65 return double($element1->value ** $element2->value);
715             }
716             }
717             elsif (is_positive_infinite($element2)) {
718 0 0       0 if ($element1->value > -1) {
    0          
    0          
719 0         0 return double(0);
720             }
721             elsif ($element1->value == -1) {
722 0         0 return double(-1);
723             }
724             elsif ($element1->value < -1) {
725 0         0 return negativeInf;
726             }
727             }
728             elsif (is_negative_infinite($element2)) {
729 0 0       0 if ($element1->value > -1) {
    0          
    0          
730 0         0 return Inf;
731             }
732             elsif ($element1->value == -1) {
733 0         0 return double(-1);
734             }
735             elsif ($element1->value < -1) {
736 0         0 return double(0);
737             }
738             }
739             }
740             }
741             elsif (is_positive_infinite($element1)) {
742 0 0       0 if (defined $element2) {
    0          
    0          
743 0 0       0 if ($element2->value == 0) {
    0          
    0          
744 0         0 return double(1);
745             }
746             elsif ($element2->value > 0) {
747 0         0 return Inf;
748             }
749             elsif ($element2->value < 0) {
750 0         0 return double(0);
751             }
752             }
753             elsif (is_positive_infinite($element2)) {
754 0         0 return Inf;
755             }
756             elsif (is_negative_infinite($element2)) {
757 0         0 return double(0);
758             }
759             }
760             elsif (is_negative_infinite($element1)) {
761 0 0       0 if (defined $element2) {
    0          
    0          
762 0 0       0 if ($element2->value == 0) {
    0          
    0          
763 0         0 return double(-1);
764             }
765             elsif ($element2->value > 0) {
766 0         0 return negativeInf;
767             }
768             elsif ($element2->value < 0) {
769 0         0 return double(0);
770             }
771             }
772             elsif (is_positive_infinite($element2)) {
773 0         0 return negativeInf;
774             }
775             elsif (is_negative_infinite($element2)) {
776 0         0 return double(0);
777             }
778             }
779             }
780             elsif (is_integer($element1)) {
781 0 0       0 if ($element1->value == 0) {
    0          
    0          
782 0 0       0 if ($element2->value == 0) {
    0          
    0          
783 0         0 return double(1);
784             }
785             elsif ($element2->value > 0) {
786 0         0 return double(0);
787             }
788             elsif ($element2->value < 0) {
789 0         0 return Inf;
790             }
791             }
792             elsif ($element1->value > 0) {
793 0 0       0 if ($element2->value == 0) {
794 0         0 return double(1);
795             }
796             else {
797 0         0 return double($element1->value ** $element2->value);
798             }
799             }
800             elsif ($element1->value < 0) {
801 0 0       0 if ($element2->value == 0) {
802 0         0 return double(-1);
803             }
804             else {
805 0         0 return double($element1->value ** $element2->value);
806             }
807             }
808             }
809             elsif (is_logical($element1)) {
810 0 0       0 if ($element1->value == 0) {
    0          
811 0 0       0 if ($element2->value == 0) {
    0          
812 0         0 return double(1);
813             }
814             elsif ($element2->value == 1) {
815 0         0 return double(0);
816             }
817             }
818             elsif ($element1->value == 1) {
819 0 0       0 if ($element2->value == 0) {
    0          
820 0         0 return double(1);
821             }
822             elsif ($element2->value == 1) {
823 0         0 return double(1);
824             }
825             }
826             }
827             else {
828 0         0 croak "Invalid type";
829             }
830             }
831              
832             sub remainder {
833 7     7 0 59 my ($element1, $element2) = @_;
834            
835 7 50 33     10 return NA if is_na($element1) || is_na($element2);
836            
837 7 100       11 if (is_character($element1)) {
    50          
    50          
    0          
    0          
838 1         71 croak "Error in a + b : non-numeric argument to binary operator";
839             }
840             elsif (is_complex($element1)) {
841 0         0 croak "unimplemented complex operation";
842             }
843             elsif (is_double($element1)) {
844 6 50 33     9 return NaN if is_nan($element1) || is_nan($element2) || is_infinite($element1) || is_infinite($element2);
      33        
      33        
845            
846 6 50       83 if ($element2->value == 0) {
847 0         0 return NaN;
848             }
849             else {
850 6         96 my $v3_value = $element1->value - POSIX::floor($element1->value/$element2->value) * $element2->value;
851 6         90 return double($v3_value);
852             }
853             }
854             elsif (is_integer($element1)) {
855 0 0       0 if ($element2->value == 0) {
856 0         0 return NaN;
857             }
858             else {
859 0         0 return double($element1 % $element2);
860             }
861             }
862             elsif (is_logical($element1)) {
863 0 0       0 if ($element2->value == 0) {
864 0         0 return NaN;
865             }
866             else {
867 0         0 return double($element1->value % $element2->value);
868             }
869             }
870             else {
871 0         0 croak "Invalid type";
872             }
873             }
874              
875             sub conj {
876 2     2 0 7 my $value = shift;
877            
878 2 50       3 if (is_complex($value)) {
879 2         37 return complex_double($value->re, Rstats::Util::negation($value->im));
880             }
881             else {
882 0         0 croak 'Invalid type';
883             }
884             }
885              
886             sub abs {
887 1     1 0 5 my $element = shift;
888            
889 1 50       3 if (is_complex($element)) {
890             return double(
891 1         3 sqrt(Rstats::Util::value($element)->{re} ** 2 + Rstats::Util::value($element)->{im} ** 2)
892             );
893             }
894             else {
895 0         0 croak 'Not implemented';
896             }
897             }
898              
899             sub more_than {
900 13     13 0 101 my ($element1, $element2) = @_;
901            
902 13 50 33     22 return NA if is_na($element1) || is_na($element2);
903            
904 13 50       27 if (is_character($element1)) {
    100          
    50          
    0          
    0          
905 0 0       0 return $element1->value gt $element2->value ? TRUE : FALSE;
906             }
907             elsif (is_complex($element1)) {
908 1         59 croak "invalid comparison with complex values";
909             }
910             elsif (is_double($element1)) {
911 12 50 33     31 return NA if is_nan($element1) || is_nan($element2);
912 12 50       168 if (defined $element1->value) {
    0          
    0          
913 12 50       63 if (defined $element2) {
    0          
    0          
914 12 100       142 return $element1->value > $element2->value ? TRUE : FALSE;
915             }
916             elsif (is_positive_infinite($element2)) {
917 0         0 return FALSE;
918             }
919             elsif (is_negative_infinite($element2)) {
920 0         0 return TRUE;
921             }
922             }
923             elsif (is_positive_infinite($element1)) {
924 0 0       0 if (defined $element2) {
    0          
    0          
925 0         0 return TRUE;
926             }
927             elsif (is_positive_infinite($element2)) {
928 0         0 return FALSE;
929             }
930             elsif (is_negative_infinite($element2)) {
931 0         0 return TRUE;
932             }
933             }
934             elsif (is_negative_infinite($element1)) {
935 0 0       0 if (defined $element2) {
    0          
    0          
936 0         0 return FALSE;
937             }
938             elsif (is_positive_infinite($element2)) {
939 0         0 return FALSE;
940             }
941             elsif (is_negative_infinite($element2)) {
942 0         0 return FALSE;
943             }
944             }
945             }
946             elsif (is_integer($element1)) {
947 0 0       0 return $element1->value > $element2->value ? TRUE : FALSE;
948             }
949             elsif (is_logical($element1)) {
950 0 0       0 return $element1->value > $element2->value ? TRUE : FALSE;
951             }
952             else {
953 0         0 croak "Invalid type";
954             }
955             }
956              
957             sub more_than_or_equal {
958 13     13 0 99 my ($element1, $element2) = @_;
959            
960 13 50 33     21 return NA if is_na($element1) || is_na($element2);
961            
962 13 50       23 if (is_character($element1)) {
    100          
    50          
    0          
    0          
963 0 0       0 return $element1->value ge $element2->value ? TRUE : FALSE;
964             }
965             elsif (is_complex($element1)) {
966 1         59 croak "invalid comparison with complex values";
967             }
968             elsif (is_double($element1)) {
969 12 50 33     23 return NA if is_nan($element1) || is_nan($element2);
970 12 50       168 if (defined $element1->value) {
    0          
    0          
971 12 50       61 if (defined $element2) {
    0          
    0          
972 12 100       151 return $element1->value >= $element2->value ? TRUE : FALSE;
973             }
974             elsif (is_positive_infinite($element2)) {
975 0         0 return FALSE;
976             }
977             elsif (is_negative_infinite($element2)) {
978 0         0 return TRUE;
979             }
980             }
981             elsif (is_positive_infinite($element1)) {
982 0 0       0 if (defined $element2) {
    0          
    0          
983 0         0 return TRUE;
984             }
985             elsif (is_positive_infinite($element2)) {
986 0         0 return TRUE;
987             }
988             elsif (is_negative_infinite($element2)) {
989 0         0 return TRUE;
990             }
991             }
992             elsif (is_negative_infinite($element1)) {
993 0 0       0 if (defined $element2) {
    0          
    0          
994 0         0 return FALSE;
995             }
996             elsif (is_positive_infinite($element2)) {
997 0         0 return FALSE;
998             }
999             elsif (is_negative_infinite($element2)) {
1000 0         0 return TRUE;
1001             }
1002             }
1003             }
1004             elsif (is_integer($element1)) {
1005 0 0       0 return $element1->value >= $element2->value ? TRUE : FALSE;
1006             }
1007             elsif (is_logical($element1)) {
1008 0 0       0 return $element1->value >= $element2->value ? TRUE : FALSE;
1009             }
1010             else {
1011 0         0 croak "Invalid type";
1012             }
1013             }
1014              
1015             sub less_than {
1016 13     13 0 105 my ($element1, $element2) = @_;
1017            
1018 13 50 33     24 return NA if is_na($element1) || is_na($element2);
1019            
1020 13 50       26 if (is_character($element1)) {
    100          
    50          
    0          
    0          
1021 0 0       0 return $element1->value lt $element2->value ? TRUE : FALSE;
1022             }
1023             elsif (is_complex($element1)) {
1024 1         154 croak "invalid comparison with complex values";
1025             }
1026             elsif (is_double($element1)) {
1027 12 50 33     14 return NA if is_nan($element1) || is_nan($element2);
1028 12 50       169 if (defined $element1->value) {
    0          
    0          
1029 12 50       67 if (defined $element2) {
    0          
    0          
1030 12 100       153 return $element1->value < $element2->value ? TRUE : FALSE;
1031             }
1032             elsif (is_positive_infinite($element2)) {
1033 0         0 return TRUE;
1034             }
1035             elsif (is_negative_infinite($element2)) {
1036 0         0 return FALSE;
1037             }
1038             }
1039             elsif (is_positive_infinite($element1)) {
1040 0 0       0 if (defined $element2) {
    0          
    0          
1041 0         0 return FALSE;
1042             }
1043             elsif (is_positive_infinite($element2)) {
1044 0         0 return TRUE;
1045             }
1046             elsif (is_negative_infinite($element2)) {
1047 0         0 return FALSE;
1048             }
1049             }
1050             elsif (is_negative_infinite($element1)) {
1051 0 0       0 if (defined $element2) {
    0          
    0          
1052 0         0 return TRUE;
1053             }
1054             elsif (is_positive_infinite($element2)) {
1055 0         0 return TRUE;
1056             }
1057             elsif (is_negative_infinite($element2)) {
1058 0         0 return FALSE;
1059             }
1060             }
1061             }
1062             elsif (is_integer($element1)) {
1063 0 0       0 return $element1->value < $element2->value ? TRUE : FALSE;
1064             }
1065             elsif (is_logical($element1)) {
1066 0 0       0 return $element1->value < $element2->value ? TRUE : FALSE;
1067             }
1068             else {
1069 0         0 croak "Invalid type";
1070             }
1071             }
1072              
1073             sub less_than_or_equal {
1074 13     13 0 102 my ($element1, $element2) = @_;
1075            
1076 13 50 33     19 return NA if is_na($element1) || is_na($element2);
1077            
1078 13 50       23 if (is_character($element1)) {
    100          
    50          
    0          
    0          
1079 0 0       0 return $element1->value le $element2->value ? TRUE : FALSE;
1080             }
1081             elsif (is_complex($element1)) {
1082 1         73 croak "invalid comparison with complex values";
1083             }
1084             elsif (is_double($element1)) {
1085 12 50 33     16 return NA if is_nan($element1) || is_nan($element2);
1086 12 50       196 if (defined $element1->value) {
    0          
    0          
1087 12 50       61 if (defined $element2) {
    0          
    0          
1088 12 100       142 return $element1->value <= $element2->value ? TRUE : FALSE;
1089             }
1090             elsif (is_positive_infinite($element2)) {
1091 0         0 return TRUE;
1092             }
1093             elsif (is_negative_infinite($element2)) {
1094 0         0 return FALSE;
1095             }
1096             }
1097             elsif (is_positive_infinite($element1)) {
1098 0 0       0 if (defined $element2) {
    0          
    0          
1099 0         0 return FALSE;
1100             }
1101             elsif (is_positive_infinite($element2)) {
1102 0         0 return TRUE;
1103             }
1104             elsif (is_negative_infinite($element2)) {
1105 0         0 return FALSE;
1106             }
1107             }
1108             elsif (is_negative_infinite($element1)) {
1109 0 0       0 if (defined $element2) {
    0          
    0          
1110 0         0 return TRUE;
1111             }
1112             elsif (is_positive_infinite($element2)) {
1113 0         0 return TRUE;
1114             }
1115             elsif (is_negative_infinite($element2)) {
1116 0         0 return TRUE;
1117             }
1118             }
1119             }
1120             elsif (is_integer($element1)) {
1121 0 0       0 return $element1->value <= $element2->value ? TRUE : FALSE;
1122             }
1123             elsif (is_logical($element1)) {
1124 0 0       0 return $element1->value <= $element2->value ? TRUE : FALSE;
1125             }
1126             else {
1127 0         0 croak "Invalid type";
1128             }
1129             }
1130              
1131             sub equal {
1132 10     10 0 73 my ($element1, $element2) = @_;
1133            
1134 10 50 33     20 return NA if is_na($element1) || is_na($element2);
1135            
1136 10 50       20 if (is_character($element1)) {
    100          
    50          
    0          
    0          
1137 0 0       0 return $element1->value eq $element2->value ? TRUE : FALSE;
1138             }
1139             elsif (is_complex($element1)) {
1140 2 100 66     39 return $element1->re->value == $element2->re->value && $element1->im->value == $element2->im->value ? TRUE : FALSE;
1141             }
1142             elsif (is_double($element1)) {
1143 8 50 33     28 return NA if is_nan($element1) || is_nan($element2);
1144 8 50       121 if (defined $element1->value) {
    0          
    0          
1145 8 50       44 if (defined $element2) {
    0          
    0          
1146 8 100       94 return $element1->value == $element2->value ? TRUE : FALSE;
1147             }
1148             elsif (is_positive_infinite($element2)) {
1149 0         0 return FALSE;
1150             }
1151             elsif (is_negative_infinite($element2)) {
1152 0         0 return FALSE;
1153             }
1154             }
1155             elsif (is_positive_infinite($element1)) {
1156 0 0       0 if (defined $element2) {
    0          
    0          
1157 0         0 return FALSE;
1158             }
1159             elsif (is_positive_infinite($element2)) {
1160 0         0 return TRUE;
1161             }
1162             elsif (is_negative_infinite($element2)) {
1163 0         0 return FALSE;
1164             }
1165             }
1166             elsif (is_negative_infinite($element1)) {
1167 0 0       0 if (defined $element2) {
    0          
    0          
1168 0         0 return FALSE;
1169             }
1170             elsif (is_positive_infinite($element2)) {
1171 0         0 return FALSE;
1172             }
1173             elsif (is_negative_infinite($element2)) {
1174 0         0 return TRUE;
1175             }
1176             }
1177             }
1178             elsif (is_integer($element1)) {
1179 0 0       0 return $element1->value == $element2->value ? TRUE : FALSE;
1180             }
1181             elsif (is_logical($element1)) {
1182 0 0       0 return $element1->value == $element2->value ? TRUE : FALSE;
1183             }
1184             else {
1185 0         0 croak "Invalid type";
1186             }
1187             }
1188              
1189             sub not_equal {
1190 10     10 0 78 my ($element1, $element2) = @_;
1191            
1192 10 50 33     18 return NA if is_na($element1) || is_na($element2);
1193            
1194 10 50       18 if (is_character($element1)) {
    100          
    50          
    0          
    0          
1195 0 0       0 return $element1->value ne $element2->value ? TRUE : FALSE;
1196             }
1197             elsif (is_complex($element1)) {
1198 2 100 66     53 return !($element1->re->value == $element2->re->value && $element1->im->value == $element2->im->value) ? TRUE : FALSE;
1199             }
1200             elsif (is_double($element1)) {
1201 8 50 33     11 return NA if is_nan($element1) || is_nan($element2);
1202 8 50       125 if (defined $element1->value) {
    0          
    0          
1203 8 50       55 if (defined $element2) {
    0          
    0          
1204 8 100       103 return $element1->value != $element2->value ? TRUE : FALSE;
1205             }
1206             elsif (is_positive_infinite($element2)) {
1207 0           return TRUE;
1208             }
1209             elsif (is_negative_infinite($element2)) {
1210 0           return TRUE;
1211             }
1212             }
1213             elsif (is_positive_infinite($element1)) {
1214 0 0         if (defined $element2) {
    0          
    0          
1215 0           return TRUE;
1216             }
1217             elsif (is_positive_infinite($element2)) {
1218 0           return FALSE;
1219             }
1220             elsif (is_negative_infinite($element2)) {
1221 0           return TRUE;
1222             }
1223             }
1224             elsif (is_negative_infinite($element1)) {
1225 0 0         if (defined $element2) {
    0          
    0          
1226 0           return TRUE;
1227             }
1228             elsif (is_positive_infinite($element2)) {
1229 0           return TRUE;
1230             }
1231             elsif (is_negative_infinite($element2)) {
1232 0           return FALSE;
1233             }
1234             }
1235             }
1236             elsif (is_integer($element1)) {
1237 0 0         return $element1->value != $element2->value ? TRUE : FALSE;
1238             }
1239             elsif (is_logical($element1)) {
1240 0 0         return $element1->value != $element2->value ? TRUE : FALSE;
1241             }
1242             else {
1243 0           croak "Invalid type";
1244             }
1245             }
1246              
1247             1;