/*
* log.h
* The basic idea is to exploit Pade polynomials.
* A lot of ideas were inspired by the cephes math library (by Stephen L. Moshier
* moshier@na-net.ornl.gov) as well as actual code.
* The Cephes library can be found here: http://www.netlib.org/cephes/
*
* Created on: Jun 23, 2012
* Author: Danilo Piparo, Thomas Hauth, Vincenzo Innocente
*/
/*
* VDT is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with this program. If not, see .
*/
#ifndef LOG_H_
#define LOG_H_
#include "vdtcore_common.h"
#include
namespace vdt{
// local namespace for the constants/functions which are necessary only here
namespace details{
const double LOG_UPPER_LIMIT = 1e307;
const double LOG_LOWER_LIMIT = 0;
const double SQRTH = 0.70710678118654752440;
inline double get_log_px(const double x){
const double PX1log = 1.01875663804580931796E-4;
const double PX2log = 4.97494994976747001425E-1;
const double PX3log = 4.70579119878881725854E0;
const double PX4log = 1.44989225341610930846E1;
const double PX5log = 1.79368678507819816313E1;
const double PX6log = 7.70838733755885391666E0;
double px = PX1log;
px *= x;
px += PX2log;
px *= x;
px += PX3log;
px *= x;
px += PX4log;
px *= x;
px += PX5log;
px *= x;
px += PX6log;
return px;
}
inline double get_log_qx(const double x){
const double QX1log = 1.12873587189167450590E1;
const double QX2log = 4.52279145837532221105E1;
const double QX3log = 8.29875266912776603211E1;
const double QX4log = 7.11544750618563894466E1;
const double QX5log = 2.31251620126765340583E1;
double qx = x;
qx += QX1log;
qx *=x;
qx += QX2log;
qx *=x;
qx += QX3log;
qx *=x;
qx += QX4log;
qx *=x;
qx += QX5log;
return qx;
}
}
// Log double precision --------------------------------------------------------
inline double fast_log(double x){
const double original_x = x;
/* separate mantissa from exponent */
double fe;
x = details::getMantExponent(x,fe);
// blending
x > details::SQRTH? fe+=1. : x+=x ;
x -= 1.0;
/* rational form */
double px = details::get_log_px(x);
//for the final formula
const double x2 = x*x;
px *= x;
px *= x2;
const double qx = details::get_log_qx(x);
double res = px / qx ;
res -= fe * 2.121944400546905827679e-4;
res -= 0.5 * x2 ;
res = x + res;
res += fe * 0.693359375;
if (original_x > details::LOG_UPPER_LIMIT)
res = std::numeric_limits::infinity();
if (original_x < details::LOG_LOWER_LIMIT) // THIS IS NAN!
res = - std::numeric_limits::quiet_NaN();
return res;
}
// Log single precision --------------------------------------------------------
namespace details{
const float LOGF_UPPER_LIMIT = MAXNUMF;
const float LOGF_LOWER_LIMIT = 0;
const float PX1logf = 7.0376836292E-2f;
const float PX2logf = -1.1514610310E-1f;
const float PX3logf = 1.1676998740E-1f;
const float PX4logf = -1.2420140846E-1f;
const float PX5logf = 1.4249322787E-1f;
const float PX6logf = -1.6668057665E-1f;
const float PX7logf = 2.0000714765E-1f;
const float PX8logf = -2.4999993993E-1f;
const float PX9logf = 3.3333331174E-1f;
inline float get_log_poly(const float x){
float y = x*PX1logf;
y += PX2logf;
y *= x;
y += PX3logf;
y *= x;
y += PX4logf;
y *= x;
y += PX5logf;
y *= x;
y += PX6logf;
y *= x;
y += PX7logf;
y *= x;
y += PX8logf;
y *= x;
y += PX9logf;
return y;
}
const float SQRTHF = 0.707106781186547524f;
}
// Log single precision --------------------------------------------------------
inline float fast_logf( float x ) {
const float original_x = x;
float fe;
x = details::getMantExponentf( x, fe);
x > details::SQRTHF? fe+=1.f : x+=x ;
x -= 1.0f;
const float x2 = x*x;
float res = details::get_log_poly(x);
res *= x2*x;
res += -2.12194440e-4f * fe;
res += -0.5f * x2;
res= x + res;
res += 0.693359375f * fe;
if (original_x > details::LOGF_UPPER_LIMIT)
res = std::numeric_limits::infinity();
if (original_x < details::LOGF_LOWER_LIMIT)
res = -std::numeric_limits::quiet_NaN();
return res;
}
//------------------------------------------------------------------------------
// void logv(const uint32_t size, double const * __restrict__ iarray, double* __restrict__ oarray);
// void fast_logv(const uint32_t size, double const * __restrict__ iarray, double* __restrict__ oarray);
// void logfv(const uint32_t size, float const * __restrict__ iarray, float* __restrict__ oarray);
// void fast_logfv(const uint32_t size, float const * __restrict__ iarray, float* __restrict__ oarray);
} //vdt namespace
#endif /* LOG_H_ */