Как мне напечатать двойное значение с полной точностью, используя cout?
-
23-08-2019 - |
Вопрос
Итак, я получил ответ на свой последний вопрос (Не знаю, почему я об этом не подумал).я печатал double
с использованием cout
это округлилось, когда я этого не ожидал.Как я могу сделать cout
распечатать double
используя полную точность?
Решение
Вы можете установить точность непосредственно на std::cout
и используйте std::fixed
спецификатор формата.
double d = 3.14159265358979;
cout.precision(17);
cout << "Pi: " << fixed << d << endl;
Ты можешь #include <limits>
чтобы получить максимальную точность float или double.
#include <limits>
typedef std::numeric_limits< double > dbl;
double d = 3.14159265358979;
cout.precision(dbl::max_digits10);
cout << "Pi: " << d << endl;
Другие советы
Использовать std::setprecision
:
std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
Вот что я бы использовал:
std::cout << std::setprecision (std::numeric_limits<double>::digits10 + 1)
<< 3.14159265358979
<< std::endl;
По сути, пакет лимитов имеет характеристики для всех типов встроенных модулей.
Одной из характеристик чисел с плавающей запятой (float/double/long double) является атрибут digits10.Это определяет точность (я забыл точную терминологию) числа с плавающей запятой в базе 10.
Видеть: http://www.cplusplus.com/reference/std/limits/numeric_limits.html
Подробности о других атрибутах.
Способ iostreams немного неуклюж.Я предпочитаю использовать boost::lexical_cast
потому что он рассчитывает для меня правильную точность.И это быстро, слишком.
#include <string>
#include <boost/lexical_cast.hpp>
using boost::lexical_cast;
using std::string;
double d = 3.14159265358979;
cout << "Pi: " << lexical_cast<string>(d) << endl;
Выход:
Пи:3.14159265358979
Вот как отобразить двойное число с полной точностью:
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;
Это отображает:
100.0000000000005
max_digits10 — это количество цифр, необходимых для уникального представления всех различных двойных значений.max_digits10 представляет количество цифр до и после десятичной точки.
Не используйте set_precision(max_digits10) с std::fixed.
В фиксированной записи set_precision() устанавливает количество цифр. только после десятичная точка.Это неверно, поскольку max_digits10 представляет количество цифр. до и после десятичная точка.
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::fixed << std::setprecision(precision) << d << std::endl;
Это отображает неверный результат:
100.00000000000049738
Примечание:Требуются заголовочные файлы
#include <iomanip>
#include <limits>
Под полной точностью я подразумеваю достаточную точность, чтобы показать наилучшее приближение к предполагаемому значению, но следует отметить, что double
хранится с использованием представления по основанию 2, а основание 2 не может представлять что-то столь же тривиальное, как 1.1
точно.Единственный способ получить полный-полный точность фактического двойного числа (без ОШИБКИ ОКРУГЛЕНИЯ) заключается в распечатке двоичных битов (или шестнадцатеричных полубайтов).Один из способов сделать это — написать double
к union
а затем распечатываем целочисленное значение битов.
union {
double d;
uint64_t u64;
} x;
x.d = 1.1;
std::cout << std::hex << x.u64;
Это даст вам 100% точную точность двойного...и быть совершенно нечитаемым, потому что люди не могут читать двойной формат IEEE! Википедия есть хорошая статья о том, как интерпретировать двоичные биты.
В более новой версии C++ вы можете сделать
std::cout << std::hexfloat << 1.1;
Как мне распечатать
double
значение с полной точностью, используя cout?
Использовать hexfloat
или
использовать scientific
и установите точность
std::cout.precision(std::numeric_limits<double>::max_digits10 - 1);
std::cout << std::scientific << 1.0/7.0 << '\n';
// C++11 Typical output
1.4285714285714285e-01
Слишком много ответов касаются только одного из 1) базового 2) фиксированного/научного макета или 3) точности.Слишком много ответов с точность не обеспечивают нужное значение.Отсюда и этот ответ на старый вопрос.
- Какая база?
А double
безусловно, кодируется с использованием базы 2.Прямой подход к C++11 заключается в печати с использованием std::hexfloat
.
Если недесятичный результат приемлем, то все готово.
std::cout << "hexfloat: " << std::hexfloat << exp (-100) << '\n';
std::cout << "hexfloat: " << std::hexfloat << exp (+100) << '\n';
// output
hexfloat: 0x1.a8c1f14e2af5dp-145
hexfloat: 0x1.3494a9b171bf5p+144
- В противном случае:
fixed
илиscientific
?
А double
это плавающая запятая типа, не фиксированная точка.
Делать нет использовать std::fixed
так как это не позволяет печатать маленькими double
как угодно, только не 0.000...000
.Для больших double
, возможно, он печатает много цифр сотни сомнительной информативности.
std::cout << "std::fixed: " << std::fixed << exp (-100) << '\n';
std::cout << "std::fixed: " << std::fixed << exp (+100) << '\n';
// output
std::fixed: 0.000000
std::fixed: 26881171418161356094253400435962903554686976.000000
Для печати с полной точностью сначала используйте std::scientific
который будет «записывать значения с плавающей запятой в научной записи».Обратите внимание, что по умолчанию 6 цифр после десятичной точки, недостаточное количество, обрабатываются в следующей точке.
std::cout << "std::scientific: " << std::scientific << exp (-100) << '\n';
std::cout << "std::scientific: " << std::scientific << exp (+100) << '\n';
// output
std::scientific: 3.720076e-44
std::scientific: 2.688117e+43
- Какая точность (сколько всего цифр)?
А double
кодированный с использованием двоичной базы 2, кодирует одинаковую точность между различными степенями двойки.Часто это 53 бита.
[1.0...2.0) есть 253 другой double
,
[2.0...4.0) есть 253 другой double
,
[4.0...8.0) есть 253 другой double
,
[8.0...10.0) есть 2/8 * 253 другой double
.
Однако если код печатается в десятичном формате с помощью N
значащие цифры, количество комбинаций [1,0...10,0) равно 9/10 * 10Н.
Что бы ни N
(точность), взаимно однозначного соответствия между double
и десятичный текст. Если фиксированный N
выбран, иногда его будет немного больше или меньше, чем действительно необходимо double
ценности.Мы могли ошибиться слишком мало (a)
ниже) или слишком много (b)
ниже).
3 кандидата N
:
а) Используйте N
поэтому при преобразовании из текста-double
-text мы приходим к одному и тому же тексту для всех double
.
std::cout << dbl::digits10 << '\n';
// Typical output
15
б) Используйте N
поэтому при преобразовании из double
-текст-double
мы приходим к одному и тому же double
для всех double
.
// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17
Когда max_digits10
недоступен, обратите внимание, что из-за атрибутов по основанию 2 и 10, digits10 + 2 <= max_digits10 <= digits10 + 3
, мы можем использовать digits10 + 3
чтобы гарантировать, что будет напечатано достаточное количество десятичных цифр.
в) Используйте N
это зависит от стоимости.
Это может быть полезно, когда код хочет отображать минимальное количество текста (N == 1
) или точный ценность double
(N == 1000-ish
в случае denorm_min
).Однако, поскольку это «работа», а не цель ОП, она будет отложена.
Обычно это b) используется для «печати double
значение с полной точностью».Некоторые приложения могут предпочесть а) ошибку при предоставлении слишком большого количества информации.
С .scientific
, .precision()
устанавливает количество цифр для печати после десятичной точки, поэтому 1 + .precision()
цифры печатаются.Требования к коду max_digits10
общее количество цифр, так что .precision()
вызывается с помощью max_digits10 - 1
.
typedef std::numeric_limits< double > dbl;
std::cout.precision(dbl::max_digits10 - 1);
std::cout << std::scientific << exp (-100) << '\n';
std::cout << std::scientific << exp (+100) << '\n';
// Typical output
3.7200759760208361e-44
2.6881171418161356e+43
printf("%.12f", M_PI);
%.12f означает плавающую запятую с точностью до 12 цифр.
cout — это объект, который имеет множество методов, которые вы можете вызвать, чтобы изменить точность и форматирование печатного материала.
Существует операция setprecision(...), но вы также можете установить другие параметры, например ширину печати и т. д.
Найдите cout в справочнике вашей IDE.
Наиболее портативно...
#include <limits>
using std::numeric_limits;
...
cout.precision(numeric_limits<double>::digits10 + 1);
cout << d;
С ostream::precision(int)
cout.precision( numeric_limits<double>::digits10 + 1);
cout << M_PI << ", " << M_E << endl;
будет давать
3.141592653589793, 2.718281828459045
Почему вам нужно говорить «+1», я понятия не имею, но дополнительная цифра, которую вы получаете, правильная.