<commit_before>my Int $UINT64_UPPER = nqp::pow_I(2, 64, Num, Int);

my role Rational is Real {
    has Int $.numerator;
    has Int $.denominator;

    multi method WHICH(Rat:D:) {
        nqp::box_s(
            nqp::concat_s(
                nqp::concat_s(nqp::unbox_s(self.^name), '|'),
                nqp::concat_s(
                    nqp::tostr_I($!numerator),
                    nqp::concat_s('/', nqp::tostr_I($!denominator))
                )
            ),
            ObjAt
        );
    }

    method new(Int \$nu = 0, Int \$de = 1) {
        my $new         := nqp::create(self);
        my Int $gcd     := $nu gcd $de;
        my $numerator   = $nu div $gcd;
        my $denominator = $de div $gcd;
        if $denominator < 0 {
            $numerator   = -$numerator;
            $denominator = -$denominator;
        }
        nqp::bindattr($new, self.WHAT, '$!numerator',     nqp::p6decont($numerator));
        nqp::bindattr($new, self.WHAT, '$!denominator',   nqp::p6decont($denominator));
        $new;
    }

    method nude() { $!numerator, $!denominator }
    method Num() {
        $!denominator == 0
          ?? ($!numerator < 0 ?? -$Inf !! $Inf)
          !!  $!numerator.Num / $!denominator.Num
    }
    method Int() { $!numerator div $!denominator }

    method Bridge() { self.Num }
    method Rat(Rat:D: Real $?) { self }
    multi method Str(Rat:D:) {
        self.Num.Str
    }
    multi method perl(Rat:D:) {
        $!numerator ~ '/' ~ $!denominator
    }
    method succ {
        Rat.new($!numerator + $!denominator, $!denominator);
    }

    method pred {
        Rat.new($!numerator - $!denominator, $!denominator);
    }
}

# XXX: should also be Cool
my class Rat    does Rational { }
my class FatRat does Rational { }

sub DIVIDE_NUMBERS(Int:D \$nu, Int:D \$de, $t1, $t2) {
    my Int $gcd        := $nu gcd $de;
    my Int $numerator   = $nu div $gcd;
    my Int $denominator = $de div $gcd;
    if $denominator < 0 {
        $numerator   = -$numerator;
        $denominator = -$denominator;
    }
    if nqp::istype($t1, FatRat) || nqp::istype($t1, FatRat) {
        my $r := nqp::create(FatRat);
        nqp::bindattr($r, FatRat, '$!numerator',   nqp::p6decont($numerator));
        nqp::bindattr($r, FatRat, '$!denominator', nqp::p6decont($denominator));
        $r;
    } elsif $denominator < $UINT64_UPPER {
        my $r := nqp::create(Rat);
        nqp::bindattr($r, Rat, '$!numerator',   nqp::p6decont($numerator));
        nqp::bindattr($r, Rat, '$!denominator', nqp::p6decont($denominator));
        $r;
    } else {
        nqp::p6box_n(nqp::div_n(
                nqp::tonum_I(nqp::p6decont $numerator),
                nqp::tonum_I(nqp::p6decont $denominator)
            )
        );
    }
}

multi prefix:<->(Rat \$a) {
    Rat.new(-$a.numerator, $a.denominator);
}<commit_msg>conversions between Rat and FatRat<commit_after>my Int $UINT64_UPPER = nqp::pow_I(2, 64, Num, Int);

my role Rational is Real {
    has Int $.numerator;
    has Int $.denominator;

    multi method WHICH(Rat:D:) {
        nqp::box_s(
            nqp::concat_s(
                nqp::concat_s(nqp::unbox_s(self.^name), '|'),
                nqp::concat_s(
                    nqp::tostr_I($!numerator),
                    nqp::concat_s('/', nqp::tostr_I($!denominator))
                )
            ),
            ObjAt
        );
    }

    method new(Int \$nu = 0, Int \$de = 1) {
        my $new         := nqp::create(self);
        my Int $gcd     := $nu gcd $de;
        my $numerator   = $nu div $gcd;
        my $denominator = $de div $gcd;
        if $denominator < 0 {
            $numerator   = -$numerator;
            $denominator = -$denominator;
        }
        nqp::bindattr($new, self.WHAT, '$!numerator',     nqp::p6decont($numerator));
        nqp::bindattr($new, self.WHAT, '$!denominator',   nqp::p6decont($denominator));
        $new;
    }

    method nude() { $!numerator, $!denominator }
    method Num() {
        $!denominator == 0
          ?? ($!numerator < 0 ?? -$Inf !! $Inf)
          !!  $!numerator.Num / $!denominator.Num
    }
    method Int() { $!numerator div $!denominator }

    method Bridge() { self.Num }
    multi method Str(Rat:D:) {
        self.Num.Str
    }
    multi method perl(Rat:D:) {
        $!numerator ~ '/' ~ $!denominator
    }
    method succ {
        Rat.new($!numerator + $!denominator, $!denominator);
    }

    method pred {
        Rat.new($!numerator - $!denominator, $!denominator);
    }
}

my class FatRat { ... }
# XXX: should also be Cool
my class Rat    does Rational { 
    method Rat   (Rat:D: Real $?) { self }
    method FatRat(Rat:D: Real $?) { FatRat.new($.numerator, $.denominator); }
}
my class FatRat does Rational {
    method FatRat(FatRat:D: Real $?) { self }
    method Rat   (FatRat:D: Real $?) {
        $.denominator < $UINT64_UPPER
            ?? Rat.new($.numerator, $.denominator)
            !! fail "Cannot convert from FatRat to Rat because denominator is too big";
    }
}

sub DIVIDE_NUMBERS(Int:D \$nu, Int:D \$de, $t1, $t2) {
    my Int $gcd        := $nu gcd $de;
    my Int $numerator   = $nu div $gcd;
    my Int $denominator = $de div $gcd;
    if $denominator < 0 {
        $numerator   = -$numerator;
        $denominator = -$denominator;
    }
    if nqp::istype($t1, FatRat) || nqp::istype($t1, FatRat) {
        my $r := nqp::create(FatRat);
        nqp::bindattr($r, FatRat, '$!numerator',   nqp::p6decont($numerator));
        nqp::bindattr($r, FatRat, '$!denominator', nqp::p6decont($denominator));
        $r;
    } elsif $denominator < $UINT64_UPPER {
        my $r := nqp::create(Rat);
        nqp::bindattr($r, Rat, '$!numerator',   nqp::p6decont($numerator));
        nqp::bindattr($r, Rat, '$!denominator', nqp::p6decont($denominator));
        $r;
    } else {
        # TODO: be smarter here if both integers are big
        nqp::p6box_n(nqp::div_n(
                nqp::tonum_I(nqp::p6decont $numerator),
                nqp::tonum_I(nqp::p6decont $denominator)
            )
        );
    }
}

multi prefix:<->(Rat \$a) {
    Rat.new(-$a.numerator, $a.denominator);
}
{'fraction_non_alphanumeric': 0.16884176182707994, 'fraction_numerical': 0.008809135399673736, 'mean_word_length': 2.093340060544904, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1149974', 'n_tokens_mistral': 2352, 'n_tokens_neox': 2247, 'n_words': 459}