C++ 以防溢出的方式将具有N个有效十进制数字的双精度整数舍入

C++ 以防溢出的方式将具有N个有效十进制数字的双精度整数舍入,c++,rounding,C++,Rounding,我需要一个溢出安全函数,该函数将双精度四舍五入,如std::round,此外,它还可以处理有效小数位数 f、 e 但这很容易溢出 假设IEEE,可以减少溢出的可能性,如下所示 double round(double value, int precision) { // assuming IEEE 754 with 64 bit representation // the number of significant digits varies between 15 and 17

我需要一个溢出安全函数,该函数将
双精度
四舍五入,如
std::round
,此外,它还可以处理有效小数位数

f、 e

但这很容易溢出

假设IEEE,可以减少溢出的可能性,如下所示

double round(double value, int precision)
{
    // assuming IEEE 754 with 64 bit representation
    // the number of significant digits varies between 15 and 17

    precision=std::min(17, precision);
    double factor=pow(10.0, precision);
    return floor(value*factor+0.5)/factor;
}
但这仍然会溢出

即使是这种性能灾难也不起作用

double round(double value, int precision)
{
    std::stringstream ss;
    ss << std::setprecision(precision) << value;
    std::string::size_type sz;
    return std::stod(ss.str(), &sz);
}
round(std::numeric_limits<double>::max(), 2.0) // throws std::out_of_range
双圆(双值,整数精度)
{
std::stringstream-ss;

ss我没有对这段代码进行过大量测试:

/* expects x in (-1, 1) */
double round_precision2(double x, int precision2) {
    double iptr, factor = std::exp2(precision2);
    double y = (x < 0) ? -x : x;
    std::modf(y * factor + .5, &iptr);
    return iptr/factor * ((x < 0) ? -1 : 1);
}

double round_precision(double x, int precision) {
    int bits = precision * M_LN10 / M_LN2;
            /* std::log2(std::pow(10., precision)); */
    double iptr, frac = std::modf(x, &iptr);
    return iptr + round_precision2(frac, bits);
}
/*需要x英寸(-1,1)*/
双圆精度2(双x,整数精度2){
双iptr,系数=std::exp2(精度2);
双y=(x<0)?-x:x;
std::modf(y*系数+0.5和iptr);
返回iptr/系数*((x<0)?-1:1);
}
双圆精度(双x,整数精度){
int位=精度*M_LN10/M_LN2;
/*标准::log2(标准::功率(10,精度))*/
双iptr,frac=std::modf(x,&iptr);
返回iptr+四舍五入精度2(分形,比特);
}
其思想是通过只对数字的小数部分进行操作来避免溢出

我们计算二进制位的数量以达到所需的精度。您应该能够根据您在问题中描述的限制对它们进行限制。 接下来,我们提取数字的小数部分和整数部分。 然后我们将整数部分加回到舍入的小数部分


为了计算舍入的小数部分,我们计算二进制因子。然后我们提取小数部分乘以因子得到的舍入数的整数部分。然后我们通过将整数部分除以因子来返回分数。

你不能。浮点没有小数点,所以你不能舍入到小数点。它是作为二进制的地方,它与小数位数不可通约。如果你想要十进制数字,你必须使用十进制基数。@ USER 20721:我不明白java答案是如何直接对OP的。@ JXH你能通过显示更多细节来将你的评论转换成ANWSER吗?你也可以单独地把这个问题重新当作C++黄金坏。ge所有者。我想知道在溢出的情况下会发生什么?在您的示例中,如果您输入
1.79769e+308
,您会得到
超出范围的
。这是可以表示为浮点的最大数字。将其四舍五入到两位小数是
1.8e+308
。这不能表示为IEEE浮点数字,因为它太大了g、 再加上user207421的答案,我想知道除了输出之外,其他任何东西舍入到小数点位的目的是什么?你永远不会得到所有数字的精确小数点位。你能得到的唯一精确的东西是二进制位。
libgmp
是否有助于解决溢出问题?@DanielJunglas:如果我理解了要求,舍入g是小数位数。由于
1.79769e+308
没有小数部分,因此该值不会更改。我可能误解了您的要求,因此如果需要改进答案,请告诉我。谢谢,不,您没有误解我的要求。请原谅我不够精确。
double round(double value, int precision)
{
    std::stringstream ss;
    ss << std::setprecision(precision) << value;
    std::string::size_type sz;
    return std::stod(ss.str(), &sz);
}
round(std::numeric_limits<double>::max(), 2.0) // throws std::out_of_range
/* expects x in (-1, 1) */
double round_precision2(double x, int precision2) {
    double iptr, factor = std::exp2(precision2);
    double y = (x < 0) ? -x : x;
    std::modf(y * factor + .5, &iptr);
    return iptr/factor * ((x < 0) ? -1 : 1);
}

double round_precision(double x, int precision) {
    int bits = precision * M_LN10 / M_LN2;
            /* std::log2(std::pow(10., precision)); */
    double iptr, frac = std::modf(x, &iptr);
    return iptr + round_precision2(frac, bits);
}