Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

perl6: why is array skipping calculated values inside declaration?

Tags:

raku

I am learning Perl6 from Perl5.

In order to make this compile, I'll post the whole program:

sub lgamma ( Num(Real) \n --> Num ){
  use NativeCall;
  sub lgamma (num64 --> num64) is native {}
  lgamma( n )
}

sub pvalue (@a, @b) {
  if @a.elems <= 1 {
    return 1.0;
  }
  if @b.elems <= 1 {
    return 1.0;
  }
  my Rat $mean1 = @a.sum / @a.elems;
  my Rat $mean2 = @b.sum / @b.elems;
  if $mean1 == $mean2 {
    return 1.0;
  }
  my Rat $variance1 = 0.0;
  my Rat $variance2 = 0.0;

  for @a -> $i {
    $variance1 += ($mean1 - $i)**2#";" unnecessary for last statement in block
  }
  for @b -> $i {
    $variance2 += ($mean2 - $i)**2
  }
  if ($variance1 == 0 && $variance2 == 0) {
    return 1.0;
  }
  $variance1 /= (@a.elems - 1);
  $variance2 /= (@b.elems - 1);

  my $WELCH_T_STATISTIC = ($mean1-$mean2)/sqrt($variance1/@a.elems+$variance2/@b.elems);
    my $DEGREES_OF_FREEDOM = (($variance1/@a.elems+$variance2/@b.elems)**2)
    /
    (
    ($variance1*$variance1)/(@a.elems*@a.elems*(@a.elems-1))+
    ($variance2*$variance2)/(@b.elems*@b.elems*(@b.elems-1))
    );
    my $A = $DEGREES_OF_FREEDOM/2;
    my $value = $DEGREES_OF_FREEDOM/($WELCH_T_STATISTIC*$WELCH_T_STATISTIC+$DEGREES_OF_FREEDOM);
  my Num $beta = lgamma($A)+0.57236494292470009-lgamma($A+0.5);
    my Rat $acu = 10**(-15);
    my ($ai,$cx,$indx,$ns,$pp,$psq,$qq,$rx,$temp,$term,$xx);
# Check the input arguments.
    return $value if $A <= 0.0;# || $q <= 0.0;
    return $value if $value < 0.0 || 1.0 < $value;
# Special cases
    return $value if $value == 0.0 || $value == 1.0;
    $psq = $A + 0.5;
    $cx = 1.0 - $value;
    if $A < $psq * $value {
        ($xx, $cx, $pp, $qq, $indx) = ($cx, $value, 0.5, $A, 1);
    } else {
        ($xx, $pp, $qq, $indx) = ($value, $A, 0.5, 0);
    }
    $term = 1.0;
    $ai = 1.0;
    $value = 1.0;
    $ns = $qq + $cx * $psq;
  $ns = $ns.Int;
#Soper reduction formula.
    $rx = $xx / $cx;
    $temp = $qq - $ai;
    $rx = $xx if $ns == 0;
    while (True) {
        $term = $term * $temp * $rx / ( $pp + $ai );
        $value = $value + $term;
        $temp = $term.abs;
        if $temp <= $acu && $temp <= $acu * $value {
        $value = $value * ($pp * $xx.log + ($qq - 1.0) * $cx.log - $beta).exp / $pp;
        $value = 1.0 - $value if $indx;
        last;
        }
        $ai++;
        $ns--;
        if 0 <= $ns {
            $temp = $qq - $ai;
            $rx = $xx if $ns == 0;
        } else {
            $temp = $psq;
            $psq = $psq + 1.0;
        }
    }
    return $value;
}

