【问题标题】:Avoid rounding when inserting double to stringstream将双精度插入字符串流时避免舍入
【发布时间】:2016-06-21 13:05:06
【问题描述】:

我正在使用此函数将双精度 f 转换为小数点后带有 p 数字的字符串。

static std::string doubleToString(double f, int p)
{
        std::stringstream ss;
        ss << std::fixed << std::setprecision(p) << f;
        std::string s = ss.str();                                   
        s.erase(s.find_last_not_of('0') + 1, std::string::npos);    
        return (s[s.size()-1] == '.') ? s.substr(0, s.size()-1) : s;
}

最后的剩余 0 被删除。例如1.23000 得到1.23

输入:

double test1 = 1;
double test2 = 1.12345678;
double test3 = 1.123456789010;

std::cout << doubleToString(test1, 8) << " " << doubleToString(test2, 8) << " " << doubleToString(test3, 8);

输出:

1 1.12345678 1.12345679

如您所见,test1test2 打印良好。 test3 但是在第 8 位之后被四舍五入。我想避免这种情况并“削减”其余数字,以便:doubleToString(1.123456789010, 8) 返回1.12345678

最有效的方法是什么?

【问题讨论】:

  • 你为什么不找.,把&lt;position of . &gt; + 8之后的所有东西都删掉?
  • 您依赖第 8 位的精确值但仍想使用浮点类型是有原因的?
  • @GMichael 我认为舍入发生在这一行:ss &lt;&lt; std::fixed &lt;&lt; std::setprecision(p) &lt;&lt; f;。在此之前,我没有可以在其中查找“。”的字符串。之后,字符串的长度已经为p。 @Warren P 是的,这是有原因的。它必须是精确的和浮点的。

标签: c++ floating-point double rounding


【解决方案1】:

对你的函数做一个小的修改就可以了;只需将一些额外的数字放入流中,并在转换后将它们删除。您需要允许 some 舍入,因为二进制值可能略小于您期望的十进制值。在下面的代码中,我将字符串转换限制为 14 位数字,这大约是 IEEE double 介于 1.0 和 10.0 之间的最大值;如果您期望的值大于此值,则需要调整算法,因为小数点后的准确位数会减少。

std::string doubleToString(double f, int p)
{
    std::stringstream ss;
    int p2 = min(p + 2, 14);
    ss << std::fixed << std::setprecision(p2) << f;
    std::string s = ss.str();
    size_t point = s.find('.');
    if (point != std::string::npos && point + 1 + p < s.size())
        s.erase(point + 1 + p);
    s.erase(s.find_last_not_of('0') + 1, std::string::npos);
    return (s[s.size()-1] == '.') ? s.substr(0, s.size()-1) : s;
}

http://ideone.com/xGoDiH查看它的实际应用。

【讨论】:

    【解决方案2】:

    你可以试试:

    doubleToString( ( test3 - ( 0.5 / ( pow( 10, 8 ) ) ) ), 8 )
    

    这不是一个明确的解决方案,但应该做你想做的。

    编辑: 它只是从你的数字中减去 0.000000005,所以它没有四舍五入。您可以将它添加到您的函数中,它将对每个数字执行此操作:

    static std::string doubleToString(double f, int p)
    {
        std::stringstream ss;
        ss << std::fixed << std::setprecision(p) << (f - (0.5 / (pow(10, p))));
        std::string s = ss.str();                                   
        s.erase(s.find_last_not_of('0') + 1, std::string::npos);    
        return (s[s.size()-1] == '.') ? s.substr(0, s.size()-1) : s;
    }
    

    【讨论】:

    • 谢谢,不过我想直接集成到函数中
    猜你喜欢
    • 2019-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    • 1970-01-01
    • 1970-01-01
    • 2020-06-25
    相关资源
    最近更新 更多