artemkorsakov's solution

to Rational Numbers in the C# Track

Published at Feb 22 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.

Running the tests

To run the tests, run the command `dotnet test` from within the exercise directory.

Initially, only the first test will be enabled. This is to encourage you to solve the exercise one step at a time. Once you get the first test passing, remove the `Skip` property from the next test and work on getting that test passing. Once none of the tests are skipped and they are all passing, you can submit your solution using `exercism submit RationalNumbers.cs`

Further information

For more detailed information about the C# track, including how to get help if you're having trouble, please visit the exercism.io C# language page.

Submitting Incomplete Solutions

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

RationalNumbersTest.cs

``````// This file was auto-generated based on version 1.0.0 of the canonical data.

using Xunit;

public class RationalNumbersTest
{
[Fact]
{
Assert.Equal(new RationalNumber(7, 6), new RationalNumber(1, 2) + (new RationalNumber(2, 3)));
}

[Fact(Skip = "Remove to run test")]
{
Assert.Equal(new RationalNumber(-1, 6), new RationalNumber(1, 2) + (new RationalNumber(-2, 3)));
}

[Fact(Skip = "Remove to run test")]
{
Assert.Equal(new RationalNumber(-7, 6), new RationalNumber(-1, 2) + (new RationalNumber(-2, 3)));
}

[Fact(Skip = "Remove to run test")]
{
Assert.Equal(new RationalNumber(0, 1), new RationalNumber(1, 2) + (new RationalNumber(-1, 2)));
}

[Fact(Skip = "Remove to run test")]
public void Subtract_two_positive_rational_numbers()
{
Assert.Equal(new RationalNumber(-1, 6), new RationalNumber(1, 2) - (new RationalNumber(2, 3)));
}

[Fact(Skip = "Remove to run test")]
public void Subtract_a_positive_rational_number_and_a_negative_rational_number()
{
Assert.Equal(new RationalNumber(7, 6), new RationalNumber(1, 2) - (new RationalNumber(-2, 3)));
}

[Fact(Skip = "Remove to run test")]
public void Subtract_two_negative_rational_numbers()
{
Assert.Equal(new RationalNumber(1, 6), new RationalNumber(-1, 2) - (new RationalNumber(-2, 3)));
}

[Fact(Skip = "Remove to run test")]
public void Subtract_a_rational_number_from_itself()
{
Assert.Equal(new RationalNumber(0, 1), new RationalNumber(1, 2) - (new RationalNumber(1, 2)));
}

[Fact(Skip = "Remove to run test")]
public void Multiply_two_positive_rational_numbers()
{
Assert.Equal(new RationalNumber(1, 3), new RationalNumber(1, 2) * (new RationalNumber(2, 3)));
}

[Fact(Skip = "Remove to run test")]
public void Multiply_a_negative_rational_number_by_a_positive_rational_number()
{
Assert.Equal(new RationalNumber(-1, 3), new RationalNumber(-1, 2) * (new RationalNumber(2, 3)));
}

[Fact(Skip = "Remove to run test")]
public void Multiply_two_negative_rational_numbers()
{
Assert.Equal(new RationalNumber(1, 3), new RationalNumber(-1, 2) * (new RationalNumber(-2, 3)));
}

[Fact(Skip = "Remove to run test")]
public void Multiply_a_rational_number_by_its_reciprocal()
{
Assert.Equal(new RationalNumber(1, 1), new RationalNumber(1, 2) * (new RationalNumber(2, 1)));
}

[Fact(Skip = "Remove to run test")]
public void Multiply_a_rational_number_by_1()
{
Assert.Equal(new RationalNumber(1, 2), new RationalNumber(1, 2) * (new RationalNumber(1, 1)));
}

[Fact(Skip = "Remove to run test")]
public void Multiply_a_rational_number_by_0()
{
Assert.Equal(new RationalNumber(0, 1), new RationalNumber(1, 2) * (new RationalNumber(0, 1)));
}

[Fact(Skip = "Remove to run test")]
public void Divide_two_positive_rational_numbers()
{
Assert.Equal(new RationalNumber(3, 4), new RationalNumber(1, 2) / (new RationalNumber(2, 3)));
}

[Fact(Skip = "Remove to run test")]
public void Divide_a_positive_rational_number_by_a_negative_rational_number()
{
Assert.Equal(new RationalNumber(-3, 4), new RationalNumber(1, 2) / (new RationalNumber(-2, 3)));
}

[Fact(Skip = "Remove to run test")]
public void Divide_two_negative_rational_numbers()
{
Assert.Equal(new RationalNumber(3, 4), new RationalNumber(-1, 2) / (new RationalNumber(-2, 3)));
}

[Fact(Skip = "Remove to run test")]
public void Divide_a_rational_number_by_1()
{
Assert.Equal(new RationalNumber(1, 2), new RationalNumber(1, 2) / (new RationalNumber(1, 1)));
}

[Fact(Skip = "Remove to run test")]
public void Absolute_value_of_a_positive_rational_number()
{
Assert.Equal(new RationalNumber(1, 2), new RationalNumber(1, 2).Abs());
}

[Fact(Skip = "Remove to run test")]
public void Absolute_value_of_a_negative_rational_number()
{
Assert.Equal(new RationalNumber(1, 2), new RationalNumber(-1, 2).Abs());
}

[Fact(Skip = "Remove to run test")]
public void Absolute_value_of_zero()
{
Assert.Equal(new RationalNumber(0, 1), new RationalNumber(0, 1).Abs());
}

[Fact(Skip = "Remove to run test")]
public void Raise_a_positive_rational_number_to_a_positive_integer_power()
{
Assert.Equal(new RationalNumber(1, 8), new RationalNumber(1, 2).Exprational(3));
}

[Fact(Skip = "Remove to run test")]
public void Raise_a_negative_rational_number_to_a_positive_integer_power()
{
Assert.Equal(new RationalNumber(-1, 8), new RationalNumber(-1, 2).Exprational(3));
}

[Fact(Skip = "Remove to run test")]
public void Raise_zero_to_an_integer_power()
{
Assert.Equal(new RationalNumber(0, 1), new RationalNumber(0, 1).Exprational(5));
}

[Fact(Skip = "Remove to run test")]
public void Raise_one_to_an_integer_power()
{
Assert.Equal(new RationalNumber(1, 1), new RationalNumber(1, 1).Exprational(4));
}

[Fact(Skip = "Remove to run test")]
public void Raise_a_positive_rational_number_to_the_power_of_zero()
{
Assert.Equal(new RationalNumber(1, 1), new RationalNumber(1, 2).Exprational(0));
}

[Fact(Skip = "Remove to run test")]
public void Raise_a_negative_rational_number_to_the_power_of_zero()
{
Assert.Equal(new RationalNumber(1, 1), new RationalNumber(-1, 2).Exprational(0));
}

[Fact(Skip = "Remove to run test")]
public void Raise_a_real_number_to_a_positive_rational_number()
{
Assert.Equal(16, 8.Expreal(new RationalNumber(4, 3)), precision: 7);
}

[Fact(Skip = "Remove to run test")]
public void Raise_a_real_number_to_a_negative_rational_number()
{
Assert.Equal(0.3333333, 9.Expreal(new RationalNumber(-1, 2)), precision: 7);
}

[Fact(Skip = "Remove to run test")]
public void Raise_a_real_number_to_a_zero_rational_number()
{
Assert.Equal(1, 2.Expreal(new RationalNumber(0, 1)), precision: 7);
}

[Fact(Skip = "Remove to run test")]
public void Reduce_a_positive_rational_number_to_lowest_terms()
{
Assert.Equal(new RationalNumber(1, 2), new RationalNumber(2, 4).Reduce());
}

[Fact(Skip = "Remove to run test")]
public void Reduce_a_negative_rational_number_to_lowest_terms()
{
Assert.Equal(new RationalNumber(-2, 3), new RationalNumber(-4, 6).Reduce());
}

[Fact(Skip = "Remove to run test")]
public void Reduce_a_rational_number_with_a_negative_denominator_to_lowest_terms()
{
Assert.Equal(new RationalNumber(-1, 3), new RationalNumber(3, -9).Reduce());
}

[Fact(Skip = "Remove to run test")]
public void Reduce_zero_to_lowest_terms()
{
Assert.Equal(new RationalNumber(0, 1), new RationalNumber(0, 6).Reduce());
}

[Fact(Skip = "Remove to run test")]
public void Reduce_an_integer_to_lowest_terms()
{
Assert.Equal(new RationalNumber(-2, 1), new RationalNumber(-14, 7).Reduce());
}

[Fact(Skip = "Remove to run test")]
public void Reduce_one_to_lowest_terms()
{
Assert.Equal(new RationalNumber(1, 1), new RationalNumber(13, 13).Reduce());
}
}``````
``````﻿using System;
using System.Diagnostics;

