Results 1 to 8 of 8

Thread: [VB.NET] Decimal to Fraction Conversion

  1. #1

    Thread Starter
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    [VB.NET] Decimal to Fraction Conversion

    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:
    1. Function dec2frac(ByVal dblDecimal As Double) As String
    2.         '
    3.         '   Excel function to convert decimal values to integer fractions.
    4.         '
    5.         '   Original Written by:     Erik Oosterwal
    6.         '   Converted to .NET by:     Chris Anderson
    7.         '   Started on:     November 16, 2006
    8.         '   Completed on:   November 16, 2006
    9.         '   Converted on:   February 25, 2007
    10.         '
    11.  
    12.         Dim intNumerator, intDenominator, intNegative As Integer
    13.         ' Declare integer variables
    14.         Dim dblFraction, dblAccuracy As Double
    15.         ' Declare floating point variables as double precision.
    16.         Dim txtDecimal As String
    17.         ' need a string representation of the input value
    18.         ' in order to determine the required accuracy.
    19.  
    20.         ' Find the accuracy needed for the output by checking the number of digits behind the decimal point
    21.         '   of the input value.
    22.         '
    23.         '    dblAccuracy = 1 / 10 ^ (Len(CStr(dblDecimal - Fix(dblDecimal))) - 2)
    24.         '
    25.         '   While the formula above should work, there is a serious error in the way Excel handles
    26.         '   decimal numbers and there's a huge rounding error issue.  Subtracting the int() of
    27.         '   12.1 from 12.1 produces 0.0999999999 or something similar.  Obviously that won't
    28.         '   work for our desired accuracy of the magnitude of the fractional part of the number
    29.         '   so a slower more cumbersome method has to be used...
    30.  
    31.         dblAccuracy = 0.1                                       ' Set the initial Accuracy level.
    32.         txtDecimal = dblDecimal.ToString                        ' Get a  string representation of the input number.
    33.  
    34.         For i As Integer = 0 To (txtDecimal.Length - 1)                                 ' Check each character to see if it's a decimal point...
    35.             If txtDecimal.Substring(i, 1) = "." Then                    ' if it is then we get the number of digits behind the decimal
    36.                 dblAccuracy = 1 / 10 ^ (txtDecimal.Length - i)    '   assign the new accuracy level, and
    37.                 Exit For                                            '   exit the for loop.
    38.             End If
    39.         Next
    40.  
    41.         intNumerator = 0                                ' Set the initial numerator value to 0.
    42.         intDenominator = 1                              ' Set the initial denominator value to 1.
    43.         intNegative = 1                                 ' Set the negative value flag to positive.
    44.  
    45.         If dblDecimal < 0 Then
    46.             intNegative = -1 ' If the desired decimal value is negative,
    47.             '   then set the negative value flag to
    48.             '   negative.
    49.         End If
    50.  
    51.         dblFraction = 0                                 ' Set the fraction value to be 0/1.
    52.  
    53.         Do While Math.Abs(dblFraction - dblDecimal) > dblAccuracy   ' As long as we're still outside the
    54.             '   desired accuracy, then...
    55.             If Math.Abs(dblFraction) > Math.Abs(dblDecimal) Then      ' If our fraction is too big,
    56.                 intDenominator += 1         '   increase the denominator
    57.             Else                                            ' Otherwise
    58.                 intNumerator += intNegative   '   increase the numerator.
    59.             End If
    60.  
    61.             dblFraction = intNumerator / intDenominator     ' Set the new value of the fraction.
    62.  
    63.         Loop
    64.  
    65.         Return intNumerator.ToString & "/" & intDenominator.ToString ' Display the numerator and denominator
    66.     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
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  2. #2
    Hyperactive Member Troy Lundin's Avatar
    Join Date
    May 2006
    Posts
    489

    Re: [VB.NET] Decimal to Fraction Conversion

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

    Code:
        ''' <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
    Prefix has no suffix, but suffix has a prefix.

  3. #3
    New Member
    Join Date
    May 2008
    Posts
    2

    Re: [VB.NET] Decimal to Fraction Conversion

    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?

  4. #4

    Thread Starter
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: [VB.NET] Decimal to Fraction Conversion

    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
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  5. #5
    New Member
    Join Date
    May 2008
    Posts
    2

    Re: [VB.NET] Decimal to Fraction Conversion

    Quote Originally Posted by 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
    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.

  6. #6

    Thread Starter
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: [VB.NET] Decimal to Fraction Conversion

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

    Code:
    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
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  7. #7
    PowerPoster JuggaloBrotha's Avatar
    Join Date
    Sep 2005
    Location
    Lansing, MI; USA
    Posts
    4,286

    Re: [VB.NET] Decimal to Fraction Conversion

    Quote Originally Posted by Troy Lundin View Post
    A better way to go is to use the Euclidean Algorithm to find the gcd.
    After finding the gcd, the rest is simple.

    Code:
        ''' <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
    This doesn't always work, when I use this:
    Code:
    GetFraction(1.5R)
    I get:
    Code:
    2 1/2
    Just thought I'd mention it
    Currently using VS 2015 Enterprise on Win10 Enterprise x64.

    CodeBank: All ThreadsColors ComboBoxFading & Gradient FormMoveItemListBox/MoveItemListViewMultilineListBoxMenuButtonToolStripCheckBoxStart with Windows

  8. #8
    New Member
    Join Date
    Nov 2010
    Posts
    1

    Re: [VB.NET] Decimal to Fraction Conversion

    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).
    Code:
        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

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width