The numerical tower and type coercion¶
Before proceeding to show how mp++’s classes can be used to perform arithmetic computations, it is useful to introduce first the hierarchy on top of which mp++’s type coercion is built.
In a broad sense, mp++ aims to extend C++’s type hierarchy with multiprecision numerical types. In C++, when numerical operands of different types are involved in an arithmetic operation, all operands are converted (or coerced) into a common type determined from the types of the operands. The converted operands are then used in place of the original operands to perform the operation, and the type of the result will be the common type. For instance:
auto a = 4 + 5l; // '4' is int, '5l' is long: a will be long. auto b = 4.f + 5l; // '4.f' is float, '5l' is long: b will be float. auto c = 4.f + 5.; // '4.f' is float, '5.' is double: c will be double.
In order to determine the common type, C++ assigns a rank to each fundamental type. In an operation involving operands of different types, the type of the result will be the type with the highest rank among the types of the operands. Although there are a few complications and caveats, the general rule in C++ is that integral types have a lower rank than floating-point types, and that, within the integral and floating-point types, a higher range or bit width translates to a higher rank. The underlying idea is that automatic type coercion should not change the value of an operand 1.
mp++ extends C++’s type hierarchy in a (hopefully) natural way:
integerhas a rank higher than any C++ integral type, but lower than any C++ floating-point type;
rationalhas a rank higher than
integer, but lower than any C++ floating-point type;
real128has a rank higher than any C++ floating-point type;
In other words, mp++’s type hierarchy (or numerical tower) from the lowest rank to the highest is the following:
Note that up to and including
rational, types with higher rank can represent exactly all values
of any type with a lower rank. The floating-point types, however, cannot represent exactly all values representable
integer or even the C++ integral types. It should also be noted
real’s precision is set at runtime, and it is thus possible to create
objects with a precision lower than
real128 or any of the C++ floating-point types. Regardless,
when it comes to type coercion,
real is always assigned a rank higher than any other type.
mp++’s type coercion rules extend beyond arithmetic operators. The exponentiation functions
pow(), for instance,
also use the type hierarchy to determine the type of the result. Type coercion is also applied in the comparison operators,
where arguments of different types are promoted to the common type before actually carrying out the comparison.
Strictly speaking, this is of course not true. On modern architectures, a large enough 64-bit
long longwill be subject to a lossy conversion to, e.g.,
floatduring type coercion.