Convert double to fraction as string in C#
Asked Answered
T

2

6

I want to display double value as fraction in C#, how can I do this ?

Thanks

Three answered 27/9, 2011 at 6:11 Comment(3)
It is your interest... You can write a method for it. Try out we help you.Burchette
Step 1: convert to fraction. Step 2: simplify. mathsisfun.com/converting-decimals-fractions.htmlDoleful
Step 0: make an example to make sure you know clearly what you want!Tallage
H
5

Try this Fraction class for C#.

/*
 * Author: Syed Mehroz Alam
 * Email: [email protected]
 * URL: Programming Home "http://www.geocities.com/smehrozalam/" 
 * Date: 6/15/2004
 * Time: 10:54 AM
 *
 */

using System;

namespace Mehroz
{
    /// <summary>
    /// Classes Contained:
    ///     Fraction
    ///     FractionException
    /// </summary>


    /// Class name: Fraction
    /// Developed by: Syed Mehroz Alam
    /// Email: [email protected]
    /// URL: Programming Home "http://www.geocities.com/smehrozalam/"
    /// Version: 2.0
    /// 
    /// What's new in version 2.0:
    ///     *   Changed Numerator and Denominator from Int32(integer) to Int64(long) for increased range
    ///     *   renamed ConvertToString() to (overloaded) ToString()
    ///     *   added the capability of detecting/raising overflow exceptions
    ///     *   Fixed the bug that very small numbers e.g. 0.00000001 could not be converted to fraction
    ///     *   Other minor bugs fixed
    /// 
    /// What's new in version 2.1
    ///     *   overloaded user-defined conversions to/from Fractions
    ///     
    /// 
    /// Properties:
    ///     Numerator: Set/Get value for Numerator
    ///     Denominator:  Set/Get value for Numerator
    ///     Value:  Set an integer value for the fraction
    /// 
    /// Constructors:
    ///     no arguments:   initializes fraction as 0/1
    ///     (Numerator, Denominator): initializes fraction with the given numerator and denominator values
    ///     (integer):  initializes fraction with the given integer value
    ///     (long): initializes fraction with the given long value
    ///     (double):   initializes fraction with the given double value
    ///     (string):   initializes fraction with the given string value
    ///                 the string can be an in the form of and integer, double or fraction.
    ///                 e.g it can be like "123" or "123.321" or "123/456"
    /// 
    /// Public Methods (Description is given with respective methods' definitions)
    ///     (override) string ToString(Fraction)
    ///     Fraction ToFraction(string)
    ///     Fraction ToFraction(double)
    ///     double ToDouble(Fraction)
    ///     Fraction Duplicate()
    ///     Fraction Inverse(integer)
    ///     Fraction Inverse(Fraction)
    ///     ReduceFraction(Fraction)
    ///     Equals(object)
    ///     GetHashCode()
    /// 
    /// Private Methods (Description is given with respective methods' definitions)
    ///     Initialize(Numerator, Denominator)
    ///     Fraction Negate(Fraction)
    ///     Fraction Add(Fraction1, Fraction2)
    /// 
    /// Overloaded Operators (overloaded for Fractions, Integers and Doubles)
    ///     Unary: -
    ///     Binary: +,-,*,/ 
    ///     Relational and Logical Operators: ==,!=,<,>,<=,>=
    /// 
    /// Overloaded user-defined conversions
    ///     Implicit:   From double/long/string to Fraction
    ///     Explicit:   From Fraction to double/string
    /// </summary>
    public class Fraction
    {
        /// <summary>
        /// Class attributes/members
        /// </summary>
        long m_iNumerator;
        long m_iDenominator;

        /// <summary>
        /// Constructors
        /// </summary>
        public Fraction()
        {
            Initialize(0,1);
        }

        public Fraction(long iWholeNumber)
        {
            Initialize(iWholeNumber, 1);
        }

        public Fraction(double dDecimalValue)
        {
            Fraction temp=ToFraction(dDecimalValue);
            Initialize(temp.Numerator, temp.Denominator);
        }

