/// <summary> /// Add two rationals /// </summary> public static Rational32 Add(Rational32 a, Rational32 b) { // self = a/b, other = c/d var a_sign = a.Sign(); var b_sign = b.Sign(); var num = (a.Numerator64() * a_sign) * b.Denominator64(); num += a.Denominator64() * (b.Numerator64() * b_sign); var den = a.Denominator64() * b.Denominator64(); var sign = num < 0; if (sign) { num = -num; } // Try to find an exact result var gcd = GCD(num, den); num /= gcd; den /= gcd; // Reduce precision until it fits while (num > MaxInt || WouldOverflow((uint)num, (uint)den)) { gcd = GCD(num, den); if (gcd == 1) { num /= 2; den /= 2; } else { num /= gcd; den /= gcd; } if (den < 1) { den = 1; break; } } return(new Rational32(sign, (uint)num, (uint)den)); }
/// <summary> /// /// </summary> /// <param name="f"></param> /// <returns></returns> public static Rational32 FromFloat(double f) { // The plan: split float into int and frac parts // With frac, invert and build rational. Invert that rational and add int part var sign = f < 0; if (sign) { f = -f; } var num = (long)f; var frac = f - num; if (Math.Abs(frac) < Sigma) { return(new Rational32(sign, (uint)num, 1)); // close enough to an integer } var top = new Rational32(sign, (uint)num, 1); var inv = new Rational32(sign, 1, (uint)(1 / frac)); return(Add(top, inv)); }