Beispiel #1
0
        public static Fraction ToFract(double val, double precision)
        {
            // find nearest fraction
            ulong intPart = (ulong)val;
            val -= intPart;

            Fraction low = new Fraction(0, 1);           // "A" = 0/1 (a/b)
            Fraction high = new Fraction(1, 1);          // "B" = 1/1 (c/d)

            for (; ; )
            {
                Debug.Assert(low.Val <= val);
                Debug.Assert(high.Val >= val);

                //         b*m - a
                //     x = -------
                //         c - d*m
                double testLow = low.Denom * val - low.Num;
                double testHigh = high.Num - high.Denom * val;
                // test for match:
                //
                // m - a/b < precision
                //
                // ==>
                //
                // b * m - a < b * precision
                //
                // which is happening here: check both the current A and B fractions.
                //if (testHigh < high.denom * Precision)
                if (testHigh < precision) // [i_a] speed improvement; this is even better for irrational 'val'
                {
                    break; // high is answer
                }
                //if (testLow < low.denom * Precision)
                if (testLow < precision) // [i_a] speed improvement; this is even better for irrational 'val'
                {
                    // low is answer
                    high = low;
                    break;
                }

                double x1 = testHigh / testLow;
                double x2 = testLow / testHigh;

                // always choose the path where we find the largest change in direction:
                if (x1 > x2)
                {
                    //double x1 = testHigh / testLow;
                    // safety checks: are we going to be out of integer bounds?
                    if ((x1 + 1) * low.Denom + high.Denom >= long.MaxValue)
                    {
                        break;
                    }

                    ulong n = (ulong)x1;    // lower bound for m
                    //int m = n + 1;    // upper bound for m

                    //     a + x*c
                    //     ------- = m
                    //     b + x*d
                    ulong hNum = n * low.Num + high.Num;
                    ulong hDenom = n * low.Denom + high.Denom;

                    //ulong l_num = m * low.num + high.num;
                    //ulong l_denom = m * low.denom + high.denom;
                    ulong lNum = hNum + low.Num;
                    ulong lDenom = hDenom + low.Denom;

                    low.Num = lNum;
                    low.Denom = lDenom;
                    high.Num = hNum;
                    high.Denom = hDenom;
                }
                else
                {
                    //double x2 = testLow / testHigh;
                    // safety checks: are we going to be out of integer bounds?
                    if (low.Denom + (x2 + 1) * high.Denom >= ulong.MaxValue)
                    {
                        break;
                    }

                    ulong n = (ulong)x2;    // lower bound for m
                    //ulong m = n + 1;    // upper bound for m

                    //     a + x*c
                    //     ------- = m
                    //     b + x*d
                    ulong lNum = low.Num + n * high.Num;
                    ulong lDenom = low.Denom + n * high.Denom;

                    //ulong h_num = low.num + m * high.num;
                    //ulong h_denom = low.denom + m * high.denom;
                    ulong hNum = lNum + high.Num;
                    ulong hDenom = lDenom + high.Denom;

                    high.Num = hNum;
                    high.Denom = hDenom;
                    low.Num = lNum;
                    low.Denom = lDenom;
                }
                Debug.Assert(low.Val <= val);
                Debug.Assert(high.Val >= val);
            }

            high.Num += high.Denom * intPart;
            return high;
        }
Beispiel #2
0
        public static Fraction ToFract(double val, double precision)
        {
            // find nearest fraction
            ulong intPart = (ulong)val;

            val -= intPart;

            Fraction low  = new Fraction(0, 1);          // "A" = 0/1 (a/b)
            Fraction high = new Fraction(1, 1);          // "B" = 1/1 (c/d)

            for (; ;)
            {
                Debug.Assert(low.Val <= val);
                Debug.Assert(high.Val >= val);

                //         b*m - a
                //     x = -------
                //         c - d*m
                double testLow  = low.Denom * val - low.Num;
                double testHigh = high.Num - high.Denom * val;
                // test for match:
                //
                // m - a/b < precision
                //
                // ==>
                //
                // b * m - a < b * precision
                //
                // which is happening here: check both the current A and B fractions.
                //if (testHigh < high.denom * Precision)
                if (testHigh < precision) // [i_a] speed improvement; this is even better for irrational 'val'
                {
                    break;                // high is answer
                }
                //if (testLow < low.denom * Precision)
                if (testLow < precision) // [i_a] speed improvement; this is even better for irrational 'val'
                {
                    // low is answer
                    high = low;
                    break;
                }

                double x1 = testHigh / testLow;
                double x2 = testLow / testHigh;

                // always choose the path where we find the largest change in direction:
                if (x1 > x2)
                {
                    //double x1 = testHigh / testLow;
                    // safety checks: are we going to be out of integer bounds?
                    if ((x1 + 1) * low.Denom + high.Denom >= long.MaxValue)
                    {
                        break;
                    }

                    ulong n = (ulong)x1;    // lower bound for m
                    //int m = n + 1;    // upper bound for m

                    //     a + x*c
                    //     ------- = m
                    //     b + x*d
                    ulong hNum   = n * low.Num + high.Num;
                    ulong hDenom = n * low.Denom + high.Denom;

                    //ulong l_num = m * low.num + high.num;
                    //ulong l_denom = m * low.denom + high.denom;
                    ulong lNum   = hNum + low.Num;
                    ulong lDenom = hDenom + low.Denom;

                    low.Num    = lNum;
                    low.Denom  = lDenom;
                    high.Num   = hNum;
                    high.Denom = hDenom;
                }
                else
                {
                    //double x2 = testLow / testHigh;
                    // safety checks: are we going to be out of integer bounds?
                    if (low.Denom + (x2 + 1) * high.Denom >= ulong.MaxValue)
                    {
                        break;
                    }

                    ulong n = (ulong)x2;    // lower bound for m
                    //ulong m = n + 1;    // upper bound for m

                    //     a + x*c
                    //     ------- = m
                    //     b + x*d
                    ulong lNum   = low.Num + n * high.Num;
                    ulong lDenom = low.Denom + n * high.Denom;

                    //ulong h_num = low.num + m * high.num;
                    //ulong h_denom = low.denom + m * high.denom;
                    ulong hNum   = lNum + high.Num;
                    ulong hDenom = lDenom + high.Denom;

                    high.Num   = hNum;
                    high.Denom = hDenom;
                    low.Num    = lNum;
                    low.Denom  = lDenom;
                }
                Debug.Assert(low.Val <= val);
                Debug.Assert(high.Val >= val);
            }

            high.Num += high.Denom * intPart;
            return(high);
        }