Как вывести двойное значение с полной точностью, используя cout? - PullRequest
292 голосов
/ 16 февраля 2009

Итак, я получил ответ на мой последний вопрос (не знаю, почему я об этом не подумал). Я печатал double, используя cout, который округлился, когда я этого не ожидал. Как я могу заставить cout печатать double с полной точностью?

Ответы [ 11 ]

347 голосов
/ 16 февраля 2009

Вы можете установить точность непосредственно на std::cout и использовать спецификатор формата std::fixed.

double d = 3.14159265358979;
cout.precision(17);
cout << "Pi: " << fixed << d << endl;

Вы можете #include <limits> получить максимальную точность поплавка или удвоения.

#include <limits>

typedef std::numeric_limits< double > dbl;

double d = 3.14159265358979;
cout.precision(dbl::max_digits10);
cout << "Pi: " << d << endl;
60 голосов
/ 16 февраля 2009

Использование std::setprecision:

std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
23 голосов
/ 17 февраля 2009

Вот что я бы использовал:

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
Подробнее о других атрибутах.

13 голосов
/ 05 августа 2011

Путь 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;

Выход:

Pi: 3,14159265358979

10 голосов
/ 01 января 2016

Вот как отобразить двойной с полной точностью:

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>
9 голосов
/ 24 октября 2015

Под полной точностью я предполагаю достаточную точность, чтобы показать наилучшее приближение к предполагаемому значению, но следует отметить, что double хранится с использованием представления базы 2, а база 2 не может представлять что-то тривиальное, как 1002 * точно. Единственный способ получить точность full-full для фактического значения double (без NO ROUND OFF ERROR) - это распечатать двоичные биты (или шестнадцатеричные биты). Один из способов сделать это - записать 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;
4 голосов
/ 12 сентября 2018

Как напечатать значение 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) точности. Слишком много ответов с точность не дают нужного значения. Отсюда и ответ на старый вопрос.

  1. Какая база?

A 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

  1. В противном случае: fixed или scientific?

A 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

  1. Сколько точности (сколько всего цифр)?

A double, закодированный с использованием двоичной базы 2, кодирует одинаковую точность между различными степенями 2. Часто это 53 бита.

[1.0 ... 2.0) есть 2 53 разные double,
[2.0 ... 4.0) есть 2 53 разные double,
[4.0 ... 8.0) Есть 2 53 разные double,
[8,0 ... 10,0) 2/8 * 2 53 разные double.

Тем не менее, если код печатается в десятичном виде с N значащими цифрами, количество комбинаций [1,0 ... 10,0) составляет 9/10 * 10 N .

Независимо от выбранной N (точности) не будет однозначного сопоставления между double и десятичным текстом. Если выбран фиксированный N, иногда это будет быть немного больше или меньше, чем нужно для определенных значений double. Мы можем ошибиться из-за слишком малого (a) ниже) или слишком большого количества (b) ниже).

3 кандидата N:

a) Используйте N, чтобы при преобразовании из текстового текста double мы получали один и тот же текст для всех double.

std::cout << dbl::digits10 << '\n';
// Typical output
15

b) Используйте N, поэтому при конвертации из double -text- double мы получаем одинаковое double для всех double.

// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17

Когда max_digits10 недоступен, обратите внимание, что из-за атрибутов base 2 и base 10, digits10 + 2 <= max_digits10 <= digits10 + 3, мы можем использовать digits10 + 3, чтобы обеспечить печать достаточного количества десятичных цифр.

в) Используйте N, который зависит от значения.

Это может быть полезно, когда код хочет отобразить минимальный текст (N == 1) или точное значение double (N == 1000-ish в случае denorm_min). Тем не менее, поскольку это «работа» и маловероятная цель ОП, она будет отложена.


Обычно б) используется для «печати значения 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

Аналогичный вопрос C

3 голосов
/ 24 января 2010
printf("%.12f", M_PI);

%. 12f означает с плавающей запятой с точностью до 12 цифр.

1 голос
/ 16 февраля 2009

cout - это объект, который имеет набор методов, которые можно вызывать для изменения точности и форматирования печатных материалов.

Существует операция setprecision (...), но вы также можете установить другие параметры, такие как ширина печати и т. Д.

Посмотрите на cout в справочнике вашей IDE.

0 голосов
/ 11 августа 2009

С ostream :: precision (int)

cout.precision( numeric_limits<double>::digits10 + 1);
cout << M_PI << ", " << M_E << endl;

даст

3.141592653589793, 2.718281828459045

Почему вы должны сказать "+1", я понятия не имею, но дополнительная цифра, которую вы получаете из нее, верна.

...