【问题标题】:Why does cout truncate a double?为什么 cout 会截断双精度数?
【发布时间】:2013-11-19 06:14:55
【问题描述】:

以下是我的控制台输入/输出。

请输入实数:-23486.33 检查的字符数:9

谢谢。 你输入的实数是-23486.3

我输入的值为 -23486.33,但 cout 将其打印为 -23486.3。 相关代码如下:

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

//  Function prototype (declaration)
string readDouble();
bool isValidDouble(string);

int main()
{
    string value;
    double number;

    value = readDouble();
    while (!isValidDouble(value)) {
        cout << "The number you entered is not a valid integer." << endl;
        value = readDouble();
    }

    number = atof(value.c_str());
    cout << "Thank you." << endl
         << "The real number you entered is " << number << endl;
}

调试时,我在方法调用atof(value.c_str())l; 之后检查数字的值。 Number 显示的值为 -23486.33。那么这和 cout 打印出来之间会发生什么?在我的代码中,我没有设置 cout 的精度或使其固定。

如果您有任何问题,请告诉我。

【问题讨论】:

  • 需要进行一些舍入以避免输出过长。例如,最接近 IEEE 754 64 位二进制到十进制 -23486.33 是 -23486.330000000001746229827404022216796875。这可能就是您的number 的价值。
  • @PatriciaShanahan 但是,在这种情况下,为什么要将我的数字(调试器显示为 -23486.33)修剪为 -23486.3 ?即使这个数字是一个小数位数过多的数字,就像你的例子一样,为什么还要继续修剪掉一组 0 呢?
  • ostream 格式基于宽度和精度,而不是数字的值。相比之下,Java 的 Double toString 将双精度转换为最短的字符串,然后再转换回相同的双精度。它会将您的号码显示为 -23486.33。
  • @PatriciaShanahan 现在说得通了。

标签: c++ double cout


【解决方案1】:

你试过了吗

std::cout << std::setprecision(2) << number;

看看: http://www.cplusplus.com/reference/iomanip/setprecision/

【讨论】:

  • 我见过这个。这将解决这个特定问题,但我需要上面的程序来支持超过 2 个小数位的双精度数。
  • @Mickster37:浮点值以二进制而不是十进制存储,因此某些十进制值仅表示为二进制的近似值。您将无法使用float 或double 读取和写入精确的十进制数字。
  • @Mickster:特别是-23486.3和-23486.30没有区别
  • @dreamlax 我明白了。如果我的数字有很多小数位,我就不会期望一个精确的小数,但是对于小数位很少的数字仍然是这种情况吗?
  • @MSalters 没有,但 -23486.33 和 -23486.3 之间存在差异
【解决方案2】:

在输出双精度时设置精度,在比较它们时显式保持精度。

当您将 DEC 数字的字符串表示形式转换为双精度(浮点数表示形式)时,内存中的数据在数学上可能不等于字符串表示形式。这是浮点数表示的最佳近似值,反之亦然。

【讨论】:

  • 可以理解。但是,正如我在原始帖子中所指出的,当使用调试器检查“数字”的值时,我显示 -23486.33 但它会打印出 -23486.3 。在我看来,打印出浮点数时会发生精度损失,而不是从字符串转换为浮点数时。
  • @Mickster37 内存中的数据可能不仅仅是-23486.33。它可能类似于 -23486.3300000000002。该程序不知道您想要的精度(用于输出)。所以它为你决定。
  • 这很有意义。很好的解释。
【解决方案3】:

-23486.3 被显示,因为std::cout 默认只打印 6 位数字。

要打印从标准输入中输入的数字(转换文本 → 浮点数 → 文本),您可以使用 set_precision 和 digits10 作为精度:

double d = -23486.33;
int precision = std::numeric_limits<double>::digits10;
std::cout << std::setprecision(precision) << d << std::endl;

这显示:

-23486.33


要打印一个全精度的数字(通常用于转换浮点数→文本→浮点数),您可以使用set_precision和max_digits10作为精度:

double d = -23486.33;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;

这显示:

-23486.330000000002

这里打印的数字不一样,因为 -23486.33 在 IEEE 编码中没有精确的表示(以基数 2 而非基数 10 表示)。


更多详情digits10和max_digits10,你可以阅读:

【讨论】:

    【解决方案4】:

    您可以将精度设置为 double 的最大限制。

    代码sn-p在这里:

    #include <iostream>
    #include <limits>
    #include <iomanip>
    
    using namespace std;
    double number = ... // your double value.
    cout << setprecision(numeric_limits<double>::digits10) << number << endl; 
    

    【讨论】:

    • 这到底是做什么的?更多 cmets 会有所帮助。
    • @Mickster37 它将精度设置为 double 的最大限制,并固定为格式说明符,可以修剪不需要的 0s
    • 非常有用的代码 sn-p!我正在向其他人提供正确答案,尽管他们更直接地回答了这个问题。谢谢。
    • @DanielLaügt 嗨 Daniel,setprecision 设置小数点前后数字的精度。通过-23456.111111119112345和-123456.111111119112345这两个数字很容易测试,它们将分别是-23456.1111111191和-123456.111111119。
    • @DanielLaügt 是的,应该删除固定的。
    猜你喜欢
    • 2019-03-13
    • 1970-01-01
    • 1970-01-01
    • 2020-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-18
    • 2012-11-10
    相关资源
    最近更新 更多