Implementing a Decimal-to-Fraction Class with Operator Overloading
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