在我之前的问题中,我打印了一个double using cout,当我没有预料到它时,它变得圆润了。我如何才能使cout打印一个双重使用全精度?


当前回答

我如何打印一个双值与全精度使用cout?

使用六漂或 使用科学,设定精度

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

否则:是固定的还是科学的?

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

有多少精度(总共有多少位数字)?

使用二进制基数2的双精度编码在2的各种幂之间编码相同的精度。通常是53位。

[1.0…2.0)有253种不同的双, [2.0…4.0)有253种不同的双, [4.0…8.0)有253种不同的双, [8.0…10.0)有2/8 * 253个不同的双。

然而,如果代码以N位有效数字的十进制方式打印,则组合的数量[1.0…10.0)为9/10 * 10N。

无论选择什么N(精度),在双精度文本和十进制文本之间都不会有一对一的映射。如果选择一个固定的N,有时它会略多于或少于某些双精度值的实际需要。我们可能会因为太少(下面a)或太多(下面b)而出错。

3候选人N:

a)使用N,当从文本-双-文本转换时,我们会得到相同的文本。

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不可用时,请注意,由于以2为基数和以10为基数的属性,digits10 + 2 <= max_digits10 <= digits10 + 3,我们可以使用digits10 + 3来确保打印足够多的十进制数字。

c)使用随数值变化的N。

当代码想要显示最小文本(N == 1)或精确的double值(在denorm_min的情况下N == 1000-ish)时,这可能很有用。然而,由于这是“工作”,不太可能是OP的目标,它将被搁置一边。


通常是b)用于“完全精确地打印双精度值”。有些应用程序可能倾向于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
//2345678901234567  17 total digits

相似的C题

其他回答

这是一个适用于任何浮点类型的函数,而不仅仅是双精度浮点类型,它还将流放回之后找到它的方式。不幸的是,它不能很好地与线程交互,但这是iostreams的本质。你需要在文件的开头包含以下内容:

#include <limits>
#include <iostream>

这是这个函数,如果你经常使用它,你可以把它放在头文件中:

template <class T>
void printVal(std::ostream& os, T val)
{
    auto oldFlags = os.flags();
    auto oldPrecision = os.precision();

    os.flags(oldFlags & ~std::ios_base::floatfield);
    os.precision(std::numeric_limits<T>::digits10);
    os << val;
    
    os.flags(oldFlags);
    os.precision(oldPrecision);
}

像这样使用它:

double d = foo();
float f = bar();
printVal(std::cout, d);
printVal(std::cout, f);

如果你想使用普通的插入<<操作符,你可以使用额外的包装器代码:

template <class T>
struct PrintValWrapper { T val; };
template <class T>
std::ostream& operator<<(std::ostream& os, PrintValWrapper<T> pvw) {
    printVal(os, pvw.val);
    return os;
}
template <class T>
PrintValWrapper<T> printIt(T val) {
    return PrintValWrapper<T>{val};
}

现在你可以这样使用它:

double d = foo();
float f = bar();
std::cout << "The values are: " << printIt(d) << ", " << printIt(f) << '\n';

我如何打印一个双值与全精度使用cout?

使用六漂或 使用科学,设定精度

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

否则:是固定的还是科学的?

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

有多少精度(总共有多少位数字)?

使用二进制基数2的双精度编码在2的各种幂之间编码相同的精度。通常是53位。

[1.0…2.0)有253种不同的双, [2.0…4.0)有253种不同的双, [4.0…8.0)有253种不同的双, [8.0…10.0)有2/8 * 253个不同的双。

然而,如果代码以N位有效数字的十进制方式打印,则组合的数量[1.0…10.0)为9/10 * 10N。

无论选择什么N(精度),在双精度文本和十进制文本之间都不会有一对一的映射。如果选择一个固定的N,有时它会略多于或少于某些双精度值的实际需要。我们可能会因为太少(下面a)或太多(下面b)而出错。

3候选人N:

a)使用N,当从文本-双-文本转换时,我们会得到相同的文本。

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不可用时,请注意,由于以2为基数和以10为基数的属性,digits10 + 2 <= max_digits10 <= digits10 + 3,我们可以使用digits10 + 3来确保打印足够多的十进制数字。

c)使用随数值变化的N。

当代码想要显示最小文本(N == 1)或精确的double值(在denorm_min的情况下N == 1000-ish)时,这可能很有用。然而,由于这是“工作”,不太可能是OP的目标,它将被搁置一边。


通常是b)用于“完全精确地打印双精度值”。有些应用程序可能倾向于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
//2345678901234567  17 total digits

相似的C题

最轻松的……

#include <limits>

using std::numeric_limits;

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

你可以直接在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;

利用std::设置精度:

#include <iomanip>
std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;