首页 > 解决方案 > perl6:为什么数组在声明中跳过计算值?

问题描述

我正在从 Perl5 学习 Perl6。

为了使这个编译,我将发布整个程序:

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);

这个子数组的不同之处在于它有“/”表示除法。如何让 Perl6 for 循环评估这个子数组?

编辑:我正在努力解决构成最小工作示例的内容。我发布了整个代码,以便它能够编译。

标签: raku

解决方案


(事实证明,这个答案完全忽略了@con 的问题。但我不会删除它,因为它收集了一些关于有理数的有用链接。)

怎么了?

为什么数组在声明中跳过计算值?

它不是。

我正在学习 Perl6 ...

像这样的数字1.3是数学和 Perl 6 中的小数。一些解释:

...来自 Perl5

Perl 5 to Perl 6 guide docs中有关这方面的内容。你愿意打开一个新的文档问题吗?

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

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

他们都被评估了。

在数学和 P6 中,文字1.0是小数是有理数。foo / bar也是理性的。

(好吧,如果foobar都是整数或有理数,并且结果的分母保持为 64 位或更少,或者其中之一是foobar是任意精度FatRat 有理数。)

然而,Perl6 似乎并不喜欢我在这里指出的值。

你还没有解释你看到的东西让你认为 P6 不喜欢它们的情况。

一个很大的可能性是,根据Brad Gilbert++ 的评论,您看到的值例如,<1/15>而不是0.066667. 前者是 100% 准确表示的 P6 字面值1/15。100% 准确地表示十进制显示必须在末尾0.06666666666666...带有 a...或 some 这样才能表示无限重复的 final 6。但是<1/15>表示相同的数字,并且更短并且可以说更简单,因此dd.perl改用该<1/15>形式。

当我声明二维数组时,如何让 Perl6 评估这样的表达式?

你不必做任何事情。它正在评估它们。:)


推荐阅读