dcsimg
October 25, 2020
Hot Topics:

Implementing a Decimal-to-Fraction Class with Operator Overloading

  • By Paul Kimmel
  • Send Email »
  • More Articles »

Listing 1: The complete listing of the Fraction class.

Public Class  Fraction

   Public Sub New(ByVal number As Double)
      _number = Math.Round(number, 8)
      Dim value As String = _number.ToString()

      SetSign(value)
      Dim index As Integer = CheckNoDecimalPoint(number)
      If (index = -1) Then Return

      SetWholePart(value, index)
      SetFractionalPart(value, index)

   End Sub

   Public Shared Operator +(ByVal lhs As Fraction, _
                            ByVal rhs As Fraction) _
      As Fraction
      Return New Fraction(rhs.Number + lhs.Number)
   End Operator

   Public Shared Operator -(ByVal lhs As Fraction, _
                            ByVal rhs As Fraction) _
      As Fraction
      Return New Fraction(rhs.Number - lhs.Number)
   End Operator

   Public Shared Operator =(ByVal lhs As Fraction, _
                            ByVal rhs As Fraction) _
      As Boolean
      Return rhs.Number = lhs.Number
   End Operator

   Public Shared Operator <>(ByVal lhs As Fraction, _
                             ByVal rhs As Fraction) _
      As Boolean
      Return rhs.Number <> lhs.Number
   End Operator

   Public Shared Widening Operator CType(ByVal rhs As Fraction) _
      As Double
      Return rhs.Number
   End Operator

   Public Shared Operator /(ByVal lhs As Fraction, _
                            ByVal rhs As Fraction) _
      As Fraction
      Return New Fraction(rhs.Number / lhs.Number)
   End Operator

   Public Shared Operator *(ByVal lhs As Fraction, _
                            ByVal rhs As Fraction) _
      As Fraction
      Return New Fraction(rhs.Number * lhs.Number)
   End Operator

   Public Shared Narrowing Operator CType(ByVal number As Double) _
      As Fraction
      Return New Fraction(number)
   End Operator

   Public Sub New(ByVal number As String)
      Me.New(Convert.ToDouble(number))
   End Sub

   Private _number As Double
   Public Property Number() As Double
      Get
         Return _number
      End Get
      Set(ByVal Value As Double)
         _number = Value
      End Set
   End Property

   Private _sign As Integer = 1
   Public Property Sign() As Integer
      Get
         Return _sign
      End Get
      Set(ByVal Value As Integer)
         _sign = Value
      End Set
   End Property

   Private _numerator As Integer = 0
   Public Property Numerator() As Integer
      Get
         Return _numerator
      End Get
      Set(ByVal Value As Integer)
         _numerator = Value
      End Set
   End Property

   Private _denominator As Integer = 1
   Public Property Denominator() As Integer
      Get
         Return _denominator
      End Get
      Set(ByVal Value As Integer)
         _denominator = Value
      End Set
   End Property

   Private _fractionalNumber As Double
   Public Property FractionalNumber() As Double
      Get
         Return _fractionalNumber
      End Get
      Set(ByVal Value As Double)
         _fractionalNumber = Value
      End Set
   End Property

   Private _wholeNumber As Integer
   Public Property WholeNumber() As Integer
      Get
         Return _wholeNumber
      End Get
      Set(ByVal Value As Integer)
         _wholeNumber = Value
      End Set
   End Property

   Private Sub SetSign(ByVal value As String)

      If (Regex.IsMatch(value, "^-")) Then
         Sign = -1
      End If

   End Sub


   Private Function CheckNoDecimalPoint(ByVa number As Double) _
      As Integer

      Dim index As Integer = number.ToString().LastIndexOf(".")

      If (index = -1) Then
         WholeNumber = Convert.ToInt32(number)
      End If

      Return index

   End Function

   Private Sub SetWholePart(ByVal value As String, _
                            ByVal index As Integer)

      Dim whole As String = value.Substring(0, index)
      If (whole.Length > 0) Then
         WholeNumber = Convert.ToInt32(whole)
      End If

   End Sub

   Private Sub SetDenominator(ByVal fraction As String)
      Denominator = Math.Pow(10, fraction.Length)
   End Sub

   Private Sub SetFractionalPart(ByRef fraction As String)
      If (fraction.Length > 8) Then
         fraction = fraction.Substring(0, 8)
      End If

      _fractionalNumber = _
         Math.Round(Convert.ToDouble("." + fraction), 8)
   End Sub

   Private Sub SetFractionalPart(ByVal value As String, _
                                 ByVal index As Integer)

      Dim fraction As String = value.Remove(0, index + 1)

      If (fraction.Length > 0) Then
         SetFractionalPart(fraction)
         _numerator = Convert.ToInt32(fraction)
         SetDenominator(fraction)
         ReduceWithGcd()
      End If
   End Sub

   Private Sub ReduceWithGcd()

      Dim divisor As Integer = Gcd(_numerator, _denominator)
      _numerator   = _numerator / divisor
      _denominator = _denominator / divisor

   End Sub

   Private Function Gcd(ByVal num As Integer, _
                        ByVal den As Integer) As Integer

      If (den Mod num = 1) Then Return 1
      While (den Mod num <> 0)
         Dim temp As Integer = num
         num = den Mod num
         den = temp
      End While

      Return num

   End Function

   Public Overrides Function ToString() As String

      If (FractionalNumber = 0 And WholeNumber = 0) Then
         Return ""
      End If

      Dim builder As StringBuilder = New StringBuilder()
      If (Sign = -1) Then builder.Append("-")

      If (Math.Abs(WholeNumber) <> 0) Then

         If (FractionalNumber = 1) Then
            builder.Append(Math.Abs(WholeNumber) + 1)
            Return builder.ToString()
         Else
            builder.Append(Math.Abs(WholeNumber))
            builder.Append(" ")
         End If
      End If

      If (FractionalNumber <> 0) Then
         builder.Append(Numerator.ToString())
         builder.Append("/")
         builder.Append(Denominator.ToString())
      End If

      Return builder.ToString()
   End Function

End Class




Page 3 of 4



This article was originally published on August 15, 2007

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.


Thanks for your registration, follow us on our social networks to keep up-to-date