Raku 中的有理数

Rational numbers in Raku

我正在使用 Raku 进行一些计算,因为它有很好的数字类型。但是,我在使用 '.raku'

时遇到问题
say (1/6+1/6).raku
#<1/3>

我们得到这个。然而,

say (1/10+1/10).raku
#0.2

这是一个错误吗?我预计 <1/5>。会发生什么?

在 Raku 中,0.2 构造一个 Rat,因此产生的结果与编写 1/5(将常量折叠)或 <1/5>(字面形式)。只有在指定指数的情况下才能得到浮点数(例如 2e-1)。

.raku(以前称为 .perl)方法的工作是生成一些东西,如果 EVAL 会往返并产生相同的值。在 1/5 的情况下,它可以精确地表示为小数,因此它会产生 0.2。它仅在小数形式不能往返时才采用小数表示法。

您始终可以使用 .numerator.denominator 方法恢复分子和分母,并根据需要格式化。另外 .nude 方法 returns 分子和分母的列表,如果需要可以用 / 加入:

say (1/6+1/6).nude.join("/");     # 1/3
say (1/10+1/10).nude.join("/");   # 1/5

你好@milou123 我也有点惊讶 raku 恢复为十进制表示法 - 我可以看到某些上下文 - 例如教小数算术将受益于 "keep as rat" 模式。话虽如此,最终只有一种方法可以 .raku 某些东西并且十进制是默认表示是有道理的。

当然,有了raku,你也可以稍微改变一下语言。在这种情况下,我发明了一个新的“→”后缀运算符...

multi postfix:<→> ( Rat:D $r ) { $r.nude.join("/") }
say (1/5+1/5)→;    # 2/5

如果内置的 'raku' 方法可以用类似的方式重写,我还不够聪明,我很想知道如何简洁地做到这一点的建议...

在 Julia 中试试这个:

julia> 1 // 10 + 1 // 10
1//5

julia> typeof(1 // 10 + 1 // 10)
Rational{Int64}


julia> 1 // 2 + 1 // 3
5//6

julia> typeof(1 // 2 + 1 // 3)
Rational{Int64}

Rat.pm6实现中,我们只能调用Rat类型的.raku方法来得到预期的格式:

multi method raku(Rat:D: --> Str:D) {
        if $!denominator == 1 {
            $!numerator ~ '.0'
        }
        else {
            my $d = $!denominator;
            unless $d == 0 {
                $d = $d div 5 while $d %% 5;
                $d = $d div 2 while $d %% 2;
            }
            if $d == 1 and (my $b := self.base(10,*)).Numeric === self {
                $b;
            }
            else {
                '<' ~ $!numerator ~ '/' ~ $!denominator ~ '>'
            }
        }
}