昨天,我们正在深入研究 Rakudo Raku,以了解Rat值成为Num值的时间。事实证明,如果该值变得太小,这意味着它的分母变得越来越大,Rakudo开始使用Num值而不是Rat。
我们找到了它发生的地方。今天,让我们进行一个练习,看看Raku的行为是否可能不同,即扩展数据类型而不是将其切换为浮点数并且失去准确性。
改变很简单。所有你需要的是更新DIVIDE_N例程中的ifs:
--- a/src/core/Rat.pm
+++ b/src/core/Rat.pm
@@ -48,16 +48,14 @@ sub DIVIDE_NUMBERS(Int:D \nu, Int:D \de, \t1, \t2) {
($numerator := -$numerator),
($denominator := -$denominator))),
nqp::if(
- nqp::istype(t1, FatRat) || nqp::istype(t2, FatRat),
+ nqp::istype(t1, FatRat) || nqp::istype(t2, FatRat) || $denominator >= UINT64_UPPER,
nqp::p6bindattrinvres(
nqp::p6bindattrinvres(nqp::create(FatRat),FatRat,'$!numerator',$numerator),
FatRat,'$!denominator',$denominator),
- nqp::if(
- $denominator < UINT64_UPPER,
nqp::p6bindattrinvres(
nqp::p6bindattrinvres(nqp::create(Rat),Rat,'$!numerator',$numerator),
- Rat,'$!denominator',$denominator),
- nqp::p6box_n(nqp::div_In($numerator, $denominator)))))
+ Rat,'$!denominator',$denominator)
+ ))
}
现在有两种结果:例程产生一个Rat值或一个FatRat。当子参数已经是FatRats或当前Rat太接近于零时,后者发生。
从昨天的帖子中用牛顿算法编译并测试我们修改过的raku可执行文件:
my $N = 25;
my @x =
Rat.new(1, 1),
-> $x {
$x - ($x ** 2 - $N) / (2 * $x)
} ... *;
.WHAT.say for @x[0..10];
.say for @x[1..10];
正如预期的那样,序列的第一个元素是大鼠,而尾部是由FatRats组成的:
(Rat)
(Rat)
(Rat)
(Rat)
(Rat)
(Rat)
(FatRat)
(FatRat)
(FatRat)
(FatRat)
(FatRat)
另外,如果您打印这些值,则可以轻松看到它:
13
7.461538
5.406027
5.01524760
5.0000231782539490
5.0000000000537228965718724535111
5.00000000000000000000028861496160410945540567902983713732806515
5.000000000000000000000000000000000000000000008329859606174157518822601061625174583303232554885171687075417887439374231515823
5.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000693865610585718905982734693675309615913812411108046914931948226816763601320201386971350204028084660605790650314446568089428143916887535905115787146371799888
5.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004814494855534925123195523522159753005055993378092336823010386671077751892080269126953923957066141452855241262256569975702944214065988292758274535222239622977104185030432093986146346015004230914044314506580063758070896734658461687838556535528402765772220596451598003813021305355635793333485373058987453787504731
* * *
我不知道什么是更好的 - 对于有理数(不包括理性角色)或者可以同时拥有’窄’和’宽’值的两种不同类型,或者一种切换到更宽数据的机制当没有足够的容量时键入。我觉得最好的是最后一种选择(当然FatRat和Rat使用不同的类型来存储分子和分母)。
据我所知,这正是最初的想法:
对于尚未执行数字作用的值,将返回Int,Rat,Num或Complex的最窄适合类型;然而,包含由/分隔的两个整数的字符串将作为Rat返回(如果分母溢出int64,则返回FatRat)。
同样感觉更自然的是默默地为更多数字增加更多空间,而不是打破鼠类型的想法。无论如何,对此有不同的看法,但这不应阻止Raku的普及。