using System; namespace Cryville.Common.Math { /// /// Provides a set of methods related to fractions. /// public static class FractionUtils { /// /// Converts a decimal to a fraction. /// /// The decimal. /// The error. /// The numerator. /// The denominator. /// is less than 0 or is not greater than 0 or greater than 1. public static void ToFraction(double value, double error, out int n, out int d) { if (value < 0.0) throw new ArgumentOutOfRangeException("value", "Must be >= 0."); if (error <= 0.0 || error > 1.0) throw new ArgumentOutOfRangeException("error", "Must be > 0 and <= 1."); int num = (int)System.Math.Floor(value); value -= num; if (value < error) { n = num; d = 1; return; } if (1 - error < value) { n = num + 1; d = 1; return; } int lower_n = 0; int lower_d = 1; int upper_n = 1; int upper_d = 1; while (true) { int middle_n = lower_n + upper_n; int middle_d = lower_d + upper_d; if (middle_d * (value + error) < middle_n) { upper_n = middle_n; upper_d = middle_d; } else if (middle_n < (value - error) * middle_d) { lower_n = middle_n; lower_d = middle_d; } else { n = num * middle_d + middle_n; d = middle_d; return; } } } /// /// Gets the greatest common divisor (GCD) of two integers. /// /// The first integer. /// The second integer. /// The greatest common divisor (GCD) of the two integers. public static int GreatestCommonDivisor(int n, int d) { while (d != 0) { int t = d; d = n % d; n = t; } return n; } /// /// Simplifies a fraction. /// /// The numerator. /// The denominator. public static void Simplify(ref int n, ref int d) { var gcd = GreatestCommonDivisor(n, d); n /= gcd; d /= gcd; } } }