提问者:小点点

有没有办法在Raku中自动使用FatRats?


Raku的一个巧妙之处在于,它在适当的时候(例如,当除以两个整数时)自动使用有理数而不是浮点数。不幸的是,一旦分母变得太大,无论如何都会使用浮点数。

FatRat类型不这样做,但据我所知,使用它们的唯一方法是显式地这样做。

例如,此脚本计算π的数字:

#!/usr/bin/env raku

unit sub MAIN(Int $decimals = 1_000);

sub atan_repr(Int $n, Int :$decimals)
{
    my $x = $n;
    my $n2 = $n²;
    my $sign = 1;
    my $limit = 10**($decimals+2);
    my $result = FatRat.new(1, $x);
    for 3,5...* -> $i {
        $x ×= $n2;
        $sign ×= -1;
        $result += FatRat.new($sign, $i × $x);
        last if $x ≥ $limit;
    }

    return $result;
}

my $π = 4 × (4 × atan_repr(5, :$decimals) - atan_repr(239, :$decimals));
my $π-str = ~$π;      # Make sure we don't do string conversion over and over

print '3. ';
for 0,5...^$decimals -> $d {
    print "    # $d\n   " if $d && $d %% 50;
    print $π-str.substr(2+$d,5), ' ';
}
print "    # $decimals" if $decimals && $decimals %% 50;
say '';

它非常优雅,除了像FatRat.new(1,$x)这样的东西。我更愿意只使用1/$x,并以某种方式声明应该自动使用FatRat而不是Rat。也许像这样的东西使用bigrat,类似于Perl的使用bigint使用bignum

有没有我没找到的方法?


共1个答案

匿名用户

单独使用Rat本身很好,直到您的精度用完(这很少见)。我认为是2022.02版本引入了$*RAT-OVERFLOW动态变量。它指定了当Rat溢出其精度时应执行的行为。默认情况下,它设置为Num,这意味着它将恢复使用(有损)浮点数。

您还可以将其设置为FatRat,一旦Rat超出精度,就会自动升级到FatRat。您还可以指定Failure(让它失败)、Exception(让它抛出异常)或CX::Warn(让它在降级到Num时发出警告)。

这是如何工作的?$*RAT-OVERFLOW变量应该是一个类或实例,当Rat溢出时,将在其上调用UPGRADE-RAT方法。因此,您可以通过创建一个包含UPGRADE-RAT方法的类来引入自己的行为。

因此,要全局激活它以升级到FatRat,您需要执行以下操作:

INIT $*RAT-OVERFLOW = FatRat;

要仅为词法范围激活它:

my $*RAT-OVERFLOW = FatRat;

我认为这仍然需要记录:(