# VBForums CodeBank > CodeBank - Visual Basic .NET >  [VB.NET] Decimal to Fraction Conversion

## techgnome

I recently needed a way to convert decimal values into their fraction counterparts. A search on Google turned up this little gem: http://www.geocities.com/oosterwal/c...onversion.html originally written for VBA/VB6. Naturally I'm working in .NET, so I converted the code to VB.NET.


VB Code:
Function dec2frac(ByVal dblDecimal As Double) As String
        '
        '   Excel function to convert decimal values to integer fractions.
        '
        '   Original Written by:     Erik Oosterwal
        '   Converted to .NET by:     Chris Anderson
        '   Started on:     November 16, 2006
        '   Completed on:   November 16, 2006
        '   Converted on:   February 25, 2007
        '
         Dim intNumerator, intDenominator, intNegative As Integer
        ' Declare integer variables 
        Dim dblFraction, dblAccuracy As Double
        ' Declare floating point variables as double precision.
        Dim txtDecimal As String
        ' need a string representation of the input value
        ' in order to determine the required accuracy.
         ' Find the accuracy needed for the output by checking the number of digits behind the decimal point
        '   of the input value.
        '
        '    dblAccuracy = 1 / 10 ^ (Len(CStr(dblDecimal - Fix(dblDecimal))) - 2)
        '
        '   While the formula above should work, there is a serious error in the way Excel handles
        '   decimal numbers and there's a huge rounding error issue.  Subtracting the int() of
        '   12.1 from 12.1 produces 0.0999999999 or something similar.  Obviously that won't
        '   work for our desired accuracy of the magnitude of the fractional part of the number
        '   so a slower more cumbersome method has to be used...
         dblAccuracy = 0.1                                       ' Set the initial Accuracy level.
        txtDecimal = dblDecimal.ToString                        ' Get a  string representation of the input number.
         For i As Integer = 0 To (txtDecimal.Length - 1)                                 ' Check each character to see if it's a decimal point...
            If txtDecimal.Substring(i, 1) = "." Then                    ' if it is then we get the number of digits behind the decimal
                dblAccuracy = 1 / 10 ^ (txtDecimal.Length - i)    '   assign the new accuracy level, and
                Exit For                                            '   exit the for loop.
            End If
        Next
         intNumerator = 0                                ' Set the initial numerator value to 0.
        intDenominator = 1                              ' Set the initial denominator value to 1.
        intNegative = 1                                 ' Set the negative value flag to positive.
         If dblDecimal < 0 Then
            intNegative = -1 ' If the desired decimal value is negative,
            '   then set the negative value flag to
            '   negative.
        End If
         dblFraction = 0                                 ' Set the fraction value to be 0/1.
         Do While Math.Abs(dblFraction - dblDecimal) > dblAccuracy   ' As long as we're still outside the
            '   desired accuracy, then...
            If Math.Abs(dblFraction) > Math.Abs(dblDecimal) Then      ' If our fraction is too big,
                intDenominator += 1         '   increase the denominator
            Else                                            ' Otherwise
                intNumerator += intNegative   '   increase the numerator.
            End If
             dblFraction = intNumerator / intDenominator     ' Set the new value of the fraction.
         Loop
         Return intNumerator.ToString & "/" & intDenominator.ToString ' Display the numerator and denominator
    End Function

It's not the prettiest, and it could probably be written a little more streamlined, but it does work. If anyone has any suggestions for improvement, please do.

-tg

----------


## Troy Lundin

A better way to go is to use the Euclidean Algorithm to find the gcd.
After finding the gcd, the rest is simple.



```
    ''' <summary>
    ''' Return a fraction string from a double.
    ''' </summary>
    ''' <param name="d">The double to convert.</param>
    ''' <returns>The converted string.</returns>
    ''' <remarks>Code written by Troy Lundin on May 3, 2007</remarks>
    Function GetFraction(ByVal d As Double) As String
        ' Get the initial denominator: 1 * (10 ^ decimal portion length)
        Dim Denom As Int32 = CInt(1 * (10 ^ tb1.Text.Split("."c)(1).Length))

        ' Get the initial numerator: integer portion of the number
        Dim Numer As Int32 = CInt(tb1.Text.Split("."c)(1))

        ' Use the Euclidean algorithm to find the gcd
        Dim a As Int32 = Numer
        Dim b As Int32 = Denom
        Dim t As Int32 = 0 ' t is a value holder

        ' Euclidean algorithm
        While b <> 0
            t = b
            b = a Mod b
            a = t
        End While

        ' Return our answer
        Return CInt(d) & " " & (Numer / a) & "/" & (Denom / a)
    End Function
```

