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


当前回答

在这个问题中,有一个关于如何无损地将double类型转换为字符串的描述(在Octave中,但它可以很容易地在c++中重现)。我们的想法是对浮点数有一个人类可读的简短描述和一个十六进制形式的无损描述,例如:pi -> 3.14{54442d18400921fb}。

其他回答

利用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;

在这个问题中,有一个关于如何无损地将double类型转换为字符串的描述(在Octave中,但它可以很容易地在c++中重现)。我们的想法是对浮点数有一个人类可读的简短描述和一个十六进制形式的无损描述,例如:pi -> 3.14{54442d18400921fb}。

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

#include <iostream>
#include <iomanip>

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

看这里:定点符号

std::固定

使用固定浮点符号设置的浮点字段格式标志 STR流的固定。 当floatfield设置为fixed时,将写入浮点值 使用定点表示法:值完全用as表示 由精度字段指定的小数部分中的多个数字 (精度)和无指数部分。

标准::设置精度

Set decimal precision设置格式化时使用的十进制精度 输出操作上的浮点值。

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

您需要首先检查该值是否在作用域内,如果是,则使用:

cout << defaultfloat << d ;

std:: defaultfloat

使用默认浮点符号设置floatfield格式标志 为STR流设置defaultfloat。 当floatfield设置为defaultfloat时,浮点值为 使用默认表示法编写:表示使用尽可能多的表示法 需要的有意义的数字,直到流的十进制精度 (精度),同时计算小数点前后的数字 点(如果有的话)。

这也是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库设置此模式。