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
?
有没有我没找到的方法?
单独使用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;
我认为这仍然需要记录:(