my @array2d = ([27.5,21.0,19.0,23.6,17.0,17.9,16.9,20.1,21.9,22.6,23.1,19.6,19.0,21.7,21.4],
 [27.1,22.0,20.8,23.4,23.4,23.5,25.8,22.0,24.8,20.2,21.9,22.1,22.9,20.5,24.4],#0.

 [17.2,20.9,22.6,18.1,21.7,21.4,23.5,24.2,14.7,21.8],
 [21.5,22.8,21.0,23.0,21.6,23.6,22.5,20.7,23.4,21.8,20.7,21.7,21.5,22.5,23.6,21.5,22.5,23.5,21.5,21.8],

 [19.8,20.4,19.6,17.8,18.5,18.9,18.3,18.9,19.5,22.0],
 [28.2,26.6,20.1,23.3,25.2,22.1,17.7,27.6,20.6,13.7,23.2,17.5,20.6,18.0,23.9,21.6,24.3,20.4,24.0,13.2],

 [30.02,29.99,30.11,29.97,30.01,29.99],
 [29.89,29.93,29.72,29.98,30.02,29.98],

 [3.0,4.0,1.0,2.1],
 [490.2,340.0,433.9],

 [<1.0/15.0>, <10.0/62.0>],
 [<1.0/10>, <2/50.0>],

 [0.010268,0.000167,0.000167],
 [0.159258,0.136278,0.122389],

 [9/23.0,21/45.0,0/38.0],
 [0/44.0,42/94.0,0/22.0]);

 say @array2d[11][0];

 my @CORRECT_ANSWERS = (0.021378001462867,
 0.148841696605327,
 0.0359722710297968,
 0.090773324285671,
 0.0107515611497845,
 0.00339907162713746,
 0.52726574965384,
 0.545266866977794);

my UInt $i = 0;
my Real $error = 0.0;
for @array2d -> @left, @right {
  my $pvalue = pvalue(@left, @right);
  $error += ($pvalue - @CORRECT_ANSWERS[$i]).abs;
  say "$i [" ~ @left.join(',') ~ '] [' ~ @right ~ "] = $pvalue";
  if $error > 10**-9 {
    say "\$p = $pvalue, but should be @CORRECT_ANSWERS[$i]";
    die;
  }
#  printf("Test sets %u p-value = %.14g\n",$i+1,$pvalue);
  $i++
}

printf("the cumulative error is %g\n", $error);

What makes this sub-array different is that it has the "/" for division. How can I make Perl6 for-loop evaluate this sub-array?

EDIT: I'm struggling with what constitutes a minimal working example. I'm posting the entire code so that it will compile.

like image 500
con Avatar asked Jan 15 '19 16:01

con


1 Answers

(It turned out that this answer completely missed what was ailing @con. But I'll not delete it because it gathers together some hopefully useful links regarding rational numerics.)

What's wrong?

why is array skipping calculated values inside declaration?

It isn't.

I am learning Perl6 ...

Numbers like 1.3 are decimals in math and in Perl 6. Some explanations:

  • Damian Conway spends 3 minutes demonstrating the difference between the Perl 6 and Perl 5 approaches to rationals.

  • My Medium comment on Baking rationals into a programming language.

  • The P6 doc's Numerics page. (Written by Zoffix. Thank you for the ton of excellent stuff you did for P6 Zoffix.)

  • My SO answer to the question "Does Perl 6 performance suffer by using rationals for decimal numbers".

... from Perl5

Something about this belongs in one of the Perl 5 to Perl 6 guide docs. Would you be willing to open a new doc issue?

[1.0/15.0, 10.0/62.0],#this isn't evaluated

[1.0/10, 2/50.0],#neither is this

They're all evaluated.

In math and in P6 a literal 1.0 is a decimal is a rational. foo / bar is also a rational.

(Well, it is if foo and bar are both integers or rationals and either the denominator of the result remains 64 bits or less or one of foo or bar is an arbitrary precision FatRat rational.)

However, Perl6 doesn't seem to like values like I have indicated here.

You haven't explained the situation in which you're seeing something that makes you think P6 doesn't like them.

A strong possibility is that, per Brad Gilbert++'s comment, you are seeing values like, say, <1/15> instead of 0.066667. The former is a P6 literal value that 100% accurately denotes 1/15. To 100% accurately denote that in decimal the display would have to be 0.06666666666666... with a ... or some such at the end to denote an infinitely repeating final 6. But <1/15> denotes the same number and is shorter and arguably simpler so dd and .perl use the <1/15> form instead.

How can I get Perl6 to evaluate expressions like this when I'm declaring the 2D array?

You don't have to do anything. It's evaluating them. :)

like image 161
raiph Avatar answered Oct 18 '22 20:10

raiph