检查c ++中的零或非规范化数字

A-A*_*A-A 5 c++ divide-by-zero

我目前有一些代码,我必须规范化双精度矢量(将每个元素除以总和).在调试时,我有时会看到向量中的元素都是0.0.如果我然后得到元素的总和,我得到0.0或4.322644347104e-314 #DEN(我最近发现的是非规范化数字).当sum为0.0或非规格化数时,我想阻止对情形进行归一化.我能想到处理这两种情况的唯一方法是检查总和是否小于'epsilon',其中epsilon是一个小数字(但我不确定制作epsilon有多小).

我有两个问题:

  1. 考虑这些案例的最佳方法是什么?
  2. 非规范化数字机器的值是否依赖?

Dav*_*men 9

#include <limits>
#include <cmath>
double epsilon = std::numeric_limits<double>::min();
if (std::abs(sum) < epsilon) {
  // Don't divide by sum.
}
else {
  // Scale vector components by sum.
}
Run Code Online (Sandbox Code Playgroud)

附录
因为你试图规范化矢量,我会冒险你的总和是矢量元素的平方和,概念上

double sum = 0;
for (unsigned int ii = 0; ii < vector_size; ++ii) {
    sum += vector[ii]*vector[ii];
}
sum = std::sqrt(sum);
Run Code Online (Sandbox Code Playgroud)

上面有三个问题.

  1. 如果这些矢量分量中的任何一个在幅度上大于sqrt(max_double)你将获得无穷大.
  2. 如果这些矢量分量中的任何一个在幅度上小于sqrt(min_double)您将获得下溢.
  3. 即使数字表现良好(幅度在2*10 -154和10 154之间),如果幅度变化很大(上述因素为10 6),上述情况也会出现问题.如果是这种情况,您需要更复杂的斜边函数.


Luc*_*ton 8

C99提供fpclassify检测非规范化数字.它还提供了C++ 0x和Boost.Math.

// C++0x
#include <cmath>
using std::fpclassify;

// Boost
//#include <boost/math/special_functions/fpclassify.hpp>
//using boost::math::fpclassify;

if(fpclassify(sum) == FP_SUBNORMAL) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)