----------


## merlin666

I have tried the first VBA code and it crashes Excel with numbers such as 0.001589546.  I suspect it hangs in the accuracy verification part. I also tried the Euclidean GCD approach but I am not sure if Excel VBA understands tb1.Text.Split. Can this be converted to VBA for Excel?

----------


## techgnome

Did you try the code I posted, or the code that was on the page I linked to? The code I posted was for .NET, NOT VBA..... the original code was a module function written in Excel, so I can only imagine that it woks, but to what degree, I don't know. I only needed to go 4 places, so didn't check beyond that as to its accuracy.

-tg

----------


## merlin666

> Did you try the code I posted, or the code that was on the page I linked to? The code I posted was for .NET, NOT VBA..... the original code was a module function written in Excel, so I can only imagine that it woks, but to what degree, I don't know. I only needed to go 4 places, so didn't check beyond that as to its accuracy.
> 
> -tg


Thanks, I used the initial code from:
http://www.geocities.com/oosterwal/c...onversion.html
that is hanging in Excel.


I may try to reduce the number of digits, but was also intrigued by the Euclidean approach. Unfortunately, my VB skills are less than basic and this was the only example in VBA that I could find.

----------


## techgnome

I think this should work (converted the Euclidean method above from .NET to VB6 (which should be close enough to VBA for you).



```
Function GetFraction(ByVal d As Double) As String
        ' Get the initial denominator: 1 * (10 ^ decimal portion length)
        Dim Denom As Long = CLng(1 * (10 ^ (Len(tb1.text) - Instr(tb1.Text, ".") -1))

        ' Get the initial numerator: integer portion of the number
        Dim Numer As Long = CLng(Mid(tb1.Text, instr(tb1.text, ".")))

        ' Use the Euclidean algorithm to find the gcd
        Dim a As Long = Numer
        Dim b As Long = Denom
        Dim t As Long = 0 ' t is a value holder

        ' Euclidean algorithm
        While b <> 0
            t = b
            b = a Mod b
            a = t
        End While

        ' Return our answer
        GetFraction = CSTR(CLng(d)) & " " & (Numer / a) & "/" & (Denom / a)
    End Function
```

I think that'll do it.

-tg

----------


## JuggaloBrotha

> A better way to go is to use the Euclidean Algorithm to find the gcd.
> After finding the gcd, the rest is simple.
> 
> 
> 
> ```
>     ''' <summary>
>     ''' Return a fraction string from a double.
>     ''' </summary>
> ...


This doesn't always work, when I use this:

```
GetFraction(1.5R)
```

I get:

```
2 1/2
```

Just thought I'd mention it

----------


## x_goal

> This doesn't always work, when I use this:
> 
> GetFraction(1.5R)
> 
> I get:
> 2 1/2
> 
> Just thought I'd mention it


This happens because the whole part of the number is get by CInt function: CInt(d)
So, if fractional part >= 0.5 then number is rounded to next integer...
The corrected code is bellow. I also replaced "tb1.Text" with "d.ToString" (I think, is appropriate for a function).


```
    Function GetFraction(ByVal d As Double) As String
        ' Get the initial denominator: 1 * (10 ^ decimal portion length)
        Dim Denom As Int32 = CInt(1 * (10 ^ d.ToString.Split("."c)(1).Length))

        ' Get the initial numerator: integer portion of the number
        Dim Numer As Int32 = CInt(d.ToString.Split("."c)(1))

        ' Use the Euclidean algorithm to find the gcd
        Dim a As Int32 = Numer
        Dim b As Int32 = Denom
        Dim t As Int32 = 0 ' t is a value holder

        ' Euclidean algorithm
        While b <> 0
            t = b
            b = a Mod b
            a = t
        End While

        'Get whole part of the number
        Dim Whole As String = d.ToString.Split("."c)(0)

        ' Return our answer
        Return Whole & " " & (Numer / a) & "/" & (Denom / a)
    End Function
```

----------

