namespace boost{ namespace multiprecision{
enum digit_base_type
{
digit_base_2 = 2,
digit_base_10 = 10
};
template <unsigned Digits, digit_base_type base = digit_base_10, class Allocator = void, class Exponent = int, ExponentMin = 0, ExponentMax = 0>
class cpp_bin_float;
typedef number<cpp_bin_float<50> > cpp_bin_float_50;
typedef number<cpp_bin_float<100> > cpp_bin_float_100;
typedef number<backends::cpp_bin_float<24, backends::digit_base_2, void, boost::int16_t, -126, 127>, et_off> cpp_bin_float_single;
typedef number<backends::cpp_bin_float<53, backends::digit_base_2, void, boost::int16_t, -1022, 1023>, et_off> cpp_bin_float_double;
typedef number<backends::cpp_bin_float<64, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_double_extended;
typedef number<backends::cpp_bin_float<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_quad;
}}
Шаблон класса cpp_bin_float
отвечает всем требованиям для типа Backend. Его члены и функции, не являющиеся членами, намеренно не документируются: они считаются деталями реализации, которые могут быть изменены.
Класс принимает шесть параметров шаблона:
- Digits
Количество цифр точности, которое должен поддерживать тип. Обычно это выражается в виде базовых 10 цифр, но это может быть изменено с помощью второго параметра шаблона.
- base
Перечисленное значение (digit_base_10
или digit_base_2
), которое указывает, является ли Digits
основанием-10 или основанием-2
- Allocator
Используемый распределитель: по умолчанию введите void
, что означает, что все хранилище находится в классе, и динамическое распределение не выполняется, но может быть установлено в стандартный распределитель библиотеки, если динамическое распределение имеет больше смысла.
- Exponent
Подписанный целочисленный тип для использования в качестве типа экспонента - по умолчанию int
.
- ExponentMin
Самый маленький (наиболее отрицательный) разрешенный показатель, по умолчанию равный нулю, что означает «определить как можно меньше с учетом ограничений типа и наших внутренних требований».
- ExponentMax
Самый большой (наиболее положительный) разрешенный показатель, по умолчанию равный нулю, что означает «определить как можно больше с учетом ограничений типа и наших внутренних требований».
Тип number_categorycpp_bin_float<...> >::type
mpl::number_kind_floating_point>
.
Более подробную информацию об этом типе можно найти в tutorial.
Внутри N-бит cpp_bin_float
представлен как N-битовое неподписанное целое число вместе с экспонентой и знаком. Целая часть нормализуется так, что наиболее значимый бит всегда 1. Предполагается, что десятичная точка находится непосредственно после наиболее значительного бита целой части. Специальные значения ноль, бесконечность и NaN имеют целочисленную часть, установленную на ноль, и показатель на одно из 3 специальных значений выше максимально допустимого показателя.
Умножение тривиально: умножьте два N-битовых целых числа мантиссы, чтобы получить 2N-битовое число, затем округлите и отрегулируйте знак и показатель.
Сложение и вычитание протекают аналогично - если экспоненты таковы, что существует перекрытие между двумя значениями, то левое смещение большего значения для получения числа между N и 2N битами, затем выполнение целочисленного сложения или вычитания, округление и корректировка экспоненты.
Разделение происходит следующим образом: сначала масштабируйте числитель некоторой мощностью 2 так, чтобы целое деление производило либо N-бит, либо N+1 бит плюс остаток. Если мы получим результат N бита, то размер вдвое больше остатка по сравнению с знаменателем дает нам направление округления. В противном случае у нас есть один дополнительный бит в результате, который мы можем использовать для определения округления (в этом случае связи возникают только в том случае, если остаток равен нулю, а дополнительный бит равен 1).
Квадратный корень использует целочисленный квадратный корень аналогично делению.
Децимальная строка к бинарному преобразованию протекает следующим образом: сначала разбирают цифры для получения целого числа, умноженного на десятичный показатель. Обратите внимание, что мы прекращаем разбор цифр, как только мы разобрали столько, сколько возможно, чтобы повлиять на результат - это останавливает целочисленную часть, которая становится слишком большой, когда есть очень большое количество введенных цифр. На этом этапе, если десятичный показатель положителен, то результат является целым числом, и мы можем в принципе просто умножить на 10^N, чтобы получить точный целочисленный результат. Однако на практике это может привести к образованию очень больших целых чисел. Мы также должны быть в состоянии разделить на 10N, если показатель отрицательный. Поэтому вычисление значений 10^N плюс умножение или деление выполняется с использованием ограниченной точности целочисленной арифметики плюс показатель и трек накопленной ошибки. В конце вычисления мы либо сможем округлиться однозначно, либо ошибка будет такова, что мы не сможем определить, каким путем округлять. В последнем случае мы просто повышаем точность и пробуем снова, пока не получим однозначно округленный результат.
Бинарное преобразование в десятичную величину происходит очень похоже на вышеуказанное, наша цель состоит в том, чтобы вычислить mantissa 10 E
, где E
вычисляется так, что результат представляет собой N битовое целое число, предполагая, что мы хотим, чтобы в результате были напечатаны N цифр. Как и прежде, мы используем ограниченную прецизионную арифметику для вычисления результата и повышения точности по мере необходимости, пока результат не будет однозначно правильно округлен. Кроме того, наш первоначальный расчет десятичного показателя может быть вычислен на 1, поэтому мы должны исправить это и цикл в этом случае.