#include "double_extras.h"
#include "mag.h"
#define LOG_TAB_STEP 32
const double d_log_tab[] = {
-0.6931471805599453094172,
-0.6325225587435104668366,
-0.5753641449035618548784,
-0.5212969236332860870771,
-0.4700036292457355536509,
-0.4212134650763035505856,
-0.374693449441410693607,
-0.3302416868705768562794,
-0.2876820724517809274392,
-0.2468600779315257978846,
-0.2076393647782445016154,
-0.1698990367953974729004,
-0.1335313926245226231463,
-0.09844007281325251990289,
-0.06453852113757117167292,
-0.031748698314580301157,
0.0,
0.03077165866675368837103,
0.06062462181643484258061,
0.08961215868968713261995,
0.1177830356563834545388,
0.1451820098444978972819,
0.1718502569266592223401,
0.1978257433299198803626,
0.2231435513142097557663,
0.2478361639045812567806,
0.2719337154836417588317,
0.2954642128938358763867,
0.3184537311185346158102,
0.3409265869705932103051,
0.3629054936893684531378,
0.3844116989103320397348,
};
const double d_log_inverses[] = {
0.0,
1.0,
0.5,
0.3333333333333333333333,
0.25,
0.2,
0.1666666666666666666667,
0.1428571428571428571429,
0.125,
0.1111111111111111111111,
0.1,
0.09090909090909090909091,
0.08333333333333333333333,
0.07692307692307692307692,
0.07142857142857142857143,
0.06666666666666666666667,
0.0625,
0.05882352941176470588235,
0.05555555555555555555556,
0.05263157894736842105263,
0.05,
0.04761904761904761904762,
0.04545454545454545454545,
0.0434782608695652173913,
0.04166666666666666666667,
0.04,
0.03846153846153846153846,
0.03703703703703703703704,
0.03571428571428571428571,
0.03448275862068965517241,
0.03333333333333333333333,
0.03225806451612903225806,
0.03125,
0.0303030303030303030303,
0.02941176470588235294118,
0.02857142857142857142857,
0.02777777777777777777778,
0.02702702702702702702703,
0.02631578947368421052632,
0.02564102564102564102564,
0.025,
0.02439024390243902439024,
0.02380952380952380952381,
0.02325581395348837209302,
0.02272727272727272727273,
0.02222222222222222222222,
0.02173913043478260869565,
0.02127659574468085106383,
};
static double
mag_d_bad_log(double x)
{
double t, u, v, t1, t2, t3;
int m, n;
if (x <= 0.0 || (x-x) != (x-x))
{
if (x == 0.0)
return -D_INF;
else if (x > 0.0)
return D_INF;
else
return D_NAN;
}
if (x < 1 + 1./LOG_TAB_STEP && x > 1 - 1./LOG_TAB_STEP)
{
return -d_polyval(d_log_inverses, 12, 1.-x);
}
t = frexp(x, &n);
if (t < 0.7071067811865475244008)
{
t *= 2.0;
n -= 1;
}
m = floor(t * LOG_TAB_STEP + 0.5);
u = t * LOG_TAB_STEP - m;
v = -u * d_log_inverses[m];
t1 = n * (-d_log_tab[0]);
t2 = d_log_tab[m - LOG_TAB_STEP / 2];
t3 = -d_polyval(d_log_inverses, 11, v);
return t1 + (t2 + t3);
}
double
mag_d_log_upper_bound(double x)
{
if (x >= 1.0)
return mag_d_bad_log(x) * (1 + 1e-14);
else
return mag_d_bad_log(x) * (1 - 1e-14);
}
double
mag_d_log_lower_bound(double x)
{
if (x >= 1.0)
return mag_d_bad_log(x) * (1 - 1e-14);
else
return mag_d_bad_log(x) * (1 + 1e-14);
}