locked
accepting, then displaying fractions

    Question

  • I am currently working on a program for work that accepts fractional numbers from the user, and displays the result using the same format. Converting to decimal is the easy part. I need some input as to how I can convert back to a fraction using different resolutions(1/16, 1/32, 1/64...etc) based on how close the answer is to a list of decimal numbers. Thank you.
    Saturday, July 04, 2009 4:00 PM

Answers

  • I found a QBASIC program for converting decimal numbers to fractions.  I didn't write it, but I translated the code into something that will run inside a VB Console application.  Check this out to see if it works for you:


    Module Module1
    
        Sub Main()
    		'translated by Solitaire from QBasic code originally written by lawgin
    		Dim min, d1, p, dp, wp, m, x1, x2, dx, y, d2 As Double
    		Dim d As String
    		min = 10
    		Console.Write("Enter decimal:  ")
    		d = Console.ReadLine()
    		p = Len(d) - InStr(d, ".") + 1
    		d1 = Val(d)
    		wp = Int(d1)
    		dp = d1 - wp
    		Do
    			m = m + 1
    			x1 = m * dp
    			x2 = CLng(x1)
    			dx = Math.Abs(x1 - x2)
    			If dx < min Then
    				min = dx
    				y = m
    				d2 = (CLng(y * dp) + y * wp) / y
    			End If
    		Loop Until Math.Abs(d2 - d1) < 1 / 10 ^ p
    		Console.WriteLine(d1 & " = " & CLng(y * dp) + y * wp & "/" & y)
    		Console.ReadLine()
    	End Sub
    
    End Module

    Solitaire
    Sunday, July 05, 2009 2:55 AM
  • Saturday, July 04, 2009 5:00 PM
  • Saturday, July 04, 2009 5:12 PM
  • Hi Solitare 

    hmm... I get my code to work but in obviuse cases it does not show the value im expekt.... My lates attemt to create a own struct is shown below.... I have also implemented the transleted code from lawgin you provided... but I couldnt get it to work properly


    Public Structure Fractions
        Public pHoleNumber As Integer
        Public pDevicor As Integer
        Public pNummorator As Integer
    
        Public Sub New(ByVal HoleNumber As Integer, ByVal Nummorator As Integer, ByVal Devicor As Integer)
            pNummorator = Nummorator
            pHoleNumber = HoleNumber
            pDevicor = Devicor
        End Sub
    
        Public Sub New(ByVal Nummorator As Integer, ByVal Devicor As Integer)
            pNummorator = Nummorator
            pDevicor = Devicor
        End Sub
    
        Public Sub New(ByVal Desimal As Double, ByVal bool As Boolean)
            Dim result As New Fractions
            If bool = True Then
                Dim d As Double = Desimal
                result.HoleNumber = Math.Floor(d)
                Dim test As Double = d - CDbl(result.HoleNumber)
                For i As Integer = 1 To 1000
                    For j As Integer = 1 To 10000
                        If i / j = test Or i / j - test < Double.Epsilon Then
                            result.Nummorator = i
                            result.Devicor = j
                            Dim counter As Integer = 0
                            If result.Nummorator < result.Devicor Then
                                counter = result.Nummorator
                            Else
                                counter = result.Devicor
                            End If
    
                            For a = 2 To counter
                                If result.Nummorator Mod a = 0 Then
                                    If result.Devicor Mod a = 0 Then
                                        result.Nummorator /= a
                                        result.Devicor /= a
                                    End If
                                End If
                            Next
                            Exit For
                            Exit For
                        End If
                    Next
                Next
    
            Else
                'Solitare translation of lawgin code
                Dim min, d1, p, dp, wp, m, x1, x2, dx, y, d2 As Double
                Dim d As String
                min = 10
    
                d = Desimal
                p = Len(d) - InStr(d, ".") + 1
                d1 = Val(d)
                wp = Int(d1)
                dp = d1 - wp
                Do
                    m = m + 1
                    x1 = m * dp
                    x2 = CLng(x1)
                    dx = Math.Abs(x1 - x2)
                    If dx < min Then
                        min = dx
                        y = m
                        d2 = (CLng(y * dp) + y * wp) / y
                    End If
                Loop Until Math.Abs(d2 - d1) < 1 / 10 ^ p
    
                result.HoleNumber = CLng(y * dp)
                result.Nummorator = y * wp
                result.Devicor = y
            End If
    
            Me.HoleNumber = result.HoleNumber
            Me.Nummorator = result.Nummorator
            Me.Devicor = result.Devicor
        End Sub
    
        Public Property Nummorator() As Integer
            Get
                Return pNummorator
            End Get
            Set(ByVal value As Integer)
                pNummorator = value
            End Set
        End Property
    
        Public Property Devicor() As Integer
            Get
                Return pDevicor
            End Get
            Set(ByVal value As Integer)
                pDevicor = value
            End Set
        End Property
    
        Public Property HoleNumber() As Integer
            Get
                Return pHoleNumber
            End Get
            Set(ByVal value As Integer)
                pHoleNumber = value
            End Set
        End Property
    
        Public Overloads Overrides Function ToString() As String
            Return pHoleNumber & " " & pNummorator & "/" & pDevicor
        End Function
    
        ' Unary operators:
        Public Shared Operator +(ByVal c As Fractions) As Fractions
            Return c
        End Operator
    
        Public Shared Operator -(ByVal c As Fractions) As Fractions
            Return New Fractions(c.HoleNumber, c.Nummorator, c.Devicor)
        End Operator
    
        Public Overloads Shared Operator +(ByVal N1 As Fractions, ByVal N2 As Fractions) As Fractions
            Dim hole As Integer = N1.pHoleNumber + N2.pHoleNumber
            Dim commonDev As Integer = N1.pDevicor * N2.pDevicor
            Dim commonNum As Integer = N1.pNummorator * N2.pDevicor + N2.pNummorator * N1.pDevicor
    
            Dim n As Integer = Math.Floor(commonNum / commonDev)
            If n >= 1 Then
                hole += n
                commonNum -= n * commonDev
            End If
            Dim counter As Integer = 0
            If commonNum < commonDev Then
                counter = commonNum
            Else
                counter = commonDev
            End If
    
            For a = 2 To counter
                If commonNum Mod a = 0 Then
                    If commonDev Mod a = 0 Then
                        commonNum /= a
                        commonDev /= a
                    End If
                End If
            Next
    
    
            Dim result As New Fractions(hole, commonNum, commonDev)
            Return result
        End Operator
    End Structure
    Feel free to have a go at it... Here is a test example:

     TextBox6.Text = CDbl(TextBox4.Text) + CDbl(TextBox3.Text)
            Dim f As New Fractions(CDbl(TextBox3.Text), True)
            Dim ff As New Fractions(CDbl(TextBox4.Text), True)
            Dim g As New Fractions
            g = f + ff
            TextBox5.Text = g.ToString

    Kenneth
    Sunday, July 05, 2009 4:06 AM

