如何使用cout输出完整精度的浮点数?

446

在我的之前的问题中,我使用cout打印了一个double,但结果被四舍五入了,而我并不希望它这样。如何让cout以完整精度打印一个double


2
很遗憾,下面的大多数答案都是不正确的。我建议查看 https://dev59.com/dHjZa4cB1Zd3GeqPd25r 代替。 - vitaut
2
请注意,实际上并不存在所谓的“完全”精度。 - Mooing Duck
2
@AlexisWilke 我认为“它可能会以微妙的方式随机地与您的编译器不兼容,而且没有‘好’的解决方法”可以被归类为“非常糟糕”。无论如何,仅仅发布一个“在我的机器上运行良好”的片段,却不暗示一下发生了一些奇怪的事情是次优的。 - Niko O
4
FWIW:这个问题在博客文章中引起了一些关注: https://www.zverovich.net/2023/06/04/printing-double.html - kebs
4
顺便说一句:这个问题在一篇博客文章中引起了一些关注: https://www.zverovich.net/2023/06/04/printing-double.html - undefined
显示剩余4条评论
17个回答

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

%.12f 这个表示浮点数,精度为 12 位小数。


13
这并不是在“使用cout”。 - johnsyweb
3
12位数字并不是“完全精确”的表达。 - Roland Illig

1
最好的选择是使用std::setprecision,解决方案如下:
# include <iostream>
# include <iomanip>

int main()
{
    double a = 34.34322;
    std::cout<<std::fixed<<a<<std::setprecision(0)<<std::endl;
    return 0;
}

注意:您无需使用 cout.setprecision 来执行此操作,我在 std::setprecision 中填充 0 是因为它必须具有一个参数。

根据这个答案,在Apple clang 13.1.6版本中,对于 double pi = 3.141592653589793 ,它会打印出 3.141593 - ChrisZZ

1
这个问题中,有一个关于如何无损地将double转换为字符串的描述(在Octave中,但可以轻松在C ++中重现)。其思想是拥有一个短的人类可读的浮点数描述和一个无损的十六进制形式描述,例如:pi -> 3.14 {54442d18400921fb}。

0

这是一个适用于浮点类型的函数,不仅仅适用于double,而且在执行后还会将流恢复到之前的状态。不幸的是,它无法良好地与线程交互,但这就是iostream的本质。您需要在文件开头包含以下内容:

#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';

-1

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

#include <iostream>
#include <iomanip>

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

请看这里:固定点表示法

std::fixed

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

当 floatfield 设置为 fixed 时,浮点值使用固定点表示法写入:该值用小数部分中指定的精度字段(precision)表示的数字位数完全相同,并且没有指数部分。

std::setprecision

设置十进制精度,以在输出操作中格式化浮点值所使用的十进制精度。

如果您熟悉 IEEE 浮点表示标准,则会知道超出标准范围显示浮点数的全精度是不可能的,也就是说,它总是会导致实际值的四舍五入。

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

cout << defaultfloat << d ;

std::defaultfloat

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

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

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


应该是 setprecision 而不是 setprecison。注意:编辑建议被阻止,因为它包含少于6个字符! - Vincent Vidal

-2

使用 ostream::precision(int)

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

将产生

3.141592653589793, 2.718281828459045

我不知道为什么你要说“+1”,但是它可以得到正确的额外数字。


3
numeric_limits<unsigned char>::digits10 等于 2。因为它可以包含任何两位数的十进制数字,即 0..99。它也可以包含 255.. 但不包括 256、257... 300 等等。这就是为什么 digits10 不是 3!我认为 "+1" 是为了克服这样的问题而添加的。 - Dmitriy Yurchenko

-2

最具可移植性的...

#include <limits>

using std::numeric_limits;

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

18
我很好奇:为什么要加“+1”? - Éric Malenfant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接