<commit_before>class Rat {
    has $.numerator;
    has $.denominator;

    # XXX TODO: should be lexical sub, but can't do those subs in setting yet.
    sub gcd(Int $a is copy, Int $b is copy) {
        $a = -$a if ($a < 0);
        $b = -$b if ($b < 0);
        while $a > 0 && $b > 0 {
            ($a, $b) = ($b, $a) if ($b > $a);
            $a %= $b;
        }
        return $a + $b;
    }

    multi method new(Int $numerator is copy, Int $denominator is copy) {
        if $denominator < 0 {
            $numerator = -$numerator;
            $denominator = -$denominator;
        }
        my $gcd = gcd($numerator, $denominator);
        $numerator = $numerator div $gcd;
        $denominator = $denominator div $gcd;
        self.bless(*, :$numerator, :$denominator);
    }

    multi method perl() { "$!numerator/$!denominator"; }

    multi method Num() { $!numerator.Num / $!denominator.Num }

    multi method Str() { $.Num.Str; }

    multi method nude() { $.numerator, $.denominator; }

    # Most of the trig functions for Rat are in Any-num.pm, but
    # sec is a special case.
    our Num multi method sec($base = 'radians') {
        self.Num.sec($base);
    }

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

    multi method abs {
        self < 0 ?? -self !! self;
    }

    our Int multi method sign() {
        self.Num.sign
    }
}

multi sub infix:<+>(Rat $a, Rat $b) {
    ($a.numerator * $b.denominator + $b.numerator * $a.denominator)
        / ($a.denominator * $b.denominator);
}

multi sub infix:<+>(Rat $a, Int $b) {
    ($a.numerator + $b * $a.denominator) / $a.denominator;
}

multi sub infix:<+>(Int $a, Rat $b) {
    ($a * $b.denominator + $b.numerator) / $b.denominator;
}

multi sub infix:<->(Rat $a, Rat $b) {
    ($a.numerator * $b.denominator - $b.numerator * $a.denominator)
        / ($a.denominator * $b.denominator);
}

multi sub infix:<->(Rat $a, Int $b) {
    ($a.numerator - $b * $a.denominator) / $a.denominator;
}

multi sub infix:<->(Int $a, Rat $b) {
    ($a * $b.denominator - $b.numerator) / $b.denominator;
}

multi sub prefix:<->(Rat $a) {
    Rat.new(-$a.numerator, $a.denominator);
}<commit_msg>Use Rat::gcd to make infix:<+>(Rat, Rat) and infix:<->(Rat, Rat) yield Rats in more cases.<commit_after>class Rat {
    has $.numerator;
    has $.denominator;

    # XXX TODO: should be lexical sub, but can't do those subs in setting yet.
    sub gcd(Int $a is copy, Int $b is copy) {
        $a = -$a if ($a < 0);
        $b = -$b if ($b < 0);
        while $a > 0 && $b > 0 {
            ($a, $b) = ($b, $a) if ($b > $a);
            $a %= $b;
        }
        return $a + $b;
    }

    multi method new(Int $numerator is copy, Int $denominator is copy) {
        if $denominator < 0 {
            $numerator = -$numerator;
            $denominator = -$denominator;
        }
        my $gcd = gcd($numerator, $denominator);
        $numerator = $numerator div $gcd;
        $denominator = $denominator div $gcd;
        self.bless(*, :$numerator, :$denominator);
    }

    multi method perl() { "$!numerator/$!denominator"; }

    multi method Num() { $!numerator.Num / $!denominator.Num }

    multi method Str() { $.Num.Str; }

    multi method nude() { $.numerator, $.denominator; }

    # Most of the trig functions for Rat are in Any-num.pm, but
    # sec is a special case.
    our Num multi method sec($base = 'radians') {
        self.Num.sec($base);
    }

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

    multi method abs {
        self < 0 ?? -self !! self;
    }

    our Int multi method sign() {
        self.Num.sign
    }
}

multi sub infix:<+>(Rat $a, Rat $b) {
    my $gcd = Rat::gcd($a.denominator, $b.denominator);
    ($a.numerator * ($b.denominator div $gcd) + $b.numerator * ($a.denominator div $gcd))
        / (($a.denominator div $gcd) * $b.denominator);
}

multi sub infix:<+>(Rat $a, Int $b) {
    ($a.numerator + $b * $a.denominator) / $a.denominator;
}

multi sub infix:<+>(Int $a, Rat $b) {
    ($a * $b.denominator + $b.numerator) / $b.denominator;
}

multi sub infix:<->(Rat $a, Rat $b) {
    my $gcd = Rat::gcd($a.denominator, $b.denominator);
    ($a.numerator * ($b.denominator div $gcd) - $b.numerator * ($a.denominator div $gcd))
        / (($a.denominator div $gcd) * $b.denominator);
}

multi sub infix:<->(Rat $a, Int $b) {
    ($a.numerator - $b * $a.denominator) / $a.denominator;
}

multi sub infix:<->(Int $a, Rat $b) {
    ($a * $b.denominator - $b.numerator) / $b.denominator;
}

multi sub prefix:<->(Rat $a) {
    Rat.new(-$a.numerator, $a.denominator);
}
{'fraction_non_alphanumeric': 0.18157405494732493, 'fraction_numerical': 0.0024788266887006815, 'mean_word_length': 2.2894021739130435, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 25, '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': '6674687', 'n_tokens_mistral': 1902, 'n_tokens_neox': 1848, 'n_words': 481}