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


当前回答

通过完全精度,我假设有足够的精度来显示与预期值的最佳近似值,但应该指出的是,double是使用以2为基数的表示来存储的,以2为基数不能准确地表示像1.1这样微不足道的东西。获得实际双精度(没有舍入错误)的唯一方法是打印出二进制位(或十六进制位)。

一种方法是使用并集将双精度值输入为整数,然后输出整数,因为整数不会受到截断或舍入问题的影响。(c++标准不支持这样的类型双关语,但C中支持。然而,大多数c++编译器可能无论如何都会打印出正确的值。我认为g++支持这一点。)

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;

其他回答

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

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

这是一个适用于任何浮点类型的函数,而不仅仅是双精度浮点类型,它还将流放回之后找到它的方式。不幸的是,它不能很好地与线程交互,但这是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';

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

c++ 20 std::格式

这个伟大的c++库新特性的优点是不会像std::setprecision那样影响std::cout的状态:

#include <format>
#include <string>

int main() {
    std::cout << std::format("{:.2} {:.3}\n", 3.1415, 3.1415);
}

预期的输出:

3.14 3.142

正如https://stackoverflow.com/a/65329803/895245中提到的,如果不显式传递精度,它会打印带有往返保证的最短十进制表示。TODO更详细地了解它与:dbl::max_digits10的比较,如https://stackoverflow.com/a/554134/895245中显示的{:.{}}:

#include <format>
#include <limits>
#include <string>

int main() {
    std::cout << std::format("{:.{}}\n",
        3.1415926535897932384626433, dbl::max_digits10);
}

参见:

返回c++中的默认浮点打印精度,以了解如何恢复pre-c++20中的初始精度 Std::string格式,如sprintf https://en.cppreference.com/w/cpp/utility/format/formatter#Standard_format_specification

利用std::设置精度:

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