 # aajaxx's solution

## to Rational Numbers in the TypeScript Track

Published at Jun 20 2019 · 0 comments
Instructions
Test suite
Solution

#### Note:

This exercise has changed since this solution was written.

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 `q`th 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.

## Setup

Go through the setup instructions for TypeScript to install the necessary dependencies:

https://exercism.io/tracks/typescript/installation

## Requirements

Install assignment dependencies:

``````\$ yarn install
``````

## Making the test suite pass

Execute the tests with:

``````\$ yarn test
``````

In the test suites all tests but the first have been skipped.

Once you get a test passing, you can enable the next one by changing `xit` to `it`.

## Submitting Incomplete Solutions

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

### rational-numbers.test.ts

``````import Rational from './rational-numbers'

it('Add two positive rational numbers', () => {
const expected = new Rational(7, 6)
})

xit('Add a positive rational number and a negative rational number', () => {
const expected = new Rational(-1, 6)
})

xit('Add two negative rational numbers', () => {
const expected = new Rational(-7, 6)
})

const expected = new Rational(0, 1)
})
})

describe('Subtraction', () => {
xit('Subtract two positive rational numbers', () => {
const expected = new Rational(-1, 6)
expect(new Rational(1, 2).sub(new Rational(2, 3))).toEqual(expected)
})

xit('Subtract a positive rational number and a negative rational number', () => {
const expected = new Rational(7, 6)
expect(new Rational(1, 2).sub(new Rational(-2, 3))).toEqual(expected)
})

xit('Subtract two negative rational numbers', () => {
const expected = new Rational(1, 6)
expect(new Rational(-1, 2).sub(new Rational(-2, 3))).toEqual(expected)
})

xit('Subtract a rational number from itself', () => {
const expected = new Rational(0, 1)
expect(new Rational(1, 2).sub(new Rational(1, 2))).toEqual(expected)
})
})

describe('Multiplication', () => {
xit('Multiply two positive rational numbers', () => {
const expected = new Rational(1, 3)
expect(new Rational(1, 2).mul(new Rational(2, 3))).toEqual(expected)
})

xit('Multiply a negative rational number by a positive rational number', () => {
const expected = new Rational(-1, 3)
expect(new Rational(-1, 2).mul(new Rational(2, 3))).toEqual(expected)
})

xit('Multiply two negative rational numbers', () => {
const expected = new Rational(1, 3)
expect(new Rational(-1, 2).mul(new Rational(-2, 3))).toEqual(expected)
})

xit('Multiply a rational number by its reciprocal', () => {
const expected = new Rational(1, 1)
expect(new Rational(1, 2).mul(new Rational(2, 1))).toEqual(expected)
})

xit('Multiply a rational number by 1', () => {
const expected = new Rational(1, 2)
expect(new Rational(1, 2).mul(new Rational(1, 1))).toEqual(expected)
})

xit('Multiply a rational number by 0', () => {
const expected = new Rational(0, 1)
expect(new Rational(1, 2).mul(new Rational(0, 1))).toEqual(expected)
})
})

describe('Division', () => {
xit('Divide two positive rational numbers', () => {
const expected = new Rational(3, 4)
expect(new Rational(1, 2).div(new Rational(2, 3))).toEqual(expected)
})

xit('Divide a positive rational number by a negative rational number', () => {
const expected = new Rational(-3, 4)
expect(new Rational(1, 2).div(new Rational(-2, 3))).toEqual(expected)
})

xit('Divide two negative rational numbers', () => {
const expected = new Rational(3, 4)
expect(new Rational(-1, 2).div(new Rational(-2, 3))).toEqual(expected)
})

xit('Divide a rational number by 1', () => {
const expected = new Rational(1, 2)
expect(new Rational(1, 2).div(new Rational(1, 1))).toEqual(expected)
})
})

describe('Absolute value', () => {
xit('Absolute value of a positive rational number', () => {
const expected = new Rational(1, 2)
expect(new Rational(1, 2).abs()).toEqual(expected)
})

xit('Absolute value of a negative rational number', () => {
const expected = new Rational(1, 2)
expect(new Rational(-1, 2).abs()).toEqual(expected)
})

xit('Absolute value of zero', () => {
const expected = new Rational(0, 1)
expect(new Rational(0, 1).abs()).toEqual(expected)
})
})

describe('Exponentiation of a rational number', () => {
xit('Raise a positive rational number to a positive integer power', () => {
const expected = new Rational(1, 8)
expect(new Rational(1, 2).exprational(3)).toEqual(expected)
})

xit('Raise a negative rational number to a positive integer power', () => {
const expected = new Rational(-1, 8)
expect(new Rational(-1, 2).exprational(3)).toEqual(expected)
})

xit('Raise zero to an integer power', () => {
const expected = new Rational(0, 1)
expect(new Rational(0, 1).exprational(5)).toEqual(expected)
})

xit('Raise one to an integer power', () => {
const expected = new Rational(1, 1)
expect(new Rational(1, 1).exprational(4)).toEqual(expected)
})

xit('Raise a positive rational number to the power of zero', () => {
const expected = new Rational(1, 1)
expect(new Rational(1, 2).exprational(0)).toEqual(expected)
})

xit('Raise a negative rational number to the power of zero', () => {
const expected = new Rational(1, 1)
expect(new Rational(-1, 2).exprational(0)).toEqual(expected)
})
})

describe('Exponentiation of a real number to a rational number', () => {
xit('Raise a real number to a positive rational number', () => {
const expected = 16.0
expect(new Rational(4, 3).expreal(8)).toEqual(expected)
})

xit('Raise a real number to a negative rational number', () => {
const expected = 1.0/3.0
expect(new Rational(-1, 2).expreal(9)).toBeCloseTo(expected, 15)
})

xit('Raise a real number to a zero rational number', () => {
const expected = 1.0
expect(new Rational(0, 1).expreal(2)).toEqual(expected)
})
})

describe('Reduction to lowest terms', () => {
xit('Reduce a positive rational number to lowest terms', () => {
const expected = new Rational(1, 2)
expect(new Rational(2, 4).reduce()).toEqual(expected)
})

xit('Reduce a negative rational number to lowest terms', () => {
const expected = new Rational(-2, 3)
expect(new Rational(-4, 6).reduce()).toEqual(expected)
})

xit('Reduce a rational number with a negative denominator to lowest terms', () => {
const expected = new Rational(-1, 3)
expect(new Rational(3, -9).reduce()).toEqual(expected)
})

xit('Reduce zero to lowest terms', () => {
const expected = new Rational(0, 1)
expect(new Rational(0, 6).reduce()).toEqual(expected)
})

xit('Reduce an integer to lowest terms', () => {
const expected = new Rational(-2, 1)
expect(new Rational(-14, 7).reduce()).toEqual(expected)
})

xit('Reduce one to lowest terms', () => {
const expected = new Rational(1, 1)
expect(new Rational(13, 13).reduce()).toEqual(expected)
})
})``````
``````class Rational {
a: number
b: number

constructor(a: number, b: number) {
if (b === 0) { throw 'denominator can\'t be 0' }
this.a = a
this.b = b
}

this.a = this.a * r.b + this.b * r.a
this.b = this.b * r.b
return this.reduce()
}

sub(r: Rational): Rational {
r.a = -r.a
}

mul(r: Rational): Rational {
this.a = this.a * r.a
this.b = this.b * r.b
return this.reduce()
}

div(r: Rational): Rational {
return this.mul(r.invert())
}

abs(): Rational {
if (this.a < 0) {
this.a = -this.a
}
if (this.b < 0) {
this.b = -this.b
}
return this.reduce()
}

exprational(n: number): Rational {
this.a **= n
this.b **= n
return this.reduce()
}

expreal(n: number): number {
// return (n ** (this.a / this.b))
return 10 ** (Math.log10(n ** this.a) / this.b)
}

reduce(): Rational {
const gcd = this.gcd(this.a, this.b)
this.a /= gcd
this.b /= gcd
if (this.a === 0) {
this.b = 1
}
return this.reSign()
}

private reSign() {
if (this.b < 0) {
this.b = -this.b
this.a = -this.a
}
return this
}

private invert() {
const temp = this.a
this.a = this.b
this.b = temp
return this
}

private gcd(a: number, b: number): number {
let temp

while (a % b !== 0) {
temp = b
b = a % b
a = temp
}

if (b < 0) {
b = 0 - b
}

return b
}
}

export default Rational``````