mirror of
https://github.com/vale981/arb
synced 2025-03-06 01:41:39 -05:00
141 lines
4.5 KiB
C
141 lines
4.5 KiB
C
/*=============================================================================
|
|
|
|
This file is part of ARB.
|
|
|
|
ARB is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
ARB 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with ARB; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
=============================================================================*/
|
|
/******************************************************************************
|
|
|
|
Copyright (C) 2013, 2014 Fredrik Johansson
|
|
|
|
******************************************************************************/
|
|
|
|
#include <math.h>
|
|
#include "elefun.h"
|
|
|
|
#define TABSIZE 256
|
|
|
|
/* bounds for log2(1/n!) */
|
|
static const int rec_fac_bound_2exp_si_tab[TABSIZE] =
|
|
{
|
|
0, 0, -1, -2, -4, -6, -9, -12, -15, -18, -21, -25, -28, -32, -36,
|
|
-40, -44, -48, -52, -56, -61, -65, -69, -74, -79, -83, -88, -93, -97,
|
|
-102, -107, -112, -117, -122, -127, -132, -138, -143, -148, -153,
|
|
-159, -164, -169, -175, -180, -186, -191, -197, -202, -208, -214,
|
|
-219, -225, -231, -237, -242, -248, -254, -260, -266, -272, -278,
|
|
-284, -289, -295, -302, -308, -314, -320, -326, -332, -338, -344,
|
|
-350, -357, -363, -369, -375, -382, -388, -394, -401, -407, -413,
|
|
-420, -426, -433, -439, -446, -452, -458, -465, -472, -478, -485,
|
|
-491, -498, -504, -511, -518, -524, -531, -538, -544, -551, -558,
|
|
-564, -571, -578, -585, -591, -598, -605, -612, -619, -626, -632,
|
|
-639, -646, -653, -660, -667, -674, -681, -688, -695, -702, -709,
|
|
-716, -723, -730, -737, -744, -751, -758, -765, -772, -779, -786,
|
|
-793, -801, -808, -815, -822, -829, -836, -844, -851, -858, -865,
|
|
-872, -880, -887, -894, -901, -909, -916, -923, -931, -938, -945,
|
|
-952, -960, -967, -975, -982, -989, -997, -1004, -1011, -1019, -1026,
|
|
-1034, -1041, -1049, -1056, -1064, -1071, -1078, -1086, -1093, -1101,
|
|
-1108, -1116, -1123, -1131, -1139, -1146, -1154, -1161, -1169, -1176,
|
|
-1184, -1192, -1199, -1207, -1214, -1222, -1230, -1237, -1245, -1253,
|
|
-1260, -1268, -1276, -1283, -1291, -1299, -1306, -1314, -1322, -1329,
|
|
-1337, -1345, -1353, -1360, -1368, -1376, -1384, -1391, -1399, -1407,
|
|
-1415, -1423, -1430, -1438, -1446, -1454, -1462, -1470, -1477, -1485,
|
|
-1493, -1501, -1509, -1517, -1525, -1532, -1540, -1548, -1556, -1564,
|
|
-1572, -1580, -1588, -1596, -1604, -1612, -1620, -1628, -1636, -1644,
|
|
-1652, -1660, -1668, -1675
|
|
};
|
|
|
|
#define ONE_OVER_LOG2 1.4426950408889634074
|
|
#define LOG2 0.69314718055994530942
|
|
|
|
/* For all we know, the log() function shipped with some libm implementation
|
|
for MS-DOS from 1987 might have given less than six digits of accuracy, so
|
|
we reimplement the function poorly but reproducibly here. */
|
|
|
|
#include "double_extras.h"
|
|
|
|
static const double logcoeffs[] = {
|
|
0.0,
|
|
1.0,
|
|
0.5,
|
|
0.33333333333333333333,
|
|
0.25,
|
|
0.2,
|
|
0.16666666666666666667,
|
|
0.14285714285714285714,
|
|
0.125,
|
|
0.11111111111111111111,
|
|
0.1,
|
|
0.090909090909090909091,
|
|
0.083333333333333333333,
|
|
0.076923076923076923077,
|
|
0.071428571428571428571,
|
|
0.066666666666666666667,
|
|
0.0625,
|
|
};
|
|
|
|
double idiot_log(double x)
|
|
{
|
|
double t;
|
|
int n;
|
|
|
|
t = frexp(x, &n);
|
|
t = sqrt(t);
|
|
|
|
return n * LOG2 - 2.0 * d_polyval(logcoeffs, 14, 1.0 - t);
|
|
}
|
|
|
|
static __inline__ long
|
|
rec_fac_bound_2exp_si(long n)
|
|
{
|
|
if (n < TABSIZE)
|
|
{
|
|
return rec_fac_bound_2exp_si_tab[n];
|
|
}
|
|
else
|
|
{
|
|
double x;
|
|
|
|
/* log(1/n!) < log((e/n)^n) = n - n*log(n) */
|
|
|
|
x = (n - n * idiot_log(n)) * ONE_OVER_LOG2;
|
|
x = x * 0.9999; /* counter rounding error */
|
|
x = ceil(x); /* round to 0 */
|
|
|
|
/* TODO: check for overflow here */
|
|
|
|
return (long) x;
|
|
}
|
|
}
|
|
|
|
long
|
|
elefun_exp_taylor_bound(long mag, long prec)
|
|
{
|
|
long i;
|
|
|
|
/* assume x <= 1/4 */
|
|
if (mag > -2)
|
|
{
|
|
printf("elefun_exp_taylor_bound: too large input %ld\n", mag);
|
|
abort();
|
|
}
|
|
|
|
for (i = 1; ; i++)
|
|
{
|
|
if (mag * i + rec_fac_bound_2exp_si(i) < -prec - 1)
|
|
return i;
|
|
}
|
|
}
|
|
|