public static class RealNumberExtension
{
public static double Expreal(this int realNumber, RationalNumber r)
{
return r.Expreal(realNumber);
}

public static int GetMaxFactor(int numerator, int denominator)
{
if (numerator % denominator == 0)
{
return denominator;
}
if (denominator % numerator == 0)
{
return numerator;
}

var factor = 1;
for (var i = 2; i <= Math.Min(Math.Abs(numerator), Math.Abs(denominator)) / 2; i++)
{
if (numerator % i == 0 && denominator % i == 0)
{
factor = i;
}
}
return factor;
}
}

public struct RationalNumber
{
private int _numerator;
private int _denominator;

public RationalNumber(int numerator, int denominator)
{
if (denominator == 0)
{
throw new ArgumentException("denominator should not be zero");
}
if (numerator == 0)
{
_numerator = 0;
_denominator = 1;
}
else if (denominator < 0)
{
_numerator = -1 * numerator;
_denominator = -1 * denominator;
}
else
{
_numerator = numerator;
_denominator = denominator;
}
}

{
var numerator = _numerator * r._denominator + _denominator * r._numerator;
var denominator = _denominator * r._denominator;
return new RationalNumber(numerator, denominator).Reduce();
}

public static RationalNumber operator +(RationalNumber r1, RationalNumber r2)
{
}

public RationalNumber Sub(RationalNumber r)
{
var numerator = _numerator * r._denominator - _denominator * r._numerator;
var denominator = _denominator * r._denominator;
return new RationalNumber(numerator, denominator).Reduce();
}

public static RationalNumber operator -(RationalNumber r1, RationalNumber r2)
{
return r1.Sub(r2);
}

public RationalNumber Mul(RationalNumber r)
{
var numerator = _numerator * r._numerator;
var denominator = _denominator * r._denominator;
return new RationalNumber(numerator, denominator).Reduce();
}

public static RationalNumber operator *(RationalNumber r1, RationalNumber r2)
{
return r1.Mul(r2);
}

public RationalNumber Div(RationalNumber r)
{
var numerator = _numerator * r._denominator;
var denominator = _denominator * r._numerator;
return new RationalNumber(numerator, denominator).Reduce();
}

public static RationalNumber operator /(RationalNumber r1, RationalNumber r2)
{
return r1.Div(r2);
}

public RationalNumber Abs()
{
return new RationalNumber(Math.Abs(_numerator), Math.Abs(_denominator));
}

public RationalNumber Reduce()
{
var factor = RealNumberExtension.GetMaxFactor(_numerator, _denominator);
return new RationalNumber(_numerator / factor, _denominator / factor);
}

public RationalNumber Exprational(int power)
{
return new RationalNumber((int)Math.Pow(_numerator, power), (int)Math.Pow(_denominator, power));
}

public double Expreal(int baseNumber)
{
return Math.Pow(Math.Pow(baseNumber, _numerator), 1.0 / _denominator);
}
}``````