Rational Numbers

A rational number is defined as the quotient of two integers a and b, called the numerator and denominator, respectively, where b != 0.

The absolute value |r| of the rational number r = a/b is equal to |a|/|b|.

The sum of two rational numbers r1 = a1/b1 and r2 = a2/b2 is r1 + r2 = a1/b1 + a2/b2 = (a1 * b2 + a2 * b1) / (b1 * b2).

The difference of two rational numbers r1 = a1/b1 and r2 = a2/b2 is r1 - r2 = a1/b1 - a2/b2 = (a1 * b2 - a2 * b1) / (b1 * b2).

The product (multiplication) of two rational numbers r1 = a1/b1 and r2 = a2/b2 is r1 * r2 = (a1 * a2) / (b1 * b2).

Dividing a rational number r1 = a1/b1 by another r2 = a2/b2 is r1 / r2 = (a1 * b2) / (a2 * b1) if a2 * b1 is not zero.

Exponentiation of a rational number r = a/b to a non-negative integer power n is r^n = (a^n)/(b^n).

Exponentiation of a rational number r = a/b to a negative integer power n is r^n = (b^m)/(a^m), where m = |n|.

Exponentiation of a rational number r = a/b to a real (floating-point) number x is the quotient (a^x)/(b^x), which is a real number.

Exponentiation of a real number x to a rational number r = a/b is x^(a/b) = root(x^a, b), where root(p, q) is the qth root of p.

Implement the following operations:

  • addition, subtraction, multiplication and division of two rational numbers,
  • absolute value, exponentiation of a given rational number to an integer power, exponentiation of a given rational number to a real (floating-point) power, exponentiation of a real number to a rational number.

Your implementation of rational numbers should always be reduced to lowest terms. For example, 4/4 should reduce to 1/1, 30/60 should reduce to 1/2, 12/8 should reduce to 3/2, etc. To reduce a rational number r = a/b, divide a and b by the greatest common divisor (gcd) of a and b. So, for example, gcd(12, 8) = 4, so r = 12/8 can be reduced to (12/4)/(8/4) = 3/2.

Assume that the programming language you are using does not have an implementation of rational numbers.

Source

Wikipedia https://en.wikipedia.org/wiki/Rational_number

Version compatibility

This exercise has been tested on Julia versions >=1.0.

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

Your solution


In [ ]:
# submit

Test suite


In [ ]:
using Test

# include("rational-numbers.jl")

@test RationalNumber <: Real
@test_throws ArgumentError RationalNumber(0, 0)

@testset "One- & Zero-elements" begin
    @test zero(RationalNumber{Int}) == RationalNumber(0, 1)
    @test one(RationalNumber{Int})  == RationalNumber(1, 1)
end

@testset "Arithmetic" begin
    @testset "Addition" begin
        @test RationalNumber( 1, 2) + RationalNumber( 2, 3) == RationalNumber( 7, 6)
        @test RationalNumber( 1, 2) + RationalNumber(-2, 3) == RationalNumber(-1, 6)
        @test RationalNumber(-1, 2) + RationalNumber(-2, 3) == RationalNumber(-7, 6)
        @test RationalNumber( 1, 2) + RationalNumber(-1, 2) == RationalNumber( 0, 1)
    end

    @testset "Subtraction" begin
        @test RationalNumber( 1, 2) - RationalNumber( 2, 3) == RationalNumber(-1, 6)
        @test RationalNumber( 1, 2) - RationalNumber(-2, 3) == RationalNumber( 7, 6)
        @test RationalNumber(-1, 2) - RationalNumber(-2, 3) == RationalNumber( 1, 6)
        @test RationalNumber( 1, 2) - RationalNumber( 1, 2) == RationalNumber( 0, 1)
    end

    @testset "Multiplication" begin
        @test RationalNumber( 1, 2) * RationalNumber( 2, 3) == RationalNumber( 1, 3)
        @test RationalNumber(-1, 2) * RationalNumber( 2, 3) == RationalNumber(-1, 3)
        @test RationalNumber(-1, 2) * RationalNumber(-2, 3) == RationalNumber( 1, 3)
        @test RationalNumber( 1, 2) * RationalNumber( 2, 1) == RationalNumber( 1, 1)
        @test RationalNumber( 1, 2) * RationalNumber( 1, 1) == RationalNumber( 1, 2)
        @test RationalNumber( 1, 2) * RationalNumber( 0, 1) == RationalNumber( 0, 1)
    end

    @testset "Exponentiation" begin
        @testset "Exponentiation of a rational number" begin
            @test RationalNumber( 1, 2)^3 == RationalNumber( 1, 8)
            @test RationalNumber(-1, 2)^3 == RationalNumber(-1, 8)
            @test RationalNumber( 0, 1)^5 == RationalNumber( 0, 1)
            @test RationalNumber( 1, 1)^4 == RationalNumber( 1, 1)
            @test RationalNumber( 1, 2)^0 == RationalNumber( 1, 1)
            @test RationalNumber(-1, 2)^0 == RationalNumber( 1, 1)
        end

        @testset "Exponentiation of a real number to a rational number" begin
            @test 8^RationalNumber( 4, 3) == 15.999999999999998
            @test 9^RationalNumber(-1, 2) == 0.3333333333333333
            @test 2^RationalNumber( 0, 1) == 1.0
        end
    end

    @testset "Division" begin
        @test RationalNumber( 1, 2) / RationalNumber( 2, 3) == RationalNumber( 3, 4)
        @test RationalNumber( 1, 2) / RationalNumber(-2, 3) == RationalNumber(-3, 4)
        @test RationalNumber(-1, 2) / RationalNumber(-2, 3) == RationalNumber( 3, 4)
        @test RationalNumber( 1, 2) / RationalNumber( 1, 1) == RationalNumber( 1, 2)
    end
