Arbitrary Precision Rationals

A rational number is a number that can be expressed as a ratio of two integers. The same rational number can be represented in many different ways. For example, 1/2 = 3/6 = -5/-10, and so on. A unique representation can be defined by requiring that the numerator and the denominator do not have any common divisors, and requiring that the denominator is always positive.

Numerics.NET provides the BigRational class, which can represent rational numbers where the numerator and the denominator are arbitrary size integers. The internal representation of rational numbers is always normalized. Furthermore, the number 0 is represented as 0/1.

Constructing rational numbers

The BigRational class has three constructors. The first constructor takes two arguments: two BigInteger values that represent the numerator and the denominator. The second constructor takes two 32 bit integer arguments that once again represent the numerator and the denominator. The third constructor takes one BigInteger argument. It constructs the BigRational representation of the integer. The denominator is set equal to one.

C#
BigInteger n = BigInteger.Pow(2, 111);
BigInteger d = BigInteger.Pow(3, 111);
BigRational a = new BigRational(n, d);
BigRational b = new BigRational(1, 5);
BigRational c = new BigRational(n);

Rational constants

The BigRational class provides several constants for commonly used and special rational numbers. These are listed in the following table:

Rational number constants

Field

Description

Zero

The number zero.

One

The number one.

MinusOne

The number minus one.

MinValue

The smallest possible BigRational value, equal to -268719476704.

MaxValue

The largest possible BigRational value, equal to 268719476704.

Working with rational numbers

Working with rational numbers is easy. The Numerator property gets the numerator of the rational number, while Denominator gets the denominator. The numerator and the denominator never have common divisors and the denominator is always positive. The Sign property returns the sign of the rational number.

Details of rational arithmetic

When performing binary operations, if one of the operands is a BigRational, and the other operand is an integer of any size (including BigInteger), then the integer operand is converted to BigRational, and, if the operation produces a numerical result, the type of the result is BigRational.

Operations with non-integer types, including, Decimal, are not supported.

Arithmetic operations

Numerics.NET provides methods for all basic arithmetic operators on rational numbers. Most contain special versions for cases where one of the operands is real. Overloaded versions of the arithmetic operators are provided for languages that support them. For languages that don't support operator overloading, equivalent static (Shared in Visual Basic) methods are supplied. For example:

C#
BigRational e = new BigRational(2, 7);
BigRational f = new BigRational(3, 5);
BigRational g = 2 - 3 * (e + f);
Rational number operators and their static (Shared) method equivalents

Operator

Static method equivalent

Description

+q

(no equivalent)

Returns the rational number q.

-q

Negate

Returns the negation of the rational number q.

q1 + q2

BigRational.Add(q1, q2)

Adds the rational numbers q1 and q2.

q + a

BigRational.Add(q, a)

Adds the rational number q and the big integer a.

a + q

BigRational.Add(a, q)

Adds the big integer a to the rational number q.

q++

(no equivalent)

Increments the rational number q by one.

q1 - q2

BigRational.Subtract(q1, q2)

Subtracts the rational numbers q1 and q2.

q - a

BigRational.Subtract(q, a)

Subtracts the big integer a from the rational number q.

a - q

BigRational.Subtract(a, q)

Subtracts the rational number q from the big integer a.

q--

(no equivalent)

Decrements the rational number q by one.

q1 * q2

BigRational.Multiply(q1, q2)

Multiplies the rational numbers q1 and q2.

q * a

BigRational.Multiply(q, a)

Multiplies the rational number q and the big integer a.

a * q

BigRational.Multiply(a, q)

Multiplies the big integer a and the rational number q.

q1 / q2

BigRational.Divide(q1, q2)

Divides the rational number q1 by q2.

q / a

BigRational.Divide(q, a)

Divides the rational number q by the big integer a.

a / q

BigRational.Divide(a, q)

Divides the big integer a by the rational number q.

In addition, the relational operators are also available. In a language that does not support custom operators, the Equals or CompareTo method can be used.

Functions of rational numbers

The Abs method returns the absolute value of a rational number. The Max and Min methods return the larger and smaller of two rational numbers, respectively. The Floor method returns the largest integer less than or equal to a rational number. The Ceiling method returns the smallest integer greater than or equal to a number. The Round method rounds a rational number to the specified number of decimal digits.

Casts and conversions

Converting to big integers

The BigRational type supports implicit conversions from all numerical including BigInteger.

For the built-in floating-point types, Single and Double, and Decimal, the result is the exact representation as a rational number where the denominator is a power of 2 or 10.

Converting from rational numbers

There are no implicit conversions from BigRational to any of the built-in numerical types. For integral types, the explicit conversions first round the number towards zero and return the least significant bits of the rounded value that fit in the type. For example, the conversion to a 32 bit unsigned integer contains the 32 least significant bits of the rounded value.

For the built-in floating-point types, Single and Double, the converted value is accurate to the first 24 or 53 bits, respectively. If the number is too large to be represented in the floating-point type, then either positive or negative infinity is returned.

The BigRational type also implements the IConvertible interface. The implementation is explicit. In order to call any of the conversion functions, you first need to cast the original to the IConvertible interface type.

Unlike type casts, calls to these conversion types do throw an OverflowException when the value is too large to fit in an integral type or Decimal.