📷 A modern, cross-platform, 2D Graphics library for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

219 lines
5.2 KiB

// <copyright file="Rational.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
using System;
using System.Text;
internal struct BigRational : IEquatable<BigRational>
{
private bool IsIndeterminate
{
get
{
if (Denominator != 0)
return false;
return Numerator == 0;
}
}
private bool IsInteger => Denominator == 1;
private bool IsNegativeInfinity
{
get
{
if (Denominator != 0)
return false;
return Numerator == -1;
}
}
private bool IsPositiveInfinity
{
get
{
if (Denominator != 0)
return false;
return Numerator == 1;
}
}
private bool IsZero
{
get
{
if (Denominator != 1)
return false;
return Numerator == 0;
}
}
private static long GreatestCommonDivisor(long a, long b)
{
return b == 0 ? a : GreatestCommonDivisor(b, a % b);
}
private void Simplify()
{
if (IsIndeterminate)
return;
if (IsNegativeInfinity)
return;
if (IsPositiveInfinity)
return;
if (IsInteger)
return;
if (IsZero)
return;
if (Numerator == 0)
{
Denominator = 0;
return;
}
if (Numerator == Denominator)
{
Numerator = 1;
Denominator = 1;
}
long gcd = GreatestCommonDivisor(Math.Abs(Numerator), Math.Abs(Denominator));
if (gcd > 1)
{
Numerator = Numerator / gcd;
Denominator = Denominator / gcd;
}
}
public BigRational(long numerator, long denominator)
: this(numerator, denominator, false)
{
}
public BigRational(long numerator, long denominator, bool simplify)
{
Numerator = numerator;
Denominator = denominator;
if (simplify)
Simplify();
}
public BigRational(double value, bool bestPrecision)
{
if (double.IsNaN(value))
{
Numerator = Denominator = 0;
return;
}
if (double.IsPositiveInfinity(value))
{
Numerator = 1;
Denominator = 0;
return;
}
if (double.IsNegativeInfinity(value))
{
Numerator = -1;
Denominator = 0;
return;
}
Numerator = 1;
Denominator = 1;
double val = Math.Abs(value);
double df = Numerator / (double)Denominator;
double epsilon = bestPrecision ? double.Epsilon : .000001;
while (Math.Abs(df - val) > epsilon)
{
if (df < val)
Numerator++;
else
{
Denominator++;
Numerator = (int)(val * Denominator);
}
df = Numerator / (double)Denominator;
}
if (value < 0.0)
Numerator *= -1;
Simplify();
}
public long Denominator
{
get;
private set;
}
public long Numerator
{
get;
private set;
}
public bool Equals(BigRational other)
{
if (Denominator == other.Denominator)
return Numerator == other.Numerator;
if (Numerator == 0 && Denominator == 0)
return other.Numerator == 0 && other.Denominator == 0;
if (other.Numerator == 0 && other.Denominator == 0)
return Numerator == 0 && Denominator == 0;
return (Numerator * other.Denominator) == (Denominator * other.Numerator);
}
public override int GetHashCode()
{
return ((Numerator * 397) ^ Denominator).GetHashCode();
}
public string ToString(IFormatProvider provider)
{
if (IsIndeterminate)
return "[ Indeterminate ]";
if (IsPositiveInfinity)
return "[ PositiveInfinity ]";
if (IsNegativeInfinity)
return "[ NegativeInfinity ]";
if (IsZero)
return "0";
if (IsInteger)
return Numerator.ToString(provider);
StringBuilder sb = new StringBuilder();
sb.Append(Numerator.ToString(provider));
sb.Append("/");
sb.Append(Denominator.ToString(provider));
return sb.ToString();
}
}
}