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

msc*_*cha 13 raku

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

\n

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

\n

例如,此脚本计算 \xcf\x80 的数字:

\n
#!/usr/bin/env raku\n\nunit sub MAIN(Int $decimals = 1_000);\n\nsub atan_repr(Int $n, Int :$decimals)\n{\n    my $x = $n;\n    my $n2 = $n\xc2\xb2;\n    my $sign = 1;\n    my $limit = 10**($decimals+2);\n    my $result = FatRat.new(1, $x);\n    for 3,5...* -> $i {\n        $x \xc3\x97= $n2;\n        $sign \xc3\x97= -1;\n        $result += FatRat.new($sign, $i \xc3\x97 $x);\n        last if $x \xe2\x89\xa5 $limit;\n    }\n\n    return $result;\n}\n\nmy $\xcf\x80 = 4 \xc3\x97 (4 \xc3\x97 atan_repr(5, :$decimals) - atan_repr(239, :$decimals));\nmy $\xcf\x80-str = ~$\xcf\x80;      # Make sure we don't do string conversion over and over\n\nprint '3. ';\nfor 0,5...^$decimals -> $d {\n    print "    # $d\\n   " if $d && $d %% 50;\n    print $\xcf\x80-str.substr(2+$d,5), ' ';\n}\nprint "    # $decimals" if $decimals && $decimals %% 50;\nsay '';\n
Run Code Online (Sandbox Code Playgroud)\n

它非常优雅,除了像FatRat.new(1, $x). 我更愿意能够使用 just1/$x并以某种方式声明FatRat应该自动使用 s 而不是Rats。也许类似于use bigratPerl 的use bigintuse bignum

\n

有没有一种方法可以做到这一点,我还没有找到?

\n

Eli*_*sen 15

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

您还可以将其设置为,这将在 a超出精度时FatRat自动升级到。您还可以指定(让它),(让它抛出异常)或(让它在降级时发出警告)。FatRatRatFailurefailExceptionCX::WarnNum

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

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

INIT $*RAT-OVERFLOW = FatRat;
Run Code Online (Sandbox Code Playgroud)

仅针对词法范围激活此功能:

my $*RAT-OVERFLOW = FatRat;
Run Code Online (Sandbox Code Playgroud)

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

  • FWIW我喜欢默认行为。正如[this](https://lemire.me/blog/2020/03/15/number-of-atoms-in-the-universe-versus-floating-point-values)所述:估计有大约宇宙中的``10**80````原子。然而,我们使用常见的双精度浮点类型可以表示的最大值大于``10**308```。这是一个难以想象的大数字。如果您的软件生成的数字太大而无法容纳双精度浮点值,则很可能您遇到了错误。 (3认同)
  • 谢谢,@伊丽莎白!只需将“$*RAT-OVERFLOW = FatRat;”添加到脚本顶部即可达到目的。(编辑:还没有看到你的编辑;`INIT $*RAT-OVERFLOW = FatRat;`可能更安全一些。) (2认同)
  • 将此答案回收到文档条目:https://github.com/Raku/doc/commit/0a7a2e5215 (2认同)
  • 也许 https://docs.raku.org/type/Rat 上还应该提到“$*RAT-OVERFLOW”?围绕这句话:“为了防止分子和分母变得异常大,分母被限制为 64 位存储。当分母溢出时,会返回 Num(浮点数)。” (2认同)
  • 请参阅 https://github.com/Raku/doc/commit/b95cdedbf8 。微软查++ (2认同)
  • 或者您正在计算 π 的数字;-) (2认同)