Click here to Skip to main content
15,887,776 members
Articles / Programming Languages / Visual Basic
Tip/Trick

A Rational .NET Class

Rate me:
Please Sign up or sign in to vote.
3.89/5 (4 votes)
3 May 2023MIT1 min read 6.2K   68   6   2
A rational class to extend numeric functionality
A rational class employing BigInteger class for Numerator and Denominator while making it possible to limit the length of both.

Image 1

Rational Class

Presented here is a Rational class which means numbers are stored in a numerator/denominator fashion.

Both numerator and denominator are BigIntegers so any numbers can be integers of any length.

To store non-integer numbers, the number is multiplied as much as needed to convert it to an integer. The denominator is also multiplied as much as the numerator.

For example, to store 1.2 is equivalent to store 1.2/1. The numerator should hold 1.2 and the denominator 1. But because we only can have integers, 1.2 is multiplied by 10 and also the denominator by 10. So we will store 12 and 10.

The initialization from double to Rational is:

VB.NET
Public Sub New(ByVal db As Double)
    If Double.IsInfinity(db) OrElse Double.IsNaN(db) Then
        tipo = db
        Exit Sub
    End If
    Dim i As Int32 = 0
    Dim s As String = String.Format("{0,25:E16}", db)
    Dim vs() As String = Split(s, "E")
    Dim sInt As String = vs(0).Chars(2) + Mid(vs(0), 5)
    Dim exp As Int32 = Int32.Parse(vs(1)) - 16
    If exp < 0 Then
        i += -exp
        exp = 0
    End If
    Numerator = BigInteger.Parse(sInt) * BigInteger.Pow(10, exp)
    If s.Chars(1) = "-" Then Numerator = -Numerator
    Denominator = BigInteger.Pow(10, i)
End Sub

Variable tipo accounts if the Rational is not a number (Double.NaN) or infinity (Double.Infinity). So, it is possible to divide for example 1/0:

VB.NET
Console.OutputEncoding = Text.Encoding.UTF8
Dim toDivide As New Rational(1.0)
Dim byZero As New Rational(0.0)
Dim s As String = (toDivide / byZero).toString
Console.WriteLine(s) ' will show the infinity symbol

Perhaps it isn't the fastest code but it is practical and does the job.

Addition code, for example, is done like:

VB.NET
Public Sub OpSuma(ByVal opB As Rational)
    Try
        If tipo OrElse opB.tipo Then
            If Double.IsNaN(tipo) OrElse Double.IsNaN(opB.tipo) Then
                tipo = Double.NaN
                Exit Try
            End If
            tipo += opB.tipo
            Exit Try
        End If
        If opB.bReduced Then bReduced = True
        If Denominator = opB.Denominator Then
            Numerator += opB.Numerator
        Else
            Dim N As BigInteger = Numerator * opB.Denominator + _
                                  Denominator * opB.Numerator
            Dim D As BigInteger = Denominator * opB.Denominator
            Numerator = N
            Denominator = D
        End If
        reduce()
    Catch ex As Exception
        Throw
    End Try
End Sub

bReduced keeps track of having reduced the length of the numerator and/or the denominator. The method calls reduce() where the length eventually will be reduced.

VB.NET
    Public Sub reduce(Optional nBytes As Int32 = 150)
    Dim sN As Int64
    Try
        ...
        Dim lnN As Int32 = Numerator.ToByteArray.Length
        Dim lnD As Int32 = Denominator.ToByteArray.Length
        If lnN > nBytes AndAlso lnD > nBytes Then

            Dim vN() As Byte = Numerator.ToByteArray
            Dim vD() As Byte = Denominator.ToByteArray
            Array.Reverse(vN)
            Array.Reverse(vD)
            Dim min As Int32 = Math.Min(lnN - nBytes, lnD - nBytes)
            ReDim Preserve vN(lnN - min), vD(lnD - min)
            Array.Reverse(vN)
            Array.Reverse(vD)
            Numerator = New BigInteger(vN)
            Denominator = New BigInteger(vD)
            If vN.Length < lnN OrElse vD.Length < vD.Length Then
                bReduced = True
            End If
            Exit Try
        End If
        If bReduced = False Then
            Dim A As BigInteger = Numerator
            Dim B As BigInteger = Denominator
            Dim C As BigInteger = BigInteger.GreatestCommonDivisor(A, B)
            A /= C : B /= C
            Numerator = A
            Denominator = B
        End If
    Catch ex As Exception
        Throw
    End Try
    If sN = -1 Then Numerator = -Numerator
End Sub 

If the length exceeds the maximum admitted, the rational is truncated. This is done by converting to byte arrays, reversing the bytes, truncating, and reversing again to have the new numerator and denominator.

Also, the bReduced flag in case of being truncated, is set.

Finally, if the set numerator, denominator has not been reduced, there is a Try to reduce both by dividing by the GCD.

Note

Now, the zip file contains the solution in both VB.NET and C#.

History

  • 2nd May, 2023: Initial version

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Spain Spain
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionContinued fractions Pin
Kenneth Haugland3-May-23 5:41
mvaKenneth Haugland3-May-23 5:41 
AnswerRe: Continued fractions Pin
Xavier Junqué i de Fortuny3-May-23 5:51
mvaXavier Junqué i de Fortuny3-May-23 5:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.