Click here to Skip to main content
11,644,286 members (71,291 online)
Click here to Skip to main content

Convert Decimal to Fraction and Vice Versa in C#

, 20 Jul 2013 CPOL 15.9K 8
Rate this:
Please Sign up or sign in to vote.
Class for converting decimals and fractions (allows rounding to a decimal also)

Introduction

Recently, I was challenged with writing a report to generate a quote for an engineering specification. One of the requirements for this report was to convert decimals to fractions, and vice versa. It was also required to round the fractions to the nearest 1/16 of an inch.

Background

I had run several internet searches to help me solve these issues and turned up some interesting stuff, but nothing to "do it all." So I combined what I found out there into one class, made some modifications, used it in my report, then decided to share this with my comrades here on CodeProject. My hope is that this class can be utilized, expanded upon, and / or optimized by the community.

Using the Code

I used Visual Studio to compile and run the class. Writing a test app to use this class should be simple enough.  If not, let me know and I'll push something up here.

Notes

  • I default the fractions to round to 1/16 as this was the requirement for the report. You can skip rounding all together by not passing in the last two parameters into the "Convert" function returning the string (fraction) value.
  • I wrote a handy little formatter for feet and inches that might help someone too (another requirement for the report I had to write).
    public static class FractionConverter
    {
        public static string Convert(decimal pvalue, 
        bool skip_rounding = false, decimal dplaces = (decimal)0.0625)
        {
            decimal value = pvalue;

            if (!skip_rounding)
                value = FractionConverter.DecimalRound(pvalue, dplaces);

            if (value == Math.Round(value, 0)) // whole number check
                return value.ToString();

            // get the whole value of the fraction
            decimal mWhole = Math.Truncate(value);

            // get the fractional value
            decimal mFraction = value - mWhole;

            // initialize a numerator and denomintar
            uint mNumerator = 0;
            uint mDenomenator = 1;

            // ensure that there is actual a fraction
            if (mFraction > 0m)
            {
                // convert the value to a string so that 
                // you can count the number of decimal places there are
                string strFraction = mFraction.ToString().Remove(0, 2);

                // store the number of decimal places
                uint intFractLength = (uint)strFraction.Length;

                // set the numerator to have the proper amount of zeros
                mNumerator = (uint)Math.Pow(10, intFractLength);

                // parse the fraction value to an integer that equals 
                // [fraction value] * 10^[number of decimal places]
                uint.TryParse(strFraction, out mDenomenator);

                // get the greatest common divisor for both numbers
                uint gcd = GreatestCommonDivisor(mDenomenator, mNumerator);

                // divide the numerator and the denominator by the greatest common divisor
                mNumerator = mNumerator / gcd;
                mDenomenator = mDenomenator / gcd;
            }

            // create a string builder
            StringBuilder mBuilder = new StringBuilder();

            // add the whole number if it's greater than 0
            if (mWhole > 0m)
            {
                mBuilder.Append(mWhole);
            }

            // add the fraction if it's greater than 0m
            if (mFraction > 0m)
            {
                if (mBuilder.Length > 0)
                {
                    mBuilder.Append(" ");
                }

                mBuilder.Append(mDenomenator);
                mBuilder.Append("/");
                mBuilder.Append(mNumerator);
            }

            return mBuilder.ToString();
        }

        // Converts fraction to decimal. 
        // There are two formats a fraction greater than 1 can consist of
        // which this function will work for:
        //  Example: 4-1/2 or 4 1/2
        // Fractions less than 1 are in the format of 1/2, etc..
        public static decimal Convert(string value)
        {
            string[] dparse;
            string[] fparse;
            string whole = "0";
            string dec = "";
            decimal dReturn = 0;

            // check for '-' or ' ' separator between whole number and fraction
            dparse = value.Contains('-') ? value.Split('-') : value.Split(' ');
            int pcount = dparse.Count();

            // fraction greater than one.
            if (pcount == 2)
            {
                whole = dparse[0];
                dec = dparse[1];
            }
            // whole number or fraction less than 1.
            else if (pcount == 1)
                dec = dparse[0];

            // split out fractional part of value passed in.
            fparse = dec.Split('/');

            // check for fraction.
            if (fparse.Count() == 2)
            {
                try
                {
                    decimal d0 = System.Convert.ToDecimal(fparse[0]); // convert numerator
                    decimal d1 = System.Convert.ToDecimal(fparse[1]); // convert denominator
                    dReturn = d0 / d1; // divide the fraction (converts to decimal)
                    decimal dWhole = System.Convert.ToDecimal(whole); // convert 
                    				// whole number part to decimal.

                    dReturn = dWhole + dReturn; // add whole number 
                    			// and fractional part and we're done.
                }
                catch (Exception e)
                {
                    dReturn = 0;
                }
            }
            else
            // there is no fractional part of the input.
            {
                try
                {
                    dReturn = System.Convert.ToDecimal(whole + dec);
                }
                catch (Exception e)
                {
                    // bad input so return 0.
                    dReturn = 0;
                }
            }

            return dReturn;
        }

        private static uint GreatestCommonDivisor(uint valA, uint valB)
        {
            // return 0 if both values are 0 (no GSD)
            if (valA == 0 &&
              valB == 0)
            {
                return 0;
            }
            // return value b if only a == 0
            else if (valA == 0 &&
                  valB != 0)
            {
                return valB;
            }
            // return value a if only b == 0
            else if (valA != 0 && valB == 0)
            {
                return valA;
            }
            // actually find the GSD
            else
            {
                uint first = valA;
                uint second = valB;

                while (first != second)
                {
                    if (first > second)
                    {
                        first = first - second;
                    }
                    else
                    {
                        second = second - first;
                    }
                }

                return first;
            }

        }

        // Converts a value to feet and inches.
        // Examples:
        //  12.1667 converts to 12' 2"
        //  4 converts to 4'
        //  0.1667 converts to 2"
        public static bool ReformatForFeetAndInches
        	(ref string line_type, bool zero_for_blank = true)
        {
            if (string.IsNullOrEmpty(line_type))
            {
                if (zero_for_blank)
                    line_type = "0'";
                return true;
            }

            decimal d = System.Convert.ToDecimal(line_type);
            decimal d1 = Math.Floor(d);
            decimal d2 = d - d1;
            d2 = Math.Round(d2 * 12, 2);

            string s1;
            string s2;

            s1 = d1 == 0 ? "" : d1.ToString() + "'";
            s2 = d2 == 0 ? "" : FractionConverter.Convert(d2) + @"""";

            line_type = string.Format(@"{0} {1}", s1, s2).Trim();

            if (string.IsNullOrEmpty(line_type))
            {
                if (zero_for_blank)
                    line_type = "0'";
                return true;
            }

            return true;
        }

        // Rounds a number to the nearest decimal.
        // For instance, carpenters do not want to see a number like 4/5.  
        // That means nothing to them
        // and you'll have an angry carpenter on your hands 
        // if you ask them cut a 2x4 to 36 and 4/5 inches.
        // So, we would want to convert to the nearest 1/16 of an inch.
        // Example: DecimalRound(0.8, 0.0625) Rounds 4/5 to 13/16 or 0.8125.
        private static decimal DecimalRound(decimal val, decimal places)
        {
            string sPlaces = FractionConverter.Convert(places, true);
            string[] s = sPlaces.Split('/');

            if (s.Count() == 2)
            {
                int nPlaces = System.Convert.ToInt32(s[1]);
                decimal d = Math.Round(val*nPlaces);
                return  d / nPlaces;
            }

            return val;
        }
    }

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Patrick Harris
Software Developer (Senior) Sukup Manufacturing Co.
United States United States
I've been a software developer for over 25 years. I've worked on commercial grade Point of Sale and Order Entry software applications. I've done extensive research in database development and have learned techniques which have enabled me to tackle database problems particularly in relation to optimizing slowness by thinking outside the box (the box being the database engine's query optimizer).

I've worked with Symbol Technology Handheld barcode scanners quite a bit. I've written Sqllite libraries that run on these devices which have greatly increased local storage capabilities.

Currently I have migrated away from local application development and am now developing client/server solutions in ASP.NET. I am, at the moment, learning MVC, MVP, and MVVM design patterns.

You may also be interested in...

Comments and Discussions

 
QuestionTest App for FractionConverter Pin
nbrooks11-Aug-13 5:12
membernbrooks11-Aug-13 5:12 
GeneralMy vote of 2 Pin
Philippe Mori19-Jul-13 13:03
memberPhilippe Mori19-Jul-13 13:03 
GeneralRe: My vote of 2 Pin
Patrick Harris19-Jul-13 15:28
memberPatrick Harris19-Jul-13 15:28 
GeneralRe: My vote of 2 Pin
Garth J Lancaster19-Jul-13 17:49
memberGarth J Lancaster19-Jul-13 17:49 
GeneralRe: My vote of 2 Pin
Patrick Harris20-Jul-13 5:45
memberPatrick Harris20-Jul-13 5:45 
GeneralRe: My vote of 2 Pin
Garth J Lancaster20-Jul-13 19:43
memberGarth J Lancaster20-Jul-13 19:43 
GeneralRe: My vote of 2 Pin
Patrick Harris20-Jul-13 21:35
memberPatrick Harris20-Jul-13 21:35 
GeneralRe: My vote of 2 Pin
Philippe Mori23-Jul-13 14:31
memberPhilippe Mori23-Jul-13 14:31 
GeneralRe: My vote of 2 Pin
Patrick Harris24-Jul-13 4:18
memberPatrick Harris24-Jul-13 4:18 
GeneralRe: My vote of 2 Pin
Philippe Mori24-Jul-13 4:48
memberPhilippe Mori24-Jul-13 4:48 
GeneralRe: My vote of 2 Pin
Patrick Harris24-Jul-13 5:10
memberPatrick Harris24-Jul-13 5:10 
GeneralRe: My vote of 2 Pin
Philippe Mori24-Jul-13 5:38
memberPhilippe Mori24-Jul-13 5:38 
GeneralRe: My vote of 2 Pin
Patrick Harris24-Jul-13 6:05
memberPatrick Harris24-Jul-13 6:05 
GeneralRe: My vote of 2 Pin
Philippe Mori24-Jul-13 6:21
memberPhilippe Mori24-Jul-13 6:21 
GeneralRe: My vote of 2 Pin
Patrick Harris24-Jul-13 8:25
memberPatrick Harris24-Jul-13 8:25 
GeneralRe: My vote of 2 Pin
Philippe Mori24-Jul-13 8:31
memberPhilippe Mori24-Jul-13 8:31 
GeneralRe: My vote of 2 Pin
Patrick Harris24-Jul-13 8:36
memberPatrick Harris24-Jul-13 8:36 
GeneralRe: My vote of 2 Pin
Philippe Mori24-Jul-13 9:09
memberPhilippe Mori24-Jul-13 9:09 
GeneralRe: My vote of 2 Pin
Patrick Harris25-Jul-13 3:49
memberPatrick Harris25-Jul-13 3:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150731.1 | Last Updated 20 Jul 2013
Article Copyright 2013 by Patrick Harris
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid