Смешанная точная арифметика полностью поддерживается библиотекой.
Существуют две различные формы:
- Где операнды отличаются точностью.
- где операнды имеют одинаковую точность, но дают более высокий результат точности.
Если аргументы двоичного оператора имеют разную точность, то операция допускается до тех пор, пока существует однозначное неявное преобразование из одного типа аргументов в другой. Во всех случаях арифметика выполняется «как если бы» перед применением оператора низкоточный тип был повышен до более высокоточного типа. Тем не менее, определенные бэкэнды могут оптимизировать это и избежать создания временного, если они могут это сделать.
Например:
mpfr_float_50 a(2), b;
mpfr_float_100 c(3), d;
static_mpfr_float_50 e(5), f;
mpz_int i(20);
d = a * c;
b = a * c;
f = a * e;
f = e * i;
Иногда требуется применить оператора к двум аргументам одинаковой точности таким образом, чтобы получить результат более высокой точности. Наиболее распространенная ситуация происходит с фиксированными целыми числами, где вы хотите умножить два N-битных числа, чтобы получить 2N-битный результат. Это поддерживается в этой библиотеке следующими бесплатными функциями:
template <class ResultType, class Source1 class Source2>
ResultType& add(ResultType& result, const Source1& a, const Source2& b);
template <class ResultType, class Source1 class Source2>
ResultType& subtract(ResultType& result, const Source1& a, const Source2& b);
template <class ResultType, class Source1 class Source2>
ResultType& multiply(ResultType& result, const Source1& a, const Source2& b);
Эти функции применяют названного оператора к аргументам.aиbи сохранить результат вРезультатВозвращениерезультат. Во всех случаях они ведут себя «как будто» аргументами.aиbбыли сначала продвинуты на тип<ResultType
>перед применением оператора, хотя отдельные бэкэнды вполне могут избежать этого шага посредством оптимизации.
Тип<ResultType
>должен быть экземпляром класса<number
>, а типы<Source1
>и<Source2
>могут быть либо экземплярами класса<number
>, либо нативными целыми типами. Последнее представляет собой оптимизацию, которая позволяет выполнять арифметику на нативных целых типах, производя расширенный результат точности.
Например:
#include <boost/multiprecision/cpp_int.hpp>
int main()
{
using namespace boost::multiprecision;
boost::uint64_t i = (std::numeric_limits<boost::uint64_t>::max)();
boost::uint64_t j = 1;
uint128_t ui128;
uint256_t ui256;
std::cout << std::hex << std::showbase << i << std::endl;
std::cout << std::hex << std::showbase << add(ui128, i, j) << std::endl;
std::cout << std::hex << std::showbase << multiply(ui128, i, i) << std::endl;
ui128 = (std::numeric_limits<uint128_t>::max)();
std::cout << std::hex << std::showbase << multiply(ui256, ui128, ui128) << std::endl;
return 0;
}
Производит продукцию:
0xffffffffffffffff
0x10000000000000000
0xFFFFFFFFFFFFFFFE0000000000000001
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00000000000000000000000000000001
Следующие бэкэнды имеют, по крайней мере, некоторую прямую поддержку смешанной точной арифметики, и поэтому избегают создания ненужных временных интервалов при использовании интерфейсов выше. Поэтому при использовании этих типов более эффективно использовать смешанную точную арифметику, чем явно отбрасывать операнды к типу результата:
mpfr_float,gmp_float,cpp_int.