Skip to content
Permalink
Browse files

Streamline final stage of Rat normalization

- use multi's to decide about Rat vs FatRat
- makes the Rat case about 3% faster
- makes the FatRat case about 2x as fast
  • Loading branch information...
lizmat committed Jan 2, 2019
1 parent daeb7f2 commit 395d633db18f764b1ec14ceca4237c596a45131a
Showing with 46 additions and 20 deletions.
  1. +46 −20 src/core/Rat.pm6
@@ -42,7 +42,11 @@ my class FatRat is Cool does Rational[Int, Int] {
}
}

sub DIVIDE_NUMBERS(Int:D $nu, Int:D $de, \t1, \t2) {
# NORMALIZE two integer values and create a Rat/FatRat/float from them.
# Provide two types: if either of them is a FatRat, then a FatRat will be
# returned. If a Rat is to be created, then a check for denominator overflow
# is done: if that is the case, then a float will be returned.
sub DIVIDE_NUMBERS(Int:D $nu, Int:D $de, \t1, \t2) is raw {
nqp::if(
$de,
nqp::stmts(
@@ -51,15 +55,15 @@ sub DIVIDE_NUMBERS(Int:D $nu, Int:D $de, \t1, \t2) {
(my \denominator := nqp::div_I($de,gcd,Int)),
nqp::if(
nqp::islt_I(denominator,0),
RAKUDO_INTERNAL_DIVIDE_NUMBERS_NO_NORMALIZE(
CREATE_RATIONAL_FROM_INTS(
nqp::neg_I(numerator,Int), nqp::neg_I(denominator,Int), t1, t2
),
RAKUDO_INTERNAL_DIVIDE_NUMBERS_NO_NORMALIZE(
CREATE_RATIONAL_FROM_INTS(
numerator, denominator, t1, t2
)
)
),
RAKUDO_INTERNAL_DIVIDE_NUMBERS_NO_NORMALIZE(
CREATE_RATIONAL_FROM_INTS(
nqp::box_i(nqp::isgt_I($nu,0) || nqp::neg_i(nqp::istrue($nu)),Int),
0, t1, t2
)
@@ -69,21 +73,43 @@ sub DIVIDE_NUMBERS(Int:D $nu, Int:D $de, \t1, \t2) {
# ALL RATIONALS MUST BE NORMALIZED, however in some operations we cannot
# ever get a non-normalized Rational, if we start with a normalized Rational.
# For such cases, we can use this routine, to bypass normalization step,
# which would be useless.
sub RAKUDO_INTERNAL_DIVIDE_NUMBERS_NO_NORMALIZE(\nu, \de, \t1, \t2) {
# which would be useless. Also used when normalization *was* needed.
proto sub CREATE_RATIONAL_FROM_INTS(|) {*}
multi sub CREATE_RATIONAL_FROM_INTS(Int:D \nu, Int:D \de, \t1, \t2) is raw {
nqp::if(
nqp::istype(t1, FatRat) || nqp::istype(t2, FatRat),
nqp::p6bindattrinvres(
nqp::p6bindattrinvres(nqp::create(FatRat),
FatRat,'$!numerator',nu),
FatRat,'$!denominator',de),
nqp::if(
nqp::islt_I(de, UINT64_UPPER),
nqp::p6bindattrinvres(
nqp::p6bindattrinvres(nqp::create(Rat),
Rat,'$!numerator',nu),
Rat,'$!denominator',de),
nqp::p6box_n(nqp::div_In(nu, de))))
nqp::islt_I(de,UINT64_UPPER), # do we need to downgrade to float?
nqp::p6bindattrinvres( # no, we need to keep a Rat
nqp::p6bindattrinvres(nqp::create(Rat),Rat,'$!numerator',nu),
Rat,'$!denominator',de
),
nqp::p6box_n(nqp::div_In(nu,de)) # downgrade to float
)
}

# already a FatRat, so keep that
multi sub CREATE_RATIONAL_FROM_INTS(
Int:D \nu, Int:D \de, FatRat \t1, \t2
) is raw {
nqp::p6bindattrinvres(
nqp::p6bindattrinvres(nqp::create(FatRat),FatRat,'$!numerator',nu),
FatRat,'$!denominator',de
)
}
multi sub CREATE_RATIONAL_FROM_INTS(
Int:D \nu, Int:D \de, \t1, FatRat \t2
) is raw {
nqp::p6bindattrinvres(
nqp::p6bindattrinvres(nqp::create(FatRat),FatRat,'$!numerator',nu),
FatRat,'$!denominator',de
)
}
multi sub CREATE_RATIONAL_FROM_INTS(
Int:D \nu, Int:D \de, FatRat \t1, FatRat \t2
) is raw {
nqp::p6bindattrinvres(
nqp::p6bindattrinvres(nqp::create(FatRat),FatRat,'$!numerator',nu),
FatRat,'$!denominator',de
)
}

multi sub prefix:<->(Rat:D \a --> Rat:D) {
@@ -230,7 +256,7 @@ multi sub infix:<**>(Rational:D \a, Int:D \b) {
nqp::if( # if we got Inf
nqp::istype(($de := nqp::pow_I(a.denominator, nqp::decont(b), Num, Int)), Num),
Failure.new(X::Numeric::Overflow.new),
RAKUDO_INTERNAL_DIVIDE_NUMBERS_NO_NORMALIZE $nu, $de, a, b)),
CREATE_RATIONAL_FROM_INTS $nu, $de, a, b)),
nqp::if( # if we got Inf
nqp::istype(($nu := nqp::pow_I(a.numerator,
nqp::neg_I(nqp::decont(b), Int), Num, Int)), Num),
@@ -239,7 +265,7 @@ multi sub infix:<**>(Rational:D \a, Int:D \b) {
nqp::istype(($de := nqp::pow_I(a.denominator,
nqp::neg_I(nqp::decont(b), Int), Num, Int)), Num),
Failure.new(X::Numeric::Underflow.new),
RAKUDO_INTERNAL_DIVIDE_NUMBERS_NO_NORMALIZE $de, $nu, a, b)))
CREATE_RATIONAL_FROM_INTS $de, $nu, a, b)))
}

multi sub infix:<==>(Rational:D \a, Rational:D \b --> Bool:D) {

0 comments on commit 395d633

Please sign in to comment.
You can’t perform that action at this time.