The base for a fraction class. Can be used to represent rational numbers precisely.
using System;
using System.Text.RegularExpressions;
public class Fraction
{
private int denominator = 1;
private int nominator = 0;
public Fraction() {
}
public Fraction(int n, int d) {
Nominator = n;
Denominator = d;
}
public static Fraction One => new Fraction { nominator = 1, denominator = 1 };
public static Fraction Zero => new Fraction { nominator = 0, denominator = 1 };
public int Denominator {
get {
Shorten();
return denominator;
}
set {
if (value == 0)
throw new DivideByZeroException("Fraction can not have a denominator with the value of 0");
denominator = value;
Shorten();
}
}
public int Nominator {
get {
Shorten();
return nominator;
}
set {
nominator = value;
Shorten();
}
}
#region Operators
public static implicit operator Fraction(int i) => new Fraction(i, 1);
public static explicit operator double(Fraction f) => f.Nominator / (double)f.Denominator;
public static explicit operator decimal(Fraction f) => f.Nominator / (decimal)f.Denominator;
public static explicit operator float(Fraction f) => f.Nominator / (float)f.Denominator;
public static Fraction operator -(Fraction f) {
return new Fraction(-f.Nominator, f.Denominator);
}
public static Fraction operator -(Fraction f1, Fraction f2) {
return f1 + (-f2);
}
public static bool operator !=(Fraction f1, Fraction f2) {
return !(f1 == f2);
}
public static Fraction operator *(Fraction f1, Fraction f2) {
return new Fraction {
Nominator = f1.Nominator * f2.Nominator,
Denominator = f1.Denominator * f2.Denominator
};
}
public static Fraction operator /(Fraction f1, Fraction f2) {
return f1 * f2.Inverse();
}
public static Fraction operator +(Fraction f1, Fraction f2) {
return new Fraction() {
Nominator = f1.Denominator * f2.Nominator + f1.Nominator * f2.Denominator,
Denominator = f1.Denominator * f2.Denominator
};
}
public static bool operator ==(Fraction f1, Fraction f2) {
if (f1 == null && f2 == null) return true;
if (f1 == null) return false;
return f1.Equals(f2);
}
#endregion Operators
public static Fraction Parse(string s) {
var regex = new Regex(@"(?<nominator>-?\d+)(?:\/(?<denominator>-?\d+))?");
var m = regex.Match(s);
if (!m.Success)
throw new FormatException();
var n = int.Parse(m.Groups["nominator"].Value);
var d = !string.IsNullOrEmpty(m.Groups["denominator"].Value) ? int.Parse(m.Groups["denominator"].Value) : 1;
return new Fraction(n, d);
}
public static Fraction Pow(Fraction f, int exponent = 2) {
return new Fraction((int)Math.Pow(f.Nominator, exponent), (int)Math.Pow(f.Denominator, exponent));
}
public static Fraction Sqrt(Fraction f) {
if (!IsPerfectSquare(f.Nominator) || !IsPerfectSquare(f.Denominator)) throw new ArgumentException("The nominator or denominator are not perfect squares");
return new Fraction((int)Math.Sqrt(f.Nominator), (int)Math.Sqrt(f.Denominator));
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((Fraction)obj);
}
public override int GetHashCode() {
unchecked {
return (Nominator * 397) ^ denominator;
}
}
public Fraction Inverse() {
return new Fraction(Denominator, Nominator);
}
public override string ToString() {
return $"{Nominator}/{Denominator}";
}
protected bool Equals(Fraction other) {
return Nominator == other.Nominator && Denominator == other.Denominator;
}
private static int Gcd(int a, int b) {
while (true) {
if (b == 0) return a;
var temp = a;
a = b;
b = temp % b;
}
}
private static bool IsPerfectSquare(double input) {
// source http://stackoverflow.com/a/4886006/1697953
var sqrt = Math.Sqrt(input);
return Math.Abs(Math.Ceiling(sqrt) - Math.Floor(sqrt)) < Double.Epsilon;
}
private void Shorten() {
var gcd = Gcd(nominator, denominator);
nominator /= gcd;
denominator /= gcd;
if (denominator < 0 && nominator >= 0) {
nominator = -nominator;
denominator = -denominator;
}
}
}