65.9K
CodeProject is changing. Read more.
Home

A Rational .NET Class

May 2, 2023

MIT

2 min read

viewsIcon

10821

downloadIcon

134

A rational class to extend numeric functionality

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.

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:

        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:

    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.

    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

2024/07/02 Release

The code has been improved while fixing some bugs.

2024/09/15 Release

  1. A new constructor for integers numerator and denominator has been included.
  2. Recoded method OpFactors() for just integers.
  3. Rewritten method OpPow(Rational, Rational)

  • 2nd May, 2023: Initial version