Лупбэкиликруговой походотносится к записи значения в виде десятичной строки с использованием<std::iostream
>, обычно к<std::stringstream
>, а затем к чтению строки обратно к другому значению и подтверждению того, что эти два значения идентичны. Тривиальный пример с использованием<float
>:
float write;
std::stringstream ss;
ss.precision(std::numeric_limits<T>::max_digits10);
ss.flags(std::ios_base::fmtflags(std::ios_base::scientific));
ss << write;
float read;
ss >> read;
BOOST_CHECK_EQUAL(write, read);
и это может быть запущено в цикле для всех возможных значений 32-битного поплавка. Для других типов плавающих точек<T
>, включая встроенные<double
>, проверка всех значений занимает слишком много времени, поэтому разумной стратегией тестирования является использование большого количества случайных значений.
T write;
std::stringstream ss;
ss.precision(std::numeric_limits<T>::max_digits10);
ss.flags(f);
ss << write;
T read;
ss >> read;
BOOST_CHECK_EQUAL(read, write);
read = static_cast<T>(ss.str());
BOOST_CHECK_EQUAL(read, write);
read = static_cast<T>(write.str(0, f));
BOOST_CHECK_EQUAL(read, write);
Тест наtest_cpp_bin_float_io.cppпозволяет любому типу с плавающей точкой бытькруговым, используя широкий диапазон довольно случайных значений. Он также включает тесты, сравнивающие наборструнных данныхтестовых случаев в файле.
Можно провести некоторые сравнения с выходом
<number<cpp_bin_float<53, digit_count_2> >
Он имеет такое же количество существенных битов (53), как и 64-битная плавающая точка с двойной точностью.
Однако, хотя большинство выводов идентичны, на некоторых платформах существуют различия, вызванные поведением, зависящим от реализации, разрешенным спецификацией C99C99 ISO/IEC 9899:TC2, включенной в C++.
"Для конверсий e, E, f, F, g и G, если число значащих десятичных знаков не превышает DECIMAL_ DIG, то результат должен быть правильно округлен. Если число знаковых десятичных знаков больше, чем DECIMAL_ DIG, но исходное значение точно отображается с помощью DECIMAL_ Цифры DIG, то результат должен быть точным представлением с нулями. В противном случае исходное значение ограничено двумя соседними десятичными строками L< U, обе из которых имеют DECIMAL_. DIG значащие цифры; значение результирующей десятичной строки D должно удовлетворять L<= D<= U, с дополнительным условием, что ошибка должна иметь правильный знак для текущего направления округления».
Таким образом, не только правильное округление для полного числа цифр не требуется, но даже если соблюдается необязательнаярекомендуемая практика, то значение этих последних нескольких цифр не указывается, пока значение находится в определенных пределах.
![[Note]](/img/note.png) |
Note |
Не ожидайте, что выход с разных платформ будетидентичным, но<cpp_dec_float >,<cpp_bin_float >(и другие бэкэнды) выходы должны быть правильно округлены до числа цифр, запрашиваемых заданной точностью и форматом. |
C99 Стандартдля спецификаторов форматов, 7.19.6 Форматированные функции ввода/вывода требуют:
«Экспонент всегда содержит по крайней мере две цифры и только столько цифр, сколько необходимо для представления экспоненты».
Соответствие стандарту C99 (включен в C++)
#define BOOST_MP_MIN_EXPONENT_DIGITS 2
Microsoft (и MinGW) не соответствуют этому стандарту и предоставляютпо меньшей мере три цифры, например<1e+001
>. Поэтому, если вы хотите, чтобы выход соответствовал встроенным типам с плавающей запятой на компиляторах, использующих время выполнения Microsoft, используйте:
#define BOOST_MP_MIN_EXPONENT_DIGITS 3
Также полезно получить минимальную ширину экспонентного поля.
#define BOOST_MP_MIN_EXPONENT_DIGITS 1
Для создания компактного вывода, такого как<2e+4
>, важно сохранить пространство.
Более крупные значения также поддерживаются, например, значение 4 для<2e+0004
>, которое может быть полезно для обеспечения выравнивания столбцов.