Rational numbers in Raku

Hi @milou123 I was also a bit surprised that raku reverts to decimal representation - I can see that some contexts - such as teaching fractional arithmetic would benefit from having a "keep as rat" mode. Having said that, ultimately it makes sense that there is only one way to .raku something and that decimal is the default representation.

Of course, with raku, you can also just change the language a bit. In this case, I have invented a new '→' postfix operator...

multi postfix:<→> ( Rat:D $r ) { $r.nude.join("/") }
say (1/5+1/5)→;    # 2/5

I am not smart enough to work out if the built in 'raku' method can be overridden in a similar way, would be keen to see advice on how to do that concisely...


try this in Julia:

julia> 1 // 10 + 1 // 10
1//5

julia> typeof(1 // 10 + 1 // 10)
Rational{Int64}


julia> 1 // 2 + 1 // 3
5//6

julia> typeof(1 // 2 + 1 // 3)
Rational{Int64}

in the Rat.pm6 implemention, we can only call .raku method on Rat type to get the expected format:

multi method raku(Rat:D: --> Str:D) {
        if $!denominator == 1 {
            $!numerator ~ '.0'
        }
        else {
            my $d = $!denominator;
            unless $d == 0 {
                $d = $d div 5 while $d %% 5;
                $d = $d div 2 while $d %% 2;
            }
            if $d == 1 and (my $b := self.base(10,*)).Numeric === self {
                $b;
            }
            else {
                '<' ~ $!numerator ~ '/' ~ $!denominator ~ '>'
            }
        }
}

In Raku, 0.2 constructs a Rat, and thus produces the very same result as writing 1/5 (which will be constant folded) or <1/5> (the literal form). You only get floating point in the case of specifying an exponent (for example, 2e-1).

The .raku (formerly known as the .perl) method's job is to produce something that will roundtrip and produce the same value if EVAL'd. In the case of 1/5, that can be exactly represented as a decimal, so it will produce 0.2. It only resorts to the fractional representation when a decimal form would not round-trip.

You can always recover the numerator and denominator using the .numerator and .denominator methods to format as you wish. Additionally .nude method returns a list of the numerator and denominator, which one can join with a / if wanted:

say (1/6+1/6).nude.join("/");     # 1/3
say (1/10+1/10).nude.join("/");   # 1/5

Tags:

Raku