#ifndef LOGVAL_H_ #define LOGVAL_H_ #define LOGVAL_CHECK_NEG false #include #include #include #include #include template class LogVal { public: LogVal() : s_(), v_(-std::numeric_limits::infinity()) {} explicit LogVal(double x) : s_(std::signbit(x)), v_(s_ ? std::log(-x) : std::log(x)) {} LogVal(int x) : s_(x<0), v_(s_ ? std::log(-x) : std::log(x)) {} LogVal(unsigned x) : s_(0), v_(std::log(x)) { } LogVal(double lnx,bool sign) : s_(sign),v_(lnx) {} static LogVal exp(T lnx) { return LogVal(lnx,false); } static LogVal One() { return LogVal(1); } static LogVal Zero() { return LogVal(); } static LogVal e() { return LogVal(1,false); } void logeq(const T& v) { s_ = false; v_ = v; } std::size_t hash_impl() const { using namespace boost; return hash_value(v_)+s_; } LogVal& operator+=(const LogVal& a) { if (a.v_ == -std::numeric_limits::infinity()) return *this; if (a.s_ == s_) { if (a.v_ < v_) { v_ = v_ + log1p(std::exp(a.v_ - v_)); } else { v_ = a.v_ + log1p(std::exp(v_ - a.v_)); } } else { if (a.v_ < v_) { v_ = v_ + log1p(-std::exp(a.v_ - v_)); } else { v_ = a.v_ + log1p(-std::exp(v_ - a.v_)); s_ = !s_; } } return *this; } LogVal& operator*=(const LogVal& a) { s_ = (s_ != a.s_); v_ += a.v_; return *this; } LogVal& operator/=(const LogVal& a) { s_ = (s_ != a.s_); v_ -= a.v_; return *this; } LogVal& operator-=(const LogVal& a) { LogVal b = a; b.invert(); return *this += b; } // LogVal(fabs(log(x)),x.s_) friend LogVal abslog(LogVal x) { if (x.v_<0) x.v_=-x.v_; return x; } LogVal& poweq(const T& power) { #if LOGVAL_CHECK_NEG if (s_) { std::cerr << "poweq(T) not implemented when s_ is true\n"; std::abort(); } else #endif v_ *= power; return *this; } void invert() { s_ = !s_; } LogVal pow(const T& power) const { LogVal res = *this; res.poweq(power); return res; } LogVal root(const T& root) const { return pow(1/root); } operator T() const { if (s_) return -std::exp(v_); else return std::exp(v_); } bool s_; T v_; }; // copy elision - as opposed to explicit copy of LogVal const& o1, we should be able to construct Logval r=a+(b+c) as a single result in place in r. todo: return std::move(o1) - C++0x template LogVal operator+(LogVal o1, const LogVal& o2) { o1 += o2; return o1; } template LogVal operator*(LogVal o1, const LogVal& o2) { o1 *= o2; return o1; } template LogVal operator/(LogVal o1, const LogVal& o2) { o1 /= o2; return o1; } template LogVal operator-(LogVal o1, const LogVal& o2) { o1 -= o2; return o1; } template T log(const LogVal& o) { #ifdef LOGVAL_CHECK_NEG if (o.s_) return log(-1.0); #endif return o.v_; } template LogVal pow(const LogVal& b, const T& e) { return b.pow(e); } template bool operator<(const LogVal& lhs, const LogVal& rhs) { if (lhs.s_ == rhs.s_) { return (lhs.v_ < rhs.v_); } else { return lhs.s_ > rhs.s_; } } #if 0 template bool operator<=(const LogVal& lhs, const LogVal& rhs) { return (lhs.v_ <= rhs.v_); } template bool operator>(const LogVal& lhs, const LogVal& rhs) { return (lhs.v_ > rhs.v_); } template bool operator>=(const LogVal& lhs, const LogVal& rhs) { return (lhs.v_ >= rhs.v_); } #endif template std::size_t hash_value(const LogVal& x) { return x.hash_impl(); } template bool operator==(const LogVal& lhs, const LogVal& rhs) { return (lhs.v_ == rhs.v_) && (lhs.s_ == rhs.s_); } template bool operator!=(const LogVal& lhs, const LogVal& rhs) { return !(lhs == rhs); } #endif