如何使用cout以全精度打印双精度值?


Answers:


390

您可以直接设置精度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;

46
为什么您明确建议使用fixed?用double h = 6.62606957e-34;fixed给我0.000000000000000scientific输出6.626069570000000e-34
亚瑟

36
精度需要为17(或std :: numeric_limits <double> :: digits10 + 2),因为从十进制转换回二进制表示形式时需要2个额外的数字以确保将值四舍五入为相同的原始值。这是一篇包含一些详细信息的论文:docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Mike Fisher

8
真的是正确的答案吗?当我手动使用高数,我可以打印多达近似电子商务51位,但cout.precision(numeric_limits<double>::digits10 + 2);我只得到16 ....
Assimilater

6
对于那些希望在@MikeFisher论文中提到17位数字的人,它属于定理15。–
Emile Cormier

15
@MikeFisher是的,C ++ 11引入max_digits10来表示相同的含义。修正了答案以反映这一点。
legends2k

70

用途std::setprecision

std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;

2
是否有某种MAX_PRECISION宏或枚举,或者可以传递给std :: setPrecision的东西?
杰森·普尼扬

2
std :: setprecision(15)为双精度(OK或16),log_10(2 ** 53)〜= 15.9
user7116

14
的std :: setprecision(标准:: numeric_limits <双> :: digits10)
埃里克Malenfant

6
应该是std::setprecision (17)双重的,请参阅有关@Bill The Lizard答案的评论。
亚历克·雅各布森

9
为了使std :: setprecision正常工作,应包括#include <iomanip>。
user2262504

24

这是我会用的:

std::cout << std::setprecision (std::numeric_limits<double>::digits10 + 1)
          << 3.14159265358979
          << std::endl;

基本上,limits包具有所有内置类型的特征。
浮点数字(浮点/双精度/长双精度)的特征之一是digits10属性。这定义了以10为底的浮点数的精度(我忘记了确切的术语)。

请参阅:http : //www.cplusplus.com/reference/std/limits/numeric_limits.html
有关其他属性的详细信息。


12
需要使用此标头std::setprecision()#include <iomanip>
Martin Berger

它应该std::numeric_limits<double>代替numberic_limits<double>
niklasfi

2
为什么你添加1std::numeric_limits<double>::digits10
亚历山德罗·贾科普森

5
@LokiAstari您可以使用C + 11 max_digits10代替。看到这个
legends2k

1
@AlecJacobson应该是 max_digits10,不是任意的digits10+2。否则,在的情况下floatlong doubleboost::multiprecision::float128这将失败,因为你需要+3,而不是+2
罗斯兰

14

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


提升文档说:“对于具有std :: numeric_limits对应专业化的数字,当前版本现在选择匹配的精度”。这似乎是获得最大精度的最简单方法。(boost.org/doc/libs/1_58_0/doc/html/boost_lexical_cast/...
JDiMatteo

11

以全精度,我假设平均精度足以显示与预期值的最佳近似值,但是应该指出的double是,使用基数2表示存储并且基数2不能1.1精确表示。获得全满的唯一方法实际双精度精度(不带ROUND OFF ERROR)是打印出二进制位(或十六进制半字节)。一种方法是double将a 写入a 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;

10

这是显示全精度双精度字的方法:

double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;

显示:

100.0000000000005


max_digits10是唯一表示所有不同的double值所需的位数。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>

4
发生这种情况是因为100.0000000000005未完全以表示double。(看起来好像应该,但是没有,因为它已经标准化,即其二进制表示形式)。要查看此内容,请尝试:100.0000000000005 - 100。我们得到4.973799150320701e-13
Evgeni Sergeev

9

如何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当然是使用base 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. 否则:fixedscientific

A double浮点类型,不是固定点

千万不能使用std::fixed作为打印失败小double,只能作为0.000...000。对于large 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. 多少精度(多少位数)?

一个 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选择什么(精度)double,十进制文本之间都不存在一对一的映射。 如果N选择了一个固定值,有时它会比某些double值的实际需要稍微多一些或少一些。我们可能会因错误(太少(a)以下)或太多(而b)下))而出错。