All replies

  • It wont work... you have to round the numbers if you want to do this.... or youll have to calculate with fractions...
    but that implice that youll have to construct a class to do it for you... not impossible but much work... I dont know of any such class in .net libraries though

    Kenneth
    Saturday, July 04, 2009 4:49 PM
  • Saturday, July 04, 2009 5:00 PM
  • Saturday, July 04, 2009 5:12 PM
  • rick
      actually, this might work for you.
      when you put the fraction into the textbox, convert it to a decimal and store that value.
      then to convert back to a fraction, loop through the numbers until a match is made with the decimal from before.

      I tried this on a lot of numbers and it was correct on all of them. need a form with 1 textbox to input the fraction and 2 buttons - 1 to convert the fraction to a decimal and 1 to go back


    Dim testnum As Double
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    
            Dim dvnd As Double
            Dim dvsr As Double
    
            Dim strDvnd As String
            Dim strDvsr As String
            If TextBox1.TextLength > 2 AndAlso TextBox1.Text.Contains("/") Then
                strDvnd = TextBox1.Text.Substring(0, TextBox1.Text.IndexOf("/"))
                strDvsr = TextBox1.Text.Substring((TextBox1.Text.IndexOf("/") + 1))
            Else
                MessageBox.Show("You must enter a valid fraction")
                Exit Sub
            End If
    
            Double.TryParse(strDvnd, dvnd)
            Double.TryParse(strDvsr, dvsr)
            testnum = dvnd / dvsr
            MessageBox.Show(testnum.ToString)
    
        End Sub
    
        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            For i As Integer = 1 To 9
                For j As Integer = 2 To 64
                    If i / j = testnum Then
                        MessageBox.Show("the fraction is " & i.ToString & "/" & j.ToString)
                        'Exit Sub 'uncomment this if you want only the reduced fraction
                    End If
                Next
            Next
        End Sub
    Sunday, July 05, 2009 12:30 AM
  • Hi

    Nice work jwavila....

    But it has some limitations on the fractions that you can recover but that is just a matter of how precice you need them Id guess


    Kenneth
    Sunday, July 05, 2009 12:39 AM
  • If you change the for statment to this it might always give you an answer

        If i / j = testnum Or i / j - testnum < Double.Epsilon Then
                        MessageBox.Show("the fraction is " & i.ToString & "/" & j.ToString)
                        'Exit Sub 'uncomment this if you want only the reduced fraction
                    End If
    And in addition ... Lets say you wright alarge fraction like 468 / 81 your program wouldnt cop with it unless you did something like this

    testnum = dvnd / dvsr - Cint(dvnd / dvsr)
    and add another variabel for the hole fraction

    dim holenumner = Cint(dvnd / dvsr)


    Kenneth
    Sunday, July 05, 2009 12:47 AM
  • well if you notice I cut off the bottom number at 64. I also tried it up to 1000 and everything worked OK. Didn't miss any of them.

    I don't know if it will stand the test of time, however.

    Do me a favor and change the j = 2 to whatever number you want and then try it.

    Thanks
    Sunday, July 05, 2009 1:00 AM
  • well if you notice I cut off the bottom number at 64. I also tried it up to 1000 and everything worked OK. Didn't miss any of them.

    I don't know if it will stand the test of time, however.

    Do me a favor and change the j = 2 to whatever number you want and then try it.

    Thanks

    Way beond you ;-) Ill post in a secound
    Kenneth
    Sunday, July 05, 2009 1:05 AM
  • Hi

    paste inn this class... It still misses something but you can easely add that

    Public Class Fractions
        Private pHoleNumber As Integer
        Private pDevicor As Integer
        Private pNummorator As Integer
    
        Public Sub New()
    
        End Sub
    
        Public Sub New(ByVal HoleNumber As Integer, ByVal Nummorator As Integer, ByVal Devicor As Integer)
            pNummorator = Nummorator
            pHoleNumber = HoleNumber
            pDevicor = Devicor
        End Sub
    
        Public Sub New(ByVal Nummorator As Integer, ByVal Devicor As Integer)
            pNummorator = Nummorator
            pDevicor = Devicor
        End Sub
    
        Public Sub New(ByVal Desimal As Double)
            pHoleNumber = CInt(Math.Floor(Desimal))
            Dim test As Double = Desimal - CInt(Math.Floor(Desimal))
    
            For i As Integer = 1 To 100
                For j As Integer = 1 To 1000
                    If i / j = test Then
                        pNummorator = i
                        pDevicor = j
                        Exit For
                        Exit For
                    End If
                Next
            Next
        End Sub
    
    
        Public Overloads Function ToString() As String
            Return pHoleNumber & " " & pNummorator & "/" & pDevicor
        End Function
    
        Public Overloads Shared Operator +(ByVal N1 As Fractions, ByVal N2 As Fractions) As Fractions
            Dim hole As Integer = N1.pHoleNumber + N2.pHoleNumber
            Dim commonDev As Integer = N1.pDevicor * N2.pDevicor
            Dim commonNum As Integer = N1.pNummorator * N2.pDevicor + N2.pNummorator * N1.pDevicor
            Dim result As New Fractions(hole, commonNum, commonDev)
            Return result
        End Operator
    
        Public Property Nummorator() As Integer
            Get
                Return pNummorator
            End Get
            Set(ByVal value As Integer)
                pNummorator = value
            End Set
        End Property
    
        Public Property Devicor() As Integer
            Get
                Return pDevicor
            End Get
            Set(ByVal value As Integer)
                pDevicor = value
            End Set
        End Property
    
        Public Property HoleNumber() As Integer
            Get
                Return pHoleNumber
            End Get
            Set(ByVal value As Integer)
                pHoleNumber = value
            End Set
        End Property
    End Class

    Kenneth
    Sunday, July 05, 2009 1:38 AM
  • Hi just a little ting ... this will work even better

     For i As Integer = 1 To 100
                For j As Integer = 1 To 1000
                    If i / j = test Then
                        pNummorator = i
                        pDevicor = j
                        Dim counter As Integer = 0
                        If pNummorator < pDevicor Then
                            counter = pNummorator
                        Else
                            Counter = pDevicor
                        End If
    
                        For a = 2 To Counter
                            If pNummorator Mod a = 0 Then
                                If pDevicor Mod a = 0 Then
                                    pNummorator /= a
                                    pDevicor /= a
                                End If
                            End If
                        Next
                        Exit For
                        Exit For
                    End If
                Next
            Next

    Kenneth
    Sunday, July 05, 2009 1:57 AM
  • hmm

    Not perfect... It does something strange when you put in double values.... and they dont get the right value input.... Could someone please check this?
    Kenneth
    Sunday, July 05, 2009 2:49 AM
  • I found a QBASIC program for converting decimal numbers to fractions.  I didn't write it, but I translated the code into something that will run inside a VB Console application.  Check this out to see if it works for you:


    Module Module1
    
        Sub Main()
    		'translated by Solitaire from QBasic code originally written by lawgin
    		Dim min, d1, p, dp, wp, m, x1, x2, dx, y, d2 As Double
    		Dim d As String
    		min = 10
    		Console.Write("Enter decimal:  ")
    		d = Console.ReadLine()
    		p = Len(d) - InStr(d, ".") + 1
    		d1 = Val(d)
    		wp = Int(d1)
    		dp = d1 - wp
    		Do
    			m = m + 1
    			x1 = m * dp
    			x2 = CLng(x1)
    			dx = Math.Abs(x1 - x2)
    			If dx < min Then
    				min = dx
    				y = m
    				d2 = (CLng(y * dp) + y * wp) / y
    			End If
    		Loop Until Math.Abs(d2 - d1) < 1 / 10 ^ p
    		Console.WriteLine(d1 & " = " & CLng(y * dp) + y * wp & "/" & y)
    		Console.ReadLine()
    	End Sub
    
    End Module

    Solitaire
    Sunday, July 05, 2009 2:55 AM
  • Hi Solitare 

    hmm... I get my code to work but in obviuse cases it does not show the value im expekt.... My lates attemt to create a own struct is shown below.... I have also implemented the transleted code from lawgin you provided... but I couldnt get it to work properly


    Public Structure Fractions
        Public pHoleNumber As Integer
        Public pDevicor As Integer
        Public pNummorator As Integer
    
        Public Sub New(ByVal HoleNumber As Integer, ByVal Nummorator As Integer, ByVal Devicor As Integer)
            pNummorator = Nummorator
            pHoleNumber = HoleNumber
            pDevicor = Devicor
        End Sub
    
        Public Sub New(ByVal Nummorator As Integer, ByVal Devicor As Integer)
            pNummorator = Nummorator
            pDevicor = Devicor
        End Sub
    
        Public Sub New(ByVal Desimal As Double, ByVal bool As Boolean)
            Dim result As New Fractions
            If bool = True Then
                Dim d As Double = Desimal
                result.HoleNumber = Math.Floor(d)
                Dim test As Double = d - CDbl(result.HoleNumber)
                For i As Integer = 1 To 1000
                    For j As Integer = 1 To 10000
                        If i / j = test Or i / j - test < Double.Epsilon Then
                            result.Nummorator = i
                            result.Devicor = j
                            Dim counter As Integer = 0
                            If result.Nummorator < result.Devicor Then
                                counter = result.Nummorator
                            Else
                                counter = result.Devicor
                            End If
    
                            For a = 2 To counter
                                If result.Nummorator Mod a = 0 Then
                                    If result.Devicor Mod a = 0 Then
                                        result.Nummorator /= a
                                        result.Devicor /= a
                                    End If
                                End If
                            Next
                            Exit For
                            Exit For
                        End If
                    Next
                Next
    
            Else
                'Solitare translation of lawgin code
                Dim min, d1, p, dp, wp, m, x1, x2, dx, y, d2 As Double
                Dim d As String
                min = 10
    
                d = Desimal
                p = Len(d) - InStr(d, ".") + 1
                d1 = Val(d)
                wp = Int(d1)
                dp = d1 - wp
                Do
                    m = m + 1
                    x1 = m * dp
                    x2 = CLng(x1)
                    dx = Math.Abs(x1 - x2)
                    If dx < min Then
                        min = dx
                        y = m
                        d2 = (CLng(y * dp) + y * wp) / y
                    End If
                Loop Until Math.Abs(d2 - d1) < 1 / 10 ^ p
    
                result.HoleNumber = CLng(y * dp)
                result.Nummorator = y * wp
                result.Devicor = y
            End If
    
            Me.HoleNumber = result.HoleNumber
            Me.Nummorator = result.Nummorator
            Me.Devicor = result.Devicor
        End Sub
    
        Public Property Nummorator() As Integer
            Get
                Return pNummorator
            End Get
            Set(ByVal value As Integer)
                pNummorator = value
            End Set
        End Property
    
        Public Property Devicor() As Integer
            Get
                Return pDevicor
            End Get
            Set(ByVal value As Integer)
                pDevicor = value
            End Set
        End Property
    
        Public Property HoleNumber() As Integer
            Get
                Return pHoleNumber
            End Get
            Set(ByVal value As Integer)
                pHoleNumber = value
            End Set
        End Property
    
        Public Overloads Overrides Function ToString() As String
            Return pHoleNumber & " " & pNummorator & "/" & pDevicor
        End Function
    
        ' Unary operators:
        Public Shared Operator +(ByVal c As Fractions) As Fractions
            Return c
        End Operator
    
        Public Shared Operator -(ByVal c As Fractions) As Fractions
            Return New Fractions(c.HoleNumber, c.Nummorator, c.Devicor)
        End Operator
    
        Public Overloads Shared Operator +(ByVal N1 As Fractions, ByVal N2 As Fractions) As Fractions
            Dim hole As Integer = N1.pHoleNumber + N2.pHoleNumber
            Dim commonDev As Integer = N1.pDevicor * N2.pDevicor
            Dim commonNum As Integer = N1.pNummorator * N2.pDevicor + N2.pNummorator * N1.pDevicor
    
            Dim n As Integer = Math.Floor(commonNum / commonDev)
            If n >= 1 Then
                hole += n
                commonNum -= n * commonDev
            End If
            Dim counter As Integer = 0
            If commonNum < commonDev Then
                counter = commonNum
            Else
                counter = commonDev
            End If
    
            For a = 2 To counter
                If commonNum Mod a = 0 Then
                    If commonDev Mod a = 0 Then
                        commonNum /= a
                        commonDev /= a
                    End If
                End If
            Next
    
    
            Dim result As New Fractions(hole, commonNum, commonDev)
            Return result
        End Operator
    End Structure
    Feel free to have a go at it... Here is a test example:

     TextBox6.Text = CDbl(TextBox4.Text) + CDbl(TextBox3.Text)
            Dim f As New Fractions(CDbl(TextBox3.Text), True)
            Dim ff As New Fractions(CDbl(TextBox4.Text), True)
            Dim g As New Fractions
            g = f + ff
            TextBox5.Text = g.ToString

    Kenneth
    Sunday, July 05, 2009 4:06 AM
  • Hmm...

    Ive been doing some thinking ... Its unusual for me... ;-) And there is ofcource a different way of getting a fraction then the ones that are mention above....

    Metod 1:
    Lets say you have a texte box and you want to write in the irrational number PI.... There is ofcourse a simple way of turnig the number Pi into a fraction...
    dim txtStr as String = TextInput
    dim Chords as String() = txtStr.Split(",") or by . in english
    you will then have the Integer in Chords(0) and in Chords(1) you will have all the numbers after decimal point.

    the nummorator can thus be set to Chords(1) and the denummorator will the become 10^(Chords(1).length). I think this is a way for irrational numbers, becouse you will never or seldom get a nice fraction from them....

    Method 2: the on that is been shown in this thread before... They work well for rational numbers or numbers that a cumbersome in decimal and nice in fractions. 

    The Ideal solution, in my mind is to combine the two methods in one... You might first check if you willl get a nice fraction with method 2... And if thats not the case you can always go for method 1.

    With method 1 there is a possibilyuty that you could factor it down. I have modified a code for doning that and it baisially sees if the same mod a goes for nummorator and denummorator. 

     Dim counter As Integer = Math.Max(commonDev, commonNum)
            Dim a As Integer = 2
            While a < commonNum Or commonDev > a
                If commonNum Mod a = 0 Then
                    If commonDev Mod a = 0 Then
                        commonNum = commonNum / a
                        commonDev = commonDev / a
                        a = 2
                    Else
                        a += 1
                    End If
                Else
                    a += 1
                End If
            End While
    For a simple program, designing a struct or a class that holds all the fractions might be a little overkill. but i you do it properly it will work on every occation. I have corrected som bad coding mistakes in it and it wont work properly the way it is displaied here.


     
    Kenneth
    Tuesday, July 07, 2009 8:05 PM