将 double 插入到 stringstream 时避免舍入

Avoid rounding when inserting double to stringstream

我正在使用此函数将双精度 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 位数字后四舍五入。我想避免那个和 "cut" 其余数字,因此:doubleToString(1.123456789010, 8) returns 1.12345678

最有效的方法是什么?

你可以试试:

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;
}

对您的功能稍作修改即可完成工作;只需将一些额外的数字放入流中,并在转换后将其删除。您需要允许 some 舍入,因为二进制值可能略小于您期望的十进制值。在我下面的代码中,我将字符串转换限制为 14 位数字,这大约是您可以从 1.0 到 10.0 之间的 IEEE 双精度数期望的最大值;如果您期望值大于此值,则需要调整算法,因为小数点后的准确位数会减少。

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 查看它的运行情况。