        public Fraction(string strValue)
        {
            Fraction temp=ToFraction(strValue);
            Initialize(temp.Numerator, temp.Denominator);
        }

        public Fraction(long iNumerator, long iDenominator)
        {
            Initialize(iNumerator, iDenominator);
        }

        /// <summary>
        /// Internal function for constructors
        /// </summary>
        private void Initialize(long iNumerator, long iDenominator)
        {
            Numerator=iNumerator;
            Denominator=iDenominator;
            ReduceFraction(this);
        }

        /// <summary>
        /// Properites
        /// </summary>
        public long Denominator
        {
            get
            {   return m_iDenominator;  }
            set
            {
                if (value!=0)
                    m_iDenominator=value;
                else
                    throw new FractionException("Denominator cannot be assigned a ZERO Value");
            }
        }

        public long Numerator
        {
            get 
            {   return m_iNumerator;    }
            set
            {   m_iNumerator=value; }
        }

        public long Value
        {
            set
            {   m_iNumerator=value;
                m_iDenominator=1;   }
        }

        /// <summary>
        /// The function returns the current Fraction object as double
        /// </summary>
        public double ToDouble()
        {
            return ( (double)this.Numerator/this.Denominator );
        }

        /// <summary>
        /// The function returns the current Fraction object as a string
        /// </summary>
        public override string ToString()
        {
            string str;
            if ( this.Denominator==1 )
                str=this.Numerator.ToString();
            else
                str=this.Numerator + "/" + this.Denominator;
            return str;
        }
        /// <summary>
        /// The function takes an string as an argument and returns its corresponding reduced fraction
        /// the string can be an in the form of and integer, double or fraction.
        /// e.g it can be like "123" or "123.321" or "123/456"
        /// </summary>
        public static Fraction ToFraction(string strValue)
        {
            int i;
            for (i=0;i<strValue.Length;i++)
                if (strValue[i]=='/')
                    break;

            if (i==strValue.Length)     // if string is not in the form of a fraction
                // then it is double or integer
                return ( Convert.ToDouble(strValue));
                //return ( ToFraction( Convert.ToDouble(strValue) ) );

            // else string is in the form of Numerator/Denominator
            long iNumerator=Convert.ToInt64(strValue.Substring(0,i));
            long iDenominator=Convert.ToInt64(strValue.Substring(i+1));
            return new Fraction(iNumerator, iDenominator);
        }


        /// <summary>
        /// The function takes a floating point number as an argument 
        /// and returns its corresponding reduced fraction
        /// </summary>
        public static Fraction ToFraction(double dValue)
        {
            try
            {
                checked
                {
                    Fraction frac;
                    if (dValue%1==0)    // if whole number
                    {
                        frac=new Fraction( (long) dValue );
                    }
                    else
                    {
                        double dTemp=dValue;
                        long iMultiple=1;
                        string strTemp=dValue.ToString();
                        while ( strTemp.IndexOf("E")>0 )    // if in the form like 12E-9
                        {
                            dTemp*=10;
                            iMultiple*=10;
                            strTemp=dTemp.ToString();
                        }
                        int i=0;
                        while ( strTemp[i]!='.' )
                            i++;
                        int iDigitsAfterDecimal=strTemp.Length-i-1;
                        while ( iDigitsAfterDecimal>0  )
                        {
                            dTemp*=10;
                            iMultiple*=10;
                            iDigitsAfterDecimal--;
                        }
                        frac=new Fraction( (int)Math.Round(dTemp) , iMultiple );
                    }
                    return frac;
                }
            }
            catch(OverflowException)
            {
                throw new FractionException("Conversion not possible due to overflow");
            }
            catch(Exception)
            {
                throw new FractionException("Conversion not possible");
            }
        }

        /// <summary>
        /// The function replicates current Fraction object
        /// </summary>
        public Fraction Duplicate()
        {
            Fraction frac=new Fraction();
            frac.Numerator=Numerator;
            frac.Denominator=Denominator;
            return frac;
        }

