繁体   English   中英

如何删除C ++中浮点数的最后有效数字/尾数位

[英]How to remove last significant digits/mantissa bits for floating numbers in C++

我想以有效的方式删除C ++中浮点数的最后2或3位有效数字。 为了更准确地表达问题 - 我想在浮点数表示中丢弃最后几个尾数位。

一些背景:我可以使用不同的方式到达相同的浮点数。 例如,如果我在矩形中使用双线性插值,其角点中的值相等,则由于机器精度限制,结果将在矩形的不同点中的最后几位数中变化。 这些偏差的绝对顺序取决于内插值的顺序。 例如,如果p [i] ~1e10(i == 1..4,矩形角处的值),则由机器精度引起的插值误差为~1e-4(对于8字节浮点数)。 如果p [i] ~1e-10那么误差将是~1e-24。 由于插值用于计算一阶或二阶导数,我需要“平滑”这些差异。 一个想法是从最终结果中删除最后几位数字。 以下是我的看法:

#include <iostream>     // std::cout
#include <limits>       // std::numeric_limits
#include <math.h>       // fabs

template<typename real>
real remove_digits(const real& value, const int num_digits)
{
  //return value;
  if (value == 0.) return 0;
  const real corrector_power =
       (std::numeric_limits<real>::digits10 - num_digits)
                               - round(log10(fabs(value)));

  //the value is too close to the limits of the double minimum value
  //to be corrected -- return 0 instead.
  if (corrector_power > std::numeric_limits<real>::max_exponent10 -
                        num_digits - 1)
  {
    return 0.;
  }
  const real corrector = pow(10, corrector_power);
  const real result =
     (value > 0) ? floor(value * corrector + 0.5) / corrector :
                    ceil(value * corrector - 0.5) / corrector;
  return result;
}//remove_digits

int main() {
  // g++ (Debian 4.7.2-5) 4.7.2 --- Debian GNU/Linux 7.8 (wheezy) 64-bit
  std::cout << remove_digits<float>(12345.1234, 1) << std::endl;  // 12345.1
  std::cout << remove_digits<float>(12345.1234, 2) << std::endl;  // 12345
  std::cout << remove_digits<float>(12345.1234, 3) << std::endl;  // 12350
  std::cout << std::numeric_limits<float>::digits10 << std::endl; // 6
}

它工作,但使用2个昂贵的操作 - log10和pow。 有更聪明的方法吗? 如上所述为实现我的目标,我不需要删除实际的十进制数字,而只需将浮点数的尾数表示中的3-4位设置为0。

“一些背景:我可以用不同的方式到达相同的浮点数。”

那不是问题。 “本地”分辨率近x近似x-std::next_after(x,0.0)其在宽范围内是线性x p[i]变化20个数量级的问题无关紧要,因为相对误差随p[i]线性变化,这意味着它也会随第一个表达式线性变化。

更一般地说,如果要比较ab是否足够相似,只需测试a/b是否约为1.00000000 (当b完全为零时,你有更大的问题 - 没有任何有意义的方式来说明1E-10是否“几乎等于”0)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM