A rational class employing BigInteger class for Numerator and Denominator while making it possible to limit the length of both.

Rational Class
Presented here is a Rational
class which means numbers are stored in a numerator/denominator
fashion.
Both numerator
and denominator
are BigInteger
s 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)
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
- A new constructor for integers numerator and denominator has been included.
- Recoded method
OpFactors()
for just integers. - Rewritten method
OpPow(Rational, Rational)
- 2nd May, 2023: Initial version