Arithmetic/Rational/C sharp

From Rosetta Code
Arithmetic/Rational/C sharp is part of Rational Arithmetic. You may find other members of Rational Arithmetic at Category:Rational Arithmetic.
using System;
 
struct Fraction : IEquatable<Fraction>, IComparable<Fraction>
{
public readonly long Num;
public readonly long Denom;
 
public Fraction(long num, long denom)
{
if (num == 0)
{
denom = 1;
}
else if (denom == 0)
{
throw new ArgumentException("Denominator may not be zero", "denom");
}
else if (denom < 0)
{
num = -num;
denom = -denom;
}
 
long d = GCD(num, denom);
this.Num = num / d;
this.Denom = denom / d;
}
 
private static long GCD(long x, long y)
{
return y == 0 ? x : GCD(y, x % y);
}
 
private static long LCM(long x, long y)
{
return x / GCD(x, y) * y;
}
 
public Fraction Abs()
{
return new Fraction(Math.Abs(Num), Denom);
}
 
public Fraction Reciprocal()
{
return new Fraction(Denom, Num);
}
 
#region Conversion Operators
 
public static implicit operator Fraction(long i)
{
return new Fraction(i, 1);
}
 
public static explicit operator double(Fraction f)
{
return f.Num == 0 ? 0 : (double)f.Num / f.Denom;
}
 
#endregion
 
#region Arithmetic Operators
 
public static Fraction operator -(Fraction f)
{
return new Fraction(-f.Num, f.Denom);
}
 
public static Fraction operator +(Fraction a, Fraction b)
{
long m = LCM(a.Denom, b.Denom);
long na = a.Num * m / a.Denom;
long nb = b.Num * m / b.Denom;
return new Fraction(na + nb, m);
}
 
public static Fraction operator -(Fraction a, Fraction b)
{
return a + (-b);
}
 
public static Fraction operator *(Fraction a, Fraction b)
{
return new Fraction(a.Num * b.Num, a.Denom * b.Denom);
}
 
public static Fraction operator /(Fraction a, Fraction b)
{
return a * b.Reciprocal();
}
 
public static Fraction operator %(Fraction a, Fraction b)
{
long l = a.Num * b.Denom, r = a.Denom * b.Num;
long n = l / r;
return new Fraction(l - n * r, a.Denom * b.Denom);
}
 
#endregion
 
#region Comparison Operators
 
public static bool operator ==(Fraction a, Fraction b)
{
return a.Num == b.Num && a.Denom == b.Denom;
}
 
public static bool operator !=(Fraction a, Fraction b)
{
return a.Num != b.Num || a.Denom != b.Denom;
}
 
public static bool operator <(Fraction a, Fraction b)
{
return (a.Num * b.Denom) < (a.Denom * b.Num);
}
 
public static bool operator >(Fraction a, Fraction b)
{
return (a.Num * b.Denom) > (a.Denom * b.Num);
}
 
public static bool operator <=(Fraction a, Fraction b)
{
return !(a > b);
}
 
public static bool operator >=(Fraction a, Fraction b)
{
return !(a < b);
}
 
#endregion
 
#region Object Members
 
public override bool Equals(object obj)
{
if (obj is Fraction)
return ((Fraction)obj) == this;
else
return false;
}
 
public override int GetHashCode()
{
return Num.GetHashCode() ^ Denom.GetHashCode();
}
 
public override string ToString()
{
return Num.ToString() + "/" + Denom.ToString();
}
 
#endregion
 
#region IEquatable<Fraction> Members
 
public bool Equals(Fraction other)
{
return other == this;
}
 
#endregion
 
#region IComparable<Fraction> Members
 
public int CompareTo(Fraction other)
{
return (this.Num * other.Denom).CompareTo(this.Denom * other.Num);
}
 
#endregion
}

Test program:

using System;
 
static class Program
{
static void Main(string[] args)
{
int max = 1 << 19;
for (int candidate = 2; candidate < max; candidate++)
{
Fraction sum = new Fraction(1, candidate);
int max2 = (int)Math.Sqrt(candidate);
for (int factor = 2; factor <= max2; factor++)
{
if (candidate % factor == 0)
{
sum += new Fraction(1, factor);
sum += new Fraction(1, candidate / factor);
}
}
 
if (sum == 1)
Console.WriteLine("{0} is perfect", candidate);
}
}
}
Output:
6 is perfect
28 is perfect
496 is perfect
8128 is perfect