don't assert when suming numbers with negative infinity

This commit is contained in:
Tiago Gomes 2012-04-13 23:12:12 +01:00
parent 24a5fe9c23
commit f6e3bb4481
1 changed files with 23 additions and 14 deletions

View File

@ -153,30 +153,39 @@ std::ostream& operator << (std::ostream& os, const vector<T>& v)
namespace { namespace {
const double INF = -numeric_limits<double>::infinity(); const double NEG_INF = -numeric_limits<double>::infinity();
}; };
inline double inline double
Util::logSum (double x, double y) Util::logSum (double x, double y)
{ {
return log (exp (x) + exp (y)); // std::log (std::exp (x) + std::exp (y)) can overflow!
assert (isfinite (x) && isfinite (y)); assert (std::isnan (x) == false);
// If one value is much smaller than the other, keep the larger value. assert (std::isnan (y) == false);
if (x < (y - log (1e200))) { if (x == NEG_INF) {
return y; return y;
} }
if (y < (x - log (1e200))) { if (y == NEG_INF) {
return x; return x;
} }
double diff = x - y; // if one value is much smaller than the other,
assert (isfinite (diff) && isfinite (x) && isfinite (y)); // keep the larger value
if (!isfinite (exp (diff))) { const double tol = 460.517; // log (1e200)
if (x < y - tol) {
return y;
}
if (y < x - tol) {
return x;
}
assert (std::isnan (x - y) == false);
const double exp_diff = std::exp (x - y);
if (std::isfinite (exp_diff) == false) {
// difference is too large // difference is too large
return x > y ? x : y; return x > y ? x : y;
} }
// otherwise return the sum. // otherwise return the sum
return y + log (static_cast<double>(1.0) + exp (diff)); return y + std::log (static_cast<double>(1.0) + exp_diff);
} }
@ -252,14 +261,14 @@ one()
inline double inline double
zero() { zero() {
return Globals::logDomain ? INF : 0.0 ; return Globals::logDomain ? NEG_INF : 0.0 ;
} }
inline double inline double
addIdenty() addIdenty()
{ {
return Globals::logDomain ? INF : 0.0; return Globals::logDomain ? NEG_INF : 0.0;
} }
@ -279,7 +288,7 @@ withEvidence()
inline double inline double
noEvidence() { noEvidence() {
return Globals::logDomain ? INF : 0.0; return Globals::logDomain ? NEG_INF : 0.0;
} }