        /// <summary>
        /// The function returns the inverse of a Fraction object
        /// </summary>
        public static Fraction Inverse(Fraction frac1)
        {
            if (frac1.Numerator==0)
                throw new FractionException("Operation not possible (Denominator cannot be assigned a ZERO Value)");

            long iNumerator=frac1.Denominator;
            long iDenominator=frac1.Numerator;
            return ( new Fraction(iNumerator, iDenominator));
        }   


        /// <summary>
        /// Operators for the Fraction object
        /// includes -(unary), and binary opertors such as +,-,*,/
        /// also includes relational and logical operators such as ==,!=,<,>,<=,>=
        /// </summary>
        public static Fraction operator -(Fraction frac1)
        {   return ( Negate(frac1) );   }

        public static Fraction operator +(Fraction frac1, Fraction frac2)
        {   return ( Add(frac1 , frac2) );  }

        public static Fraction operator +(int iNo, Fraction frac1)
        {   return ( Add(frac1 , new Fraction(iNo) ) ); }

        public static Fraction operator +(Fraction frac1, int iNo)
        {   return ( Add(frac1 , new Fraction(iNo) ) ); }

        public static Fraction operator +(double dbl, Fraction frac1)
        {   return ( Add(frac1 , Fraction.ToFraction(dbl) ) );  }

        public static Fraction operator +(Fraction frac1, double dbl)
        {   return ( Add(frac1 , Fraction.ToFraction(dbl) ) );  }

        public static Fraction operator -(Fraction frac1, Fraction frac2)
        {   return ( Add(frac1 , -frac2) ); }

        public static Fraction operator -(int iNo, Fraction frac1)
        {   return ( Add(-frac1 , new Fraction(iNo) ) );    }

        public static Fraction operator -(Fraction frac1, int iNo)
        {   return ( Add(frac1 , -(new Fraction(iNo)) ) );  }

        public static Fraction operator -(double dbl, Fraction frac1)
        {   return ( Add(-frac1 , Fraction.ToFraction(dbl) ) ); }

        public static Fraction operator -(Fraction frac1, double dbl)
        {   return ( Add(frac1 , -Fraction.ToFraction(dbl) ) ); }

        public static Fraction operator *(Fraction frac1, Fraction frac2)
        {   return ( Multiply(frac1 , frac2) ); }

        public static Fraction operator *(int iNo, Fraction frac1)
        {   return ( Multiply(frac1 , new Fraction(iNo) ) );    }

        public static Fraction operator *(Fraction frac1, int iNo)
        {   return ( Multiply(frac1 , new Fraction(iNo) ) );    }

        public static Fraction operator *(double dbl, Fraction frac1)
        {   return ( Multiply(frac1 , Fraction.ToFraction(dbl) ) ); }

        public static Fraction operator *(Fraction frac1, double dbl)
        {   return ( Multiply(frac1 , Fraction.ToFraction(dbl) ) ); }

        public static Fraction operator /(Fraction frac1, Fraction frac2)
        {   return ( Multiply( frac1 , Inverse(frac2) ) );  }

        public static Fraction operator /(int iNo, Fraction frac1)
        {   return ( Multiply( Inverse(frac1) , new Fraction(iNo) ) );  }

        public static Fraction operator /(Fraction frac1, int iNo)
        {   return ( Multiply( frac1 , Inverse(new Fraction(iNo)) ) );  }

        public static Fraction operator /(double dbl, Fraction frac1)
        {   return ( Multiply( Inverse(frac1) , Fraction.ToFraction(dbl) ) );   }

        public static Fraction operator /(Fraction frac1, double dbl)
        {   return ( Multiply( frac1 , Fraction.Inverse( Fraction.ToFraction(dbl) ) ) );    }

        public static bool operator ==(Fraction frac1, Fraction frac2)
        {   return frac1.Equals(frac2);     }

        public static bool operator !=(Fraction frac1, Fraction frac2)
        {   return ( !frac1.Equals(frac2) );    }

        public static bool operator ==(Fraction frac1, int iNo)
        {   return frac1.Equals( new Fraction(iNo));    }

        public static bool operator !=(Fraction frac1, int iNo)
        {   return ( !frac1.Equals( new Fraction(iNo)) );   }