3名候选人 N

a)N从文本文本double转换时,使用so可以使所有文本都到达相同的文本double

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

b)Ndouble-text- 转换时,请使用so,因此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用来确保打印足够的十进制数字。

c)使用N随值变化的。

当代码要显示最小文本(这可能是有用的N == 1)或确切的值doubleN == 1000-ish在的情况下denorm_min)。然而,由于这是“工作”,而不是OP的目标,因此将其搁置一旁。


通常是b)用于“ double以全精度打印值”。某些应用程序可能更喜欢a)由于没有提供太多信息而出错。

使用.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
//1234567890123456  17 total digits

相似的C问题


好答案!不过,请注意以下几点:正确precision()设置了科学模式的小数位数。如果不指定scientific,它将设置位数(不包括指数)。您可能仍然会根据数字值获得科学的输出结果,但是随后您获得的数字也可能少于指定的数字。示例:的cout.precision(3); cout << 1.7976931348623158e+308; // "1.8e+308"结果printf可能不同。令人困惑的东西应该引起注意。
Simpleton

为了后代,这里是使用printf在科学模式下保证所有双数的精确字符串表示形式所需的缓冲区长度:char buf[DBL_DECIMAL_DIG + 3 + 5]; sprintf(buf, "%.*g", DBL_DECIMAL_DIG, d);额外的字符用于:符号,小数点,尾随零,e [+ |-],指数的3位数字( DBL_MAX_10_EXP = 308)。因此所需的字符的总数目是25。
心眼

无法编辑我的第一条评论,因此我们再继续:科学模式的另一个问题是它可能决定不使用指数输出,甚至可能决定根本不使用浮点输出。也就是说,它将输出1.0作为“ 1”,这在序列化/反序列化上下文中可能是一个问题。您可以使用“%#。* g”强制其输出小数点,但是这样做的缺点是,它添加了多个尾随零,而这并非没有#...
Simpleton

3
printf("%.12f", M_PI);

%.12f表示浮点数,精度为12位数字。


11
这不是“使用cout”。
Johnsyweb

2
12位数字不是“全精度”
Roland Illig

0

最便携的...

#include <limits>

using std::numeric_limits;

    ...
    cout.precision(numeric_limits<double>::digits10 + 1);
    cout << d;

16
我很好奇:为什么要“ +1”?
埃里克·马伦芬(

现在对此进行了投票。
stephanmg

0

使用ostream :: precision(int)

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

将产生

3.141592653589793, 2.718281828459045

为什么您必须说“ +1”我不知道,但是您从中得到的多余数字是正确的。


3
numeric_limits <无符号字符> :: digits10等于2。因为它可以包含两位十进制数字0..99。它还可以包含255 ..但不能包含256、257 ... 300等。这就是为什么digits10不是3的原因!我认为添加“ +1”可以克服这种情况。
Dmitriy Yurchenko

0

这将显示该点后最多两位小数的值。

#include <iostream>
#include <iomanip>

double d = 2.0;
int n = 2;
cout << fixed << setprecison(n) << d;

参见此处: 定点表示法

标准::固定

使用固定浮点表示法将str流的floatfield格式标志设置为固定。

当floatfield设置为固定值时,将使用定点符号写入浮点值:该值用精确字段(precision)指定的小数部分中的位数完全相同,而没有指数部分。

std :: setprecision

设置小数精度设置用于格式化输出操作上的浮点值的小数精度。

如果您熟悉用于表示浮点的IEEE标准,那么您将知道不可能以全精度显示浮点而不超出该标准的范围,也就是说,它将始终导致实际价值的取整。

您需要首先检查该值是否在范围内,如果是,则使用:

cout << defaultfloat << d ;

std :: defaultfloat

使用默认浮点表示法将str流的floatfield格式标志设置为defaultfloat。

当floatfield设置为defaultfloat时,将使用默认表示法写入浮点值:该表示使用所需的尽可能多的有效数字,直到流的小数精度(精度),同时对小数点前后的数字进行计数(如果有) )。

这也是的默认行为cout,这意味着您不会显式使用它。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.