Skip to content

Commit

Permalink
Make Num.Rat conversion again 1.5x as fast
Browse files Browse the repository at this point in the history
- reduce Scalar allocations as much as possible by binding
- use nqp::ops as much as possible to prevent unneeded coercions

Again, should affect performance of `now` similarly.
  • Loading branch information
lizmat committed Apr 14, 2020
1 parent 3aaca26 commit 2d1ba43
Showing 1 changed file with 34 additions and 24 deletions.
58 changes: 34 additions & 24 deletions src/core.c/Num.pm6
Expand Up @@ -43,7 +43,7 @@ my class Num does Real { # declared in BOOTSTRAP
!! nqp::concat($res,'e0')
}

method Rat(Num:D: Real $epsilon = 1.0e-6, :$fat) {
method Rat(Num:D: Real $Epsilon = 1.0e-6, :$fat) {
my \RAT = $fat ?? FatRat !! Rat;
my num $num = self;

Expand All @@ -53,7 +53,7 @@ my class Num does Real { # declared in BOOTSTRAP
) if nqp::isnanorinf($num);

$num = nqp::neg_n($num) if (my int $signum = nqp::islt_n($num,0e0));
my num $r = $num - nqp::floor_n($num);
my num $r = nqp::sub_n($num,nqp::floor_n($num));

# basically have an Int
if nqp::iseq_n($r,0e0) {
Expand All @@ -62,35 +62,45 @@ my class Num does Real { # declared in BOOTSTRAP

# find convergents of the continued fraction.
else {
my Int $a = 1;
my Int $b = nqp::fromnum_I($num, Int);
my Int $c = 0;
my Int $d = 1;
my Int $a := 1;
my Int $b := nqp::fromnum_I($num,Int);
my Int $c := 0;
my Int $d := 1;

my Int $q;
my num $modf_arg;
my $orig_b;
my $orig_d;

while nqp::isne_n($r,0e0) && abs($num - ($b / $d)) > $epsilon {
$modf_arg = 1e0 / $r;
$q = nqp::fromnum_I($modf_arg, Int);
$r = $modf_arg - nqp::floor_n($modf_arg);
# bind some value to prevent Scalar container creation
my Int $q := 0;
my Int $orig_b := 0;
my Int $orig_d := 0;

$orig_b = $b;
$b = $q * $b + $a;
$a = $orig_b;

$orig_d = $d;
$d = $q * $d + $c;
$c = $orig_d;
}
my num $modf_arg;
my num $epsilon = $Epsilon.Num;

nqp::while(
nqp::isne_n($r,0e0)
&& nqp::isgt_n(
nqp::abs_n(nqp::sub_n($num,nqp::div_In($b,$d))),
$epsilon
),
nqp::stmts(
($modf_arg = nqp::div_n(1e0,$r)),
($q := nqp::fromnum_I($modf_arg,Int)),
($r = nqp::sub_n($modf_arg,nqp::floor_n($modf_arg))),

($orig_b := $b),
($b := nqp::add_I(nqp::mul_I($q,$b,Int),$a,Int)),
($a := $orig_b),

($orig_d := $d),
($d := nqp::add_I(nqp::mul_I($q,$d,Int),$c,Int)),
($c := $orig_d)
)
);

# Note that this result has less error than any Rational with a
# smaller denominator but it is not (necessarily) the Rational
# with the smallest denominator that has less than $epsilon error.
# However, to find that Rational would take more processing.
RAT.new($signum ?? nqp::neg_I(nqp::decont($b),Int) !! $b, $d)
RAT.new($signum ?? nqp::neg_I($b,Int) !! $b, $d)
}
}
method FatRat(Num:D: Real $epsilon = 1.0e-6) {
Expand Down

0 comments on commit 2d1ba43

Please sign in to comment.