mirror of
https://github.com/vale981/arb
synced 2025-03-05 09:21:38 -05:00
213 lines
6.7 KiB
C
213 lines
6.7 KiB
C
/*
|
|
Copyright (C) 2014 Fredrik Johansson
|
|
|
|
This file is part of Arb.
|
|
|
|
Arb is free software: you can redistribute it and/or modify it under
|
|
the terms of the GNU Lesser General Public License (LGPL) as published
|
|
by the Free Software Foundation; either version 2.1 of the License, or
|
|
(at your option) any later version. See <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "flint/double_extras.h"
|
|
#include "mag.h"
|
|
|
|
/*
|
|
This is a bad implementation the logarithm function,
|
|
Any decent libm should compute log() with < 1 ulp
|
|
error, but we have no way to know that this is the case
|
|
(the IEEE 754 and C language standards make virtually
|
|
no guarantees whatsoever about transcendental functions).
|
|
|
|
So here is a bad implementation which almost certainly
|
|
has much worse accuracy than the libm log(), but which
|
|
is simple and for which we can give an explicit error
|
|
bound. The only precomputed constants are rational
|
|
numbers and logarithms of rational numbers, which are
|
|
easy to validate.
|
|
|
|
First write x = 2^n * t with sqrt(2)/2 < t < sqrt(2)
|
|
(a few ulps outside this range is fine). Then write
|
|
t = m/32 + u with |u| <= 1/64. We have 23 <= m <= 45.
|
|
Let v = 32*u/m (note that |v| <= 1/46). Then we have
|
|
|
|
log(x) = log(2^n*t)
|
|
= n*log(2) + log(t)
|
|
= n*log(2) + log(m/32 + u)
|
|
= n*log(2) + log(m/32 + m/32 * 32*u/m)
|
|
= n*log(2) + log(m/32) + log(1 + 32*u/m)
|
|
= n*log(2) + (log(m/32) + log(1 + v))
|
|
|
|
We compute log(x) as t1 + (t2 + t3) where t1 ~= n*log(2)
|
|
involves two roundings, t2 involves one rounding,
|
|
and t3 ~= v - [v^2/2 + ...] involves two roundings for
|
|
the multiplication by 1/m, one rounding for subtraction,
|
|
plus a much smaller error contribution due to the
|
|
error in the approximation of the terms in brackets.
|
|
|
|
Now consider the outer sum t1 + (t2 + t3). When n != 0,
|
|
t1 will always be about twice as large as (t2+t3).
|
|
When n = 0, t2 will always be exactly zero or
|
|
about twice as large as t3. So there can be no significant
|
|
cancellation, and most of the final error comes from
|
|
the largest nonzero term.
|
|
|
|
By inspection, the final error is clearly bounded by
|
|
10 ulp (a 3 ulp or maybe even 2 ulp bound could probably
|
|
be proved with a careful calculation).
|
|
|
|
Multiplying the output by 1 +/- 1e-14, we get guaranteed
|
|
upper/lower bounds for the logarithm. This factor
|
|
is chosen conservatively so that we get correct bounds
|
|
even on x87 or if the CPU rounding mode has been changed.
|
|
|
|
*/
|
|
|
|
#define LOG_TAB_STEP 32
|
|
|
|
const double d_log_tab[] = {
|
|
-0.6931471805599453094172, /* log(16/32) */
|
|
-0.6325225587435104668366, /* log(17/32) */
|
|
-0.5753641449035618548784, /* log(18/32) */
|
|
-0.5212969236332860870771, /* log(19/32) */
|
|
-0.4700036292457355536509, /* log(20/32) */
|
|
-0.4212134650763035505856, /* log(21/32) */
|
|
-0.374693449441410693607, /* log(22/32) */
|
|
-0.3302416868705768562794, /* log(23/32) */
|
|
-0.2876820724517809274392, /* log(24/32) */
|
|
-0.2468600779315257978846, /* log(25/32) */
|
|
-0.2076393647782445016154, /* log(26/32) */
|
|
-0.1698990367953974729004, /* log(27/32) */
|
|
-0.1335313926245226231463, /* log(28/32) */
|
|
-0.09844007281325251990289, /* log(29/32) */
|
|
-0.06453852113757117167292, /* log(30/32) */
|
|
-0.031748698314580301157, /* log(31/32) */
|
|
0.0, /* log(32/32) */
|
|
0.03077165866675368837103, /* log(33/32) */
|
|
0.06062462181643484258061, /* log(34/32) */
|
|
0.08961215868968713261995, /* log(35/32) */
|
|
0.1177830356563834545388, /* log(36/32) */
|
|
0.1451820098444978972819, /* log(37/32) */
|
|
0.1718502569266592223401, /* log(38/32) */
|
|
0.1978257433299198803626, /* log(39/32) */
|
|
0.2231435513142097557663, /* log(40/32) */
|
|
0.2478361639045812567806, /* log(41/32) */
|
|
0.2719337154836417588317, /* log(42/32) */
|
|
0.2954642128938358763867, /* log(43/32) */
|
|
0.3184537311185346158102, /* log(44/32) */
|
|
0.3409265869705932103051, /* log(45/32) */
|
|
0.3629054936893684531378, /* log(46/32) */
|
|
0.3844116989103320397348, /* log(47/32) */
|
|
};
|
|
|
|
const double d_log_inverses[] = {
|
|
0.0,
|
|
1.0, /* 1/1 */
|
|
0.5, /* 1/2 */
|
|
0.3333333333333333333333, /* 1/3 */
|
|
0.25, /* 1/4 */
|
|
0.2, /* 1/5 */
|
|
0.1666666666666666666667, /* 1/6 */
|
|
0.1428571428571428571429, /* 1/7 */
|
|
0.125, /* 1/8 */
|
|
0.1111111111111111111111, /* 1/9 */
|
|
0.1, /* 1/10 */
|
|
0.09090909090909090909091, /* 1/11 */
|
|
0.08333333333333333333333, /* 1/12 */
|
|
0.07692307692307692307692, /* 1/13 */
|
|
0.07142857142857142857143, /* 1/14 */
|
|
0.06666666666666666666667, /* 1/15 */
|
|
0.0625, /* 1/16 */
|
|
0.05882352941176470588235, /* 1/17 */
|
|
0.05555555555555555555556, /* 1/18 */
|
|
0.05263157894736842105263, /* 1/19 */
|
|
0.05, /* 1/20 */
|
|
0.04761904761904761904762, /* 1/21 */
|
|
0.04545454545454545454545, /* 1/22 */
|
|
0.0434782608695652173913, /* 1/23 */
|
|
0.04166666666666666666667, /* 1/24 */
|
|
0.04, /* 1/25 */
|
|
0.03846153846153846153846, /* 1/26 */
|
|
0.03703703703703703703704, /* 1/27 */
|
|
0.03571428571428571428571, /* 1/28 */
|
|
0.03448275862068965517241, /* 1/29 */
|
|
0.03333333333333333333333, /* 1/30 */
|
|
0.03225806451612903225806, /* 1/31 */
|
|
0.03125, /* 1/32 */
|
|
0.0303030303030303030303, /* 1/33 */
|
|
0.02941176470588235294118, /* 1/34 */
|
|
0.02857142857142857142857, /* 1/35 */
|
|
0.02777777777777777777778, /* 1/36 */
|
|
0.02702702702702702702703, /* 1/37 */
|
|
0.02631578947368421052632, /* 1/38 */
|
|
0.02564102564102564102564, /* 1/39 */
|
|
0.025, /* 1/40 */
|
|
0.02439024390243902439024, /* 1/41 */
|
|
0.02380952380952380952381, /* 1/42 */
|
|
0.02325581395348837209302, /* 1/43 */
|
|
0.02272727272727272727273, /* 1/44 */
|
|
0.02222222222222222222222, /* 1/45 */
|
|
0.02173913043478260869565, /* 1/46 */
|
|
0.02127659574468085106383, /* 1/47 */
|
|
};
|
|
|
|
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 / 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);
|
|
}
|
|
|