end

@testset "Absolute value" begin
    @test abs(RationalNumber( 1,  2)) == RationalNumber(1, 2)
    @test abs(RationalNumber(-1,  2)) == RationalNumber(1, 2)
    @test abs(RationalNumber( 0,  1)) == RationalNumber(0, 1)
    @test abs(RationalNumber( 1, -2)) == RationalNumber(1, 2)
end

@testset "Reduction to lowest terms" begin
    r = RationalNumber(2, 4)
    @test numerator(r)   == 1
    @test denominator(r) == 2
    
    r = RationalNumber(-4, 6)
    @test numerator(r)   == -2
    @test denominator(r) ==  3
    
    r = RationalNumber(3, -9)
    @test numerator(r)   == -1
    @test denominator(r) ==  3
    
    r = RationalNumber(0, 6)
    @test numerator(r)   == 0
    @test denominator(r) == 1
    
    r = RationalNumber(-14, 7)
    @test numerator(r)   == -2
    @test denominator(r) ==  1
    
    r = RationalNumber(13, 13)
    @test numerator(r)   == 1
    @test denominator(r) == 1
    
    r = RationalNumber(1, -1)
    @test numerator(r)   == -1
    @test denominator(r) ==  1
end

# TODO add to problem spec
# The following testset is based on the tests for rational numbers in Julia Base (MIT license)
# https://github.com/JuliaLang/julia/blob/52bafeb981bac548afd2264edb518d8d86944dca/test/rational.jl
# https://github.com/JuliaLang/julia/blob/52bafeb981bac548afd2264edb518d8d86944dca/LICENSE.md
@testset "Ordering" begin
    for a in -5:5, b in -5:5, c in -5:5
        a == b == 0 && continue
        
        r = RationalNumber(a, b)

        @test (r == c) == (a / b == c)
        @test (r != c) == (a / b != c)
        @test (r <= c) == (a / b <= c)
        @test (r <  c) == (a / b <  c)
        @test (r >= c) == (a / b >= c)
        @test (r >  c) == (a / b >  c)

        for d in -5:5
            c == d == 0 && continue

            s = RationalNumber(c, d)

            @test (r == s) == (a / b == c / d)
            @test (r != s) == (a / b != c / d)
            @test (r <= s) == (a / b <= c / d)
            @test (r <  s) == (a / b <  c / d)
            @test (r >= s) == (a / b >= c / d)
            @test (r >  s) == (a / b >  c / d)
        end
    end
end

@testset "Showing RationalNumbers" begin
    @test sprint(show, RationalNumber(23, 42)) == "23//42"
    @test sprint(show, RationalNumber(-2500, 5000)) == "-1//2"
end

Prepare submission

To submit your exercise, you need to save your solution in a file called rational-numbers.jl before using the CLI. You can either create it manually or use the following functions, which will automatically write every notebook cell that starts with # submit to the file rational-numbers.jl.


In [ ]:
# using Pkg; Pkg.add("Exercism")
# using Exercism
# Exercism.create_submission("rational-numbers")