在我之前的问题中,我打印了一个double using cout,当我没有预料到它时,它变得圆润了。我如何才能使cout打印一个双重使用全精度?
当前回答
最好的选择是使用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。我在std::setprecision处填充0,因为它必须有一个参数。
其他回答
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
最轻松的……
#include <limits>
using std::numeric_limits;
...
cout.precision(numeric_limits<double>::digits10 + 1);
cout << d;
通过完全精度,我假设有足够的精度来显示与预期值的最佳近似值,但应该指出的是,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;
在c++ 20中,你可以使用std::format来做到这一点:
std::cout << std::format("{}", M_PI);
输出(假设双IEEE754):
3.141592653589793
默认浮点格式是具有往返保证的最短十进制表示形式。与setprecision I/O操纵符相比,这种方法的优点是它不会打印不必要的数字。
在此期间,您可以使用{fmt}库,std::format是基于。{fmt}还提供了print函数,使这更容易和更有效(godbolt):
fmt::print("{}", M_PI);
免责声明:我是{fmt}和c++ 20 std::format的作者。
这是一个适用于任何浮点类型的函数,而不仅仅是双精度浮点类型,它还将流放回之后找到它的方式。不幸的是,它不能很好地与线程交互,但这是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';