在我之前的问题中,我打印了一个double using cout,当我没有预料到它时,它变得圆润了。我如何才能使cout打印一个双重使用全精度?
当前回答
IEEE 754浮点值使用2进制表示存储。任何以2为底的数字都可以表示为精确的十进制(以10为底)。然而,提出的答案中没有一个是这样的。它们都截断了十进制值。
这似乎是由于曲解std::numeric_limits<T>::max_digits10表示:
std::numeric_limits<T>::max_digits10的值是唯一表示T类型的所有不同值所必需的以10为基数的数字的数量。
换句话说:如果您希望在不丢失任何信息的情况下,从二进制到十进制再到二进制进行往返,则输出所需的位数(最坏情况)。如果输出至少max_digits10个小数并重新构造一个浮点值,则可以保证得到与开始时完全相同的二进制表示。
What's important: max_digits10 in general neither yields the shortest decimal, nor is it sufficient to represent the full precision. I'm not aware of a constant in the C++ Standard Library that encodes the maximum number of decimal digits required to contain the full precision of a floating point value. I believe it's something like 767 for doubles1. One way to output a floating point value with full precision would be to use a sufficiently large value for the precision, like so2, and have the library strip any trailing zeros:
#include <iostream>
int main() {
double d = 0.1;
std::cout.precision(767);
std::cout << "d = " << d << std::endl;
}
这将产生以下输出,其中包含完整的精度:
d = 0.1000000000000000055511151231257827021181583404541015625
注意,这比max_digits10建议的数字要多得多。
While that answers the question that was asked, a far more common goal would be to get the shortest decimal representation of any given floating point value, that retains all information. Again, I'm not aware of any way to instruct the Standard I/O library to output that value. Starting with C++17 the possibility to do that conversion has finally arrived in C++ in the form of std::to_chars. By default, it produces the shortest decimal representation of any given floating point value that retains the entire information.
它的接口有点笨拙,你可能想把它包装成一个函数模板,返回一些你可以输出到std::cout(像std::string)的东西,例如。
#include <charconv>
#include <array>
#include <string>
#include <system_error>
#include <iostream>
#include <cmath>
template<typename T>
std::string to_string(T value)
{
// 24 characters is the longest decimal representation of any double value
std::array<char, 24> buffer {};
auto const res { std::to_chars(buffer.data(), buffer.data() + buffer.size(), value) };
if (res.ec == std::errc {})
{
// Success
return std::string(buffer.data(), res.ptr);
}
// Error
return { "FAILED!" };
}
int main()
{
auto value { 0.1f };
std::cout << to_string(value) << std::endl;
value = std::nextafter(value, INFINITY);
std::cout << to_string(value) << std::endl;
value = std::nextafter(value, INFINITY);
std::cout << to_string(value) << std::endl;
}
这将打印出(使用微软的c++标准库):
0.1
0.10000001
0.10000002
1摘自Stephan T. Lavavej的CppCon 2019演讲,题为《浮点<charconv>:用c++ 17的Final Boss让你的代码快10倍》。(整个演讲都值得一看。)
2这也需要使用scientific和fixed的组合,以较短者为准。我不知道如何使用c++标准I/O库设置此模式。
其他回答
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
printf("%.12f", M_PI);
%。12f表示浮点数,精度为12位。
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::设置精度:
#include <iomanip>
std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
你可以直接在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;