Files
ADOFAIRenderer/Util/RationalUtil.cs
T

58 lines
2.0 KiB
C#

using System;
namespace ADOFAIRenderer.Util
{
internal static class RationalUtil
{
public static (int Numerator, int Denominator) Double2MaxPrecisionInt(double value,
int maxDenominator = 100000000)
{
// 1. Edge case handling and sign detection
if (value == 0.0) return (0, 1);
var isNegative = value < 0;
var target = Math.Abs(value);
// 2. Stern-Brocot / continued fraction boundary initialization
// Starts between (0/1, 1/0) and converges towards the target value.
long m00 = 0, m01 = 1;
long m10 = 1, m11 = 0;
var x = target;
// Iterate while preventing integer overflow
while (true)
{
var ai = (long)Math.Floor(x);
// Calculate next numerator and denominator (temporarily computed as long to prevent overflow)
var nextNumerator = ai * m10 + m00;
var nextDenominator = ai * m11 + m01;
// If exceeding integer range or specified maximum denominator, return previous optimal value
if (nextNumerator > int.MaxValue || nextDenominator > maxDenominator)
{
break;
}
// Update matrix
m00 = m10; m01 = m11;
m10 = nextNumerator; m11 = nextDenominator;
// Terminate if error is negligible (precision limit reached)
if (Math.Abs(x - ai) < 1e-15) break;
// Prepare next continued fraction term
x = 1.0 / (x - ai);
}
// 3. Final determined integer numerator and denominator
var finalNumerator = (int)m10;
var finalDenominator = (int)m11;
// Restore sign
if (isNegative) finalNumerator = -finalNumerator;
return (finalNumerator, finalDenominator);
}
}
}