c#中的十进制到精确分数转换器

时间:2017-01-31 04:21:00

标签: c# decimal fractions

所以我已经开始了一个项目,在那里我制作了一个二次方程求解器,我已经设法做到了。我的下一步是转换X 1 和X 2 的值,例如。(X + X 1 )(X + X 2 )到精确分数,如果它们变成小数。

所以一个例子是:

  

12x 2 + 44x + 21

     

给了我,

     

X 1 = -3.10262885097732

     

X 2 = -0.564037815689349

但是我怎么能将它转换成精确的分数呢? 谢谢你的帮助!

1 个答案:

答案 0 :(得分:0)

您可以使用Continued Fractions解决此问题。

正如评论中所述,您无法获得完全代表rational number的分数(irrational number),但您可以非常接近。

我在宠物项目中实施了一次有理数字类型。你可以找到它here。查看TryFromDouble以获取如何使用连续分数将任何给定数字得到最接近的有理数(具有指定精度)的示例。

相关代码的摘录如下(我会 不发布整个类型的实现,因为它太长了,但代码应该仍然是可以理解的):

public static bool TryFromDouble(double target, double precision, out Rational result)
{
    //Continued fraction algorithm: http://en.wikipedia.org/wiki/Continued_fraction
    //Implemented recursively. Problem is figuring out when precision is met without unwinding each solution. Haven't figured out how to do that.
    //Current implementation computes rational number approximations for increasing algorithm depths until precision criteria is met, maximum depth is reached (fromDoubleMaxIterations)
    //or an OverflowException is thrown. Efficiency is probably improvable but this method will not be used in any performance critical code. No use in optimizing it unless there is
    //a good reason. Current implementation works reasonably well.

    result = zero;
    int steps = 0;

    while (Math.Abs(target - Rational.ToDouble(result)) > precision)
    {
        if (steps > fromDoubleMaxIterations)
        {
            result = zero;
            return false;
        }

        result = getNearestRationalNumber(target, 0, steps++);
    }

    return true;
}

private static Rational getNearestRationalNumber(double number, int currentStep, int maximumSteps)
{
    var integerPart = (BigInteger)number;
    double fractionalPart = number - Math.Truncate(number);

    while (currentStep < maximumSteps && fractionalPart != 0)
    {
        return integerPart + new Rational(1, getNearestRationalNumber(1 / fractionalPart, ++currentStep, maximumSteps));
    }

    return new Rational(integerPart);
}