(Print this page)

Get Fractions from a decimal value
Published date: Sunday, April 28, 2013
On: Moer and Éric Moreau's web site

This month, I am providing a handy method for whomever needs to transform a decimal value in a fraction representation. I have been required to do this in the past few months on a report. For example 1.25 needed to be read as 1 1/4.

This month demo code

The code of this month demo is provided both in VB and C#. The solution was created using Visual Studio 2012 but the same code can be reused in older version as well.

The UI

You can’t really have a simpler user interface. Two textboxes to let the user (you) provide the decimal value and the denominator and a listbox to show the results.

Figure 1: The demo application in action

Notice that when you run the application, the listbox will automatically be populated with a couple of values I used for testing.

The MakeFraction method

The real value of this article is in that method. Don’t look for something else, it is all in there!

According to the second argument of the method (pLargestDenominator), the GCD (Greatest Common Denominator is found) and the fraction is created based on it (more about this argument here below).

The method reads like this:

Private Function MakeFraction(ByVal pDecimalNumber As Decimal,
                              Optional ByVal pLargestDenominator As Integer = 64) As String
    Dim intGCD As Integer
    Dim intTopNumber As Integer
    Dim intRemainder As Integer
    Dim intWholeNumber As Integer
    Dim intNumerator As Integer
    Dim intDenominator As Integer

    Dim blnIsNegative As Boolean = (pDecimalNumber < 0)
    pDecimalNumber = Math.Abs(pDecimalNumber)

    intWholeNumber = Convert.ToInt32(Fix(pDecimalNumber))
    intDenominator = pLargestDenominator
    If (pDecimalNumber - intWholeNumber) = 0 Then
        Return If(blnIsNegative, "-", "") + intWholeNumber.ToString()
    Else
        intNumerator = Convert.ToInt32(intDenominator * Math.Abs(pDecimalNumber - intWholeNumber))

        If intNumerator <> 0 Then
            intGCD = pLargestDenominator
            intTopNumber = intNumerator

            Do
                intRemainder = (intGCD Mod intTopNumber)
                intGCD = intTopNumber
                intTopNumber = intRemainder
            Loop Until intRemainder = 0

            intNumerator = intNumerator \ intGCD
            intDenominator = intDenominator \ intGCD

            If intDenominator = 1 Then
                Return If(blnIsNegative, "-", "") + (intWholeNumber + 1).ToString()
            Else
                Return If(blnIsNegative, "-", "") + intWholeNumber.ToString() +
                    " " +
                    intNumerator.ToString() +
                    "/" +
                    intDenominator.ToString()
            End If
        End If
    End If
End Function

The Largest Denominator argument

You need to be aware of the kind of data that you are handling.

For example, if you are dealing with weight in pounds, you better set the Largest Denominator parameter to 16 (since there are 16 ounces in a pound). If you are dealing with dollar, this parameter would make sense with a value of 100. If you are dealing with pizzas that you cut in 8 slices, guess what the perfect value would be? I’ll give you a hint, a value between 7 and 9!

Setting this argument to a value that doesn’t match the domain of values will return you a value (the closest one) based on the provided denominator but it won’t be THE exact fraction.

Interesting conversion facts

While I was converting the solution from my original VB code to C#, I found 2 interesting conversion tips.

The first one is about the well know VB Fix method. This method returns the integer portion of a number. It doesn’t round the number and it also behaves correctly with negative numbers. This method is part of the Microsoft Visual Basic component because it comes from the VB pre .Net era (it is legacy). While C# developers can add a reference to that component without a problem and (ab)use it, there is another way. Apparently, the simple fact of casting the number to an integer is enough (i.e.: (int)myDecimalValue).

The second conversion tip is about the \ operator which is only available to VB programmers. It divides two numbers and returns an integer result whatever data types the two number have. In C#, you can use the regular / operator and as long as both numbers are already integers, the returned result will also be an integer.

Conclusion

If you know what kind of data you are dealing with and want to see fractions instead of decimal values, this little method is for you.


(Print this page)