【问题标题】:Doubles rounding again双打再次四舍五入
【发布时间】:2016-01-27 15:02:44
【问题描述】:

在我的程序中,某些双精度数有一些精度(一些正整数,在大多数情况下应该是 的形式),因此double * precision 应该成为一个整数。

但是众所周知浮点数是不准确的,所以,例如1.3029515可以保存为1.3029514999999998...,在我的程序中我需要将这样的浮点数写入文件,但我想要这个@ 987654327@ 代替 1.3029514999999998... 之类的东西。

以前在我的程序中只使用了 形式的精度,而我已经通过如下代码达到了想要的结果:

// I have a function for doubles equality check
inline bool sameDoubles(const double& lhs, const double& rhs, const double& epsilon) {
    return fabs(lhs - rhs) < epsilon;
}

inline void roundDownDouble(double& value, const unsigned int& numberOfDigitsInFraction = 6) {
    assert(numberOfDigitsInFraction <= 9);
    double factor = pow(10.0, numberOfDigitsInFraction);
    double oldValue = value;
    value = (((int)(value * factor)) / factor);
    // when, for example, 1.45 is stored as 1.4499999999..., we can get wrong value, so, need to do the check below
    double diff = pow(10.0, 0.0 - numberOfDigitsInFraction);
    if(sameDoubles(diff, fabs(oldValue - value), 1e-9)) {
        value += diff;
    }
};

但是现在,我无法使用相同的技术达到想要的结果,我尝试了以下功能,但没有成功:

// calculates logarithm of number with given base
double inline logNbase(double number, double base) {
    return log(number)/log(base);
}

// sameDoubles function is the same as in above case

inline void roundDownDouble(double& value, unsigned int precision = 1e+6) {
    if(sameDoubles(value, 0.0)) { value = 0; return; }
    double oldValue = value;
    value = ((long int)(value * precision) / (double)precision);
    // when, for example, 1.45 is stored as 1.4499999999..., we can get wrong value, so, need to do the check below
    int pwr = (int)(logNbase((double)precision, 10.0));
    long int coeff = precision / pow(10, pwr);
    double diff = coeff * pow(10, -pwr);
    if(sameDoubles(diff, fabs(oldValue - value),  diff / 10.0)) {
        if(value > 0.0) {
            value += diff;
        } else {
            value -= diff;
        }
    }
}

对于1.3029515 值和precision = 2000000,此函数返回不正确的1.302951 值(表达式(long int)(value * precision) 变为等于2605902 而不是2605903)。

我该如何解决这个问题?或者也许有一些聪明的方法可以使这种舍入正确发生?

【问题讨论】:

  • expression (long int)(value * precision) becomes equal to 2605902 instead of 2605903 Can't reproduce
  • 浮点数总是不准确,除非出于某种巧合,它们可以写成 2 的幂之和。例如 0.5 或 0.025,但绝不是 0.1。自己重新生成数字并不会改变这一点,它会使情况变得更糟,因为您添加了计算错误。如果你想公开快乐的整数,那么你必须写 strings.
  • 浮点数并非不准确。从字符表示到浮点值的转换通常是不准确的;可以表示为字符序列的值比浮点值多得多。但是,当然,实数的数量也远多于实数的文本表示,所以如果你喜欢说浮点表示不准确,你也可以说数字的文本表示不准确。跨度>
  • @IgorTandetnik,我也无法在一个小测试用例上重现它,实际上在我的大程序中达到了这种情况,我正在从文件中读取双精度并做很多其他的东西.

标签: c++ double rounding c++98


【解决方案1】:

您正在艰难地进行四舍五入。改用简单的方法:

double rounding = 0.5;
if (value < 0.0) rounding = -0.5;
value = ((long int)(value * precision + rounding) / (double)precision);

现在不需要剩下的代码了。

【讨论】:

  • 我测试了it,并没有得到预期的结果。
  • 但您对其余代码的建议似乎工作正常。
猜你喜欢
  • 2016-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-12
  • 2012-08-04
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多