        public static bool operator ==(Fraction frac1, double dbl)
        {   return frac1.Equals( new Fraction(dbl));    }

        public static bool operator !=(Fraction frac1, double dbl)
        {   return ( !frac1.Equals( new Fraction(dbl)) );   }

        public static bool operator<(Fraction frac1, Fraction frac2)
        {   return frac1.Numerator * frac2.Denominator < frac2.Numerator * frac1.Denominator;   }

        public static bool operator>(Fraction frac1, Fraction frac2)
        {   return frac1.Numerator * frac2.Denominator > frac2.Numerator * frac1.Denominator;   }

        public static bool operator<=(Fraction frac1, Fraction frac2)
        {   return frac1.Numerator * frac2.Denominator <= frac2.Numerator * frac1.Denominator;  }

        public static bool operator>=(Fraction frac1, Fraction frac2)
        {   return frac1.Numerator * frac2.Denominator >= frac2.Numerator * frac1.Denominator;  }


        /// <summary>
        /// overloaed user defined conversions: from numeric data types to Fractions
        /// </summary>
        public static implicit operator Fraction(long lNo)
        {   return new Fraction(lNo);   }
        public static implicit operator Fraction(double dNo)
        {   return new Fraction(dNo);   }
        public static implicit operator Fraction(string strNo)
        {   return new Fraction(strNo); }

        /// <summary>
        /// overloaed user defined conversions: from fractions to double and string
        /// </summary>
        public static explicit operator double(Fraction frac)
        {   return frac.ToDouble(); }

        public static implicit operator string(Fraction frac)
        {   return frac.ToString(); }

        /// <summary>
        /// checks whether two fractions are equal
        /// </summary>
        public override bool Equals(object obj)
        {
            Fraction frac=(Fraction)obj;
            return ( Numerator==frac.Numerator && Denominator==frac.Denominator);
        }

        /// <summary>
        /// returns a hash code for this fraction
        /// </summary>
        public override int GetHashCode()
        {
            return ( Convert.ToInt32((Numerator ^ Denominator) & 0xFFFFFFFF) ) ;
        }

        /// <summary>
        /// internal function for negation
        /// </summary>
        private static Fraction Negate(Fraction frac1)
        {
            long iNumerator=-frac1.Numerator;
            long iDenominator=frac1.Denominator;
            return ( new Fraction(iNumerator, iDenominator) );

        }   

        /// <summary>
        /// internal functions for binary operations
        /// </summary>
        private static Fraction Add(Fraction frac1, Fraction frac2)
        {
            try
            {
                checked
                {
                    long iNumerator=frac1.Numerator*frac2.Denominator + frac2.Numerator*frac1.Denominator;
                    long iDenominator=frac1.Denominator*frac2.Denominator;
                    return ( new Fraction(iNumerator, iDenominator) );
                }
            }
            catch(OverflowException)
            {
                throw new FractionException("Overflow occurred while performing arithemetic operation");
            }
            catch(Exception)
            {
                throw new FractionException("An error occurred while performing arithemetic operation");
            }
        }

        private static Fraction Multiply(Fraction frac1, Fraction frac2)
        {
            try
            {
                checked
                {
                    long iNumerator=frac1.Numerator*frac2.Numerator;
                    long iDenominator=frac1.Denominator*frac2.Denominator;
                    return ( new Fraction(iNumerator, iDenominator) );
                }
            }
            catch(OverflowException)
            {
                throw new FractionException("Overflow occurred while performing arithemetic operation");
            }
            catch(Exception)
            {
                throw new FractionException("An error occurred while performing arithemetic operation");
            }
        }

        /// <summary>
        /// The function returns GCD of two numbers (used for reducing a Fraction)
        /// </summary>
        private static long GCD(long iNo1, long iNo2)
        {
            // take absolute values
            if (iNo1 < 0) iNo1 = -iNo1;
            if (iNo2 < 0) iNo2 = -iNo2;

            do
            {
                if (iNo1 < iNo2)
                {
                    long tmp = iNo1;  // swap the two operands
                    iNo1 = iNo2;
                    iNo2 = tmp;
                }
                iNo1 = iNo1 % iNo2;
            } while (iNo1 != 0);
            return iNo2;
        }

        /// <summary>
        /// The function reduces(simplifies) a Fraction object by dividing both its numerator 
        /// and denominator by their GCD
        /// </summary>
        public static void ReduceFraction(Fraction frac)
        {
            try
            {
                if (frac.Numerator==0)
                {
                    frac.Denominator=1;
                    return;
                }

                long iGCD=GCD(frac.Numerator, frac.Denominator);
                frac.Numerator/=iGCD;
                frac.Denominator/=iGCD;

                if ( frac.Denominator<0 )   // if -ve sign in denominator
                {
                    //pass -ve sign to numerator
                    frac.Numerator*=-1;
                    frac.Denominator*=-1;   
                }
            } // end try
            catch(Exception exp)
            {
                throw new FractionException("Cannot reduce Fraction: " + exp.Message);
            }
        }

    }   //end class Fraction


    /// <summary>
    /// Exception class for Fraction, derived from System.Exception
    /// </summary>
    public class FractionException : Exception
    {
        public FractionException() : base()
        {}

        public FractionException(string Message) : base(Message)
        {}

        public FractionException(string Message, Exception InnerException) : base(Message, InnerException)
        {}
    }   //end class FractionException


}   //end namespace Mehroz

As @Tillito points out in comment, I double checked with the following codes:

using System.IO;
using System;
using Mehroz;

class Program
{
    static void Main()
    {
        double d = .5;
        string str = new Fraction(d).ToString();

        Console.WriteLine(str);
    }
}

which outputs:

1/2

Haldeman answered 27/9, 2011 at 6:13 Comment(5)
Didn't work for me: double d=.5; string str = new fraction(d).ToString(); always throws an exception. (Value cannot be converted).Jeminah
not sure if you're having a typo or other issues, but fraction() is not the same as Fraction(). See my updated answer. The class has no problem on your code (except on the capital letter)Haldeman
For 1.333333 it outputs 1333333333/1000000000 instead of 1 1/3Reflective
I just wanted to add that I had to adjust the Class to do what I want. Probably because I live in Germany and we use "9,25" instead of "9.25", for some odd reason this was passed on to that function as well and kept on throwing exceptions. Adding the second part to "while (strTemp[i] != '.' && strTemp[i] != ',')" fixed itNickerson
Instead of using replace, you should use built-in Germany locale (available for other countries as well), see thisHaldeman
T
1

Put the code that will follow into a static class to create an extension then use like:

var number = 2.83;
var result = number.ToFractions(4);

expected result: "2 3/4"

Code:

public static string ToFractions(this double number, int precision = 4)
{
    int w, n, d;
    RoundToMixedFraction(number, precision, out w, out n, out d);
    var ret = $"{w}";
    if (w > 0)
    {
        if (n > 0)
            ret = $"{w} {n}/{d}";
    }
    else
    {
        if (n > 0)
            ret = $"{n}/{d}";
    }
    return ret;
}

static void RoundToMixedFraction(double input, int accuracy, out int whole, out int numerator, out int denominator)
{
    double dblAccuracy = (double)accuracy;
    whole = (int)(Math.Truncate(input));
    var fraction = Math.Abs(input - whole);
    if (fraction == 0)
    {
        numerator = 0;
        denominator = 1;
        return;
    }
    var n = Enumerable.Range(0, accuracy + 1).SkipWhile(e => (e / dblAccuracy) < fraction).First();
    var hi = n / dblAccuracy;
    var lo = (n - 1) / dblAccuracy;
    if ((fraction - lo) < (hi - fraction)) n--;
    if (n == accuracy)
    {
        whole++;
        numerator = 0;
        denominator = 1;
        return;
    }
    var gcd = GCD(n, accuracy);
    numerator = n / gcd;
    denominator = accuracy / gcd;
}

static int GCD(int a, int b)
{
    if (b == 0) return a;
    else return GCD(b, a % b);
}
Typography answered 21/10, 2018 at 7:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.