Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: tmp_highfive
Fetching contributors…

Cannot retrieve contributors at this time

file 123 lines (111 sloc) 3.525 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
my role Rational[::NuT, ::DeT] does Real {
    has NuT $.numerator;
    has DeT $.denominator;

    multi method WHICH(Rational: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(NuT \nu = 0, DeT \de = 1) {
        my $new := nqp::create(self);
        my $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)
          !! nqp::p6box_n(nqp::div_In(
                nqp::p6decont($!numerator),
                nqp::p6decont($!denominator)
             ));
    }

    method floor(Rational:D:) returns Int:D {
        $!denominator == 1
            ?? $!numerator
            !! $!numerator < 0
            ?? ($!numerator div $!denominator - 1) # XXX because div for negati
            !! $!numerator div $!denominator
    }

    method ceiling(Rational:D:) returns Int:D {
        $!denominator == 1
            ?? $!numerator
            !! $!numerator < 0
            ?? ($!numerator div $!denominator) # XXX should be +1, but div is buggy
            !! ($!numerator div $!denominator + 1)
    }

    method Int() { $!numerator div $!denominator }

    method Bridge() { self.Num }

    multi method Str(::?CLASS:D:) {
        my $s = $!numerator < 0 ?? '-' !! '';
        my $r = self.abs;
        my $i = $r.floor;
        $r -= $i;
        $s ~= $i;
        if $r {
            $s ~= '.';
            my $want = $!denominator < 100_000
                       ?? 6
                       !! $!denominator.Str.chars + 1;
            my $f = '';
            while $r and $f.chars < $want {
                $r *= 10;
                $i = $r.floor;
                $f ~= $i;
                $r -= $i;
            }
            $f++ if 2 * $r >= 1;
            $s ~= $f;
        }
        $s;
    }

    method base($base) {
        my $s = $!numerator < 0 ?? '-' !! '';
        my $r = self.abs;
        my $i = $r.floor;
        $r -= $i;
        $s ~= $i.base($base);
        if $r {
            my $want = $!denominator < $base**6 ?? 6 !! $!denominator.log($base).ceiling + 1;
            my @f;
            while $r and @f < $want {
                $r *= $base;
                $i = $r.floor;
                push @f, $i;
                $r -= $i;
            }
            if 2 * $r >= 1 {
                for @f-1 ... 0 -> $x {
                    last if ++@f[$x] < $base;
                    @f[$x] = 0;
                    $s ~= ($i+1).base($base) if $x == 0; # never happens?
                }
            }
            $s ~= '.';
            $s ~= (0..9,'A'..'Z')[@f].join;
        }
        $s;
    }

    method succ {
        self.new($!numerator + $!denominator, $!denominator);
    }

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

    method norm() { self }
}
Something went wrong with that request. Please try again.