2012-03-13 01:17:53 -04:00
|
|
|
/* origin: OpenBSD /usr/src/lib/libm/src/ld80/s_log1pl.c */
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* Relative error logarithm
|
|
|
|
* Natural logarithm of 1+x, long double precision
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* SYNOPSIS:
|
|
|
|
*
|
|
|
|
* long double x, y, log1pl();
|
|
|
|
*
|
|
|
|
* y = log1pl( x );
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* DESCRIPTION:
|
|
|
|
*
|
|
|
|
* Returns the base e (2.718...) logarithm of 1+x.
|
|
|
|
*
|
|
|
|
* The argument 1+x is separated into its exponent and fractional
|
|
|
|
* parts. If the exponent is between -1 and +1, the logarithm
|
|
|
|
* of the fraction is approximated by
|
|
|
|
*
|
|
|
|
* log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x).
|
|
|
|
*
|
|
|
|
* Otherwise, setting z = 2(x-1)/x+1),
|
|
|
|
*
|
|
|
|
* log(x) = z + z^3 P(z)/Q(z).
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* ACCURACY:
|
|
|
|
*
|
|
|
|
* Relative error:
|
|
|
|
* arithmetic domain # trials peak rms
|
|
|
|
* IEEE -1.0, 9.0 100000 8.2e-20 2.5e-20
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "libm.h"
|
|
|
|
|
|
|
|
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
|
|
|
long double log1pl(long double x)
|
|
|
|
{
|
|
|
|
return log1p(x);
|
|
|
|
}
|
|
|
|
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
|
|
|
|
/* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x)
|
|
|
|
* 1/sqrt(2) <= x < sqrt(2)
|
|
|
|
* Theoretical peak relative error = 2.32e-20
|
|
|
|
*/
|
2012-03-18 01:58:28 -04:00
|
|
|
static const long double P[] = {
|
2012-03-13 01:17:53 -04:00
|
|
|
4.5270000862445199635215E-5L,
|
|
|
|
4.9854102823193375972212E-1L,
|
|
|
|
6.5787325942061044846969E0L,
|
|
|
|
2.9911919328553073277375E1L,
|
|
|
|
6.0949667980987787057556E1L,
|
|
|
|
5.7112963590585538103336E1L,
|
|
|
|
2.0039553499201281259648E1L,
|
|
|
|
};
|
2012-03-18 01:58:28 -04:00
|
|
|
static const long double Q[] = {
|
2012-03-13 01:17:53 -04:00
|
|
|
/* 1.0000000000000000000000E0,*/
|
|
|
|
1.5062909083469192043167E1L,
|
|
|
|
8.3047565967967209469434E1L,
|
|
|
|
2.2176239823732856465394E2L,
|
|
|
|
3.0909872225312059774938E2L,
|
|
|
|
2.1642788614495947685003E2L,
|
|
|
|
6.0118660497603843919306E1L,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2),
|
|
|
|
* where z = 2(x-1)/(x+1)
|
|
|
|
* 1/sqrt(2) <= x < sqrt(2)
|
|
|
|
* Theoretical peak relative error = 6.16e-22
|
|
|
|
*/
|
2012-03-18 01:58:28 -04:00
|
|
|
static const long double R[4] = {
|
2012-03-13 01:17:53 -04:00
|
|
|
1.9757429581415468984296E-3L,
|
|
|
|
-7.1990767473014147232598E-1L,
|
|
|
|
1.0777257190312272158094E1L,
|
|
|
|
-3.5717684488096787370998E1L,
|
|
|
|
};
|
2012-03-18 01:58:28 -04:00
|
|
|
static const long double S[4] = {
|
2012-03-13 01:17:53 -04:00
|
|
|
/* 1.00000000000000000000E0L,*/
|
|
|
|
-2.6201045551331104417768E1L,
|
|
|
|
1.9361891836232102174846E2L,
|
|
|
|
-4.2861221385716144629696E2L,
|
|
|
|
};
|
|
|
|
static const long double C1 = 6.9314575195312500000000E-1L;
|
|
|
|
static const long double C2 = 1.4286068203094172321215E-6L;
|
|
|
|
|
|
|
|
#define SQRTH 0.70710678118654752440L
|
|
|
|
|
|
|
|
long double log1pl(long double xm1)
|
|
|
|
{
|
|
|
|
long double x, y, z;
|
|
|
|
int e;
|
|
|
|
|
|
|
|
if (isnan(xm1))
|
|
|
|
return xm1;
|
|
|
|
if (xm1 == INFINITY)
|
|
|
|
return xm1;
|
|
|
|
if (xm1 == 0.0)
|
|
|
|
return xm1;
|
|
|
|
|
2012-03-19 23:41:19 +01:00
|
|
|
x = xm1 + 1.0;
|
2012-03-13 01:17:53 -04:00
|
|
|
|
|
|
|
/* Test for domain errors. */
|
2012-03-19 23:41:19 +01:00
|
|
|
if (x <= 0.0) {
|
|
|
|
if (x == 0.0)
|
math: extensive log*.c cleanup
The log, log2 and log10 functions share a lot of code and to a lesser
extent log1p too. A small part of the code was kept separately in
__log1p.h, but since it did not capture much of the common code and
it was inlined anyway, it did not solve the issue properly. Now the
log functions have significant code duplication, which may be resolved
later, until then they need to be modified together.
logl, log10l, log2l, log1pl:
* Fix the sign when the return value should be -inf.
* Remove the volatile hack from log10l (seems unnecessary)
log1p, log1pf:
* Change the handling of small inputs: only |x|<2^-53 is special
(then it is enough to return x with the usual subnormal handling)
this fixes the sign of log1p(0) in downward rounding.
* Do not handle the k==0 case specially (other than skipping the
elaborate argument reduction)
* Do not handle 1+x close to power-of-two specially (this code was
used rarely, did not give much speed up and the precision wasn't
better than the general)
* Fix the correction term formula (c=1-(u-x) was used incorrectly
when x<1 but (double)(x+1)==2, this was not a critical issue)
* Use the exact same method for calculating log(1+f) as in log
(except in log1p the c correction term is added to the result).
log, logf, log10, log10f, log2, log2f:
* Use double_t and float_t consistently.
* Now the first part of log10 and log2 is identical to log (until the
return statement, hopefully this makes maintainence easier).
* Most special case formulas were removed (close to power-of-two and
k==0 cases), they increase the code size without providing precision
or performance benefits (and obfuscate the code).
Only x==1 is handled specially so in downward rounding mode the
sign of zero is correct (the general formula happens to give -0).
* For x==0 instead of -1/0.0 or -two54/0.0, return -1/(x*x) to force
raising the exception at runtime.
* Arg reduction code is changed (slightly simplified)
* The thresholds for arg reduction to [sqrt(2)/2,sqrt(2)] are now
consistently the [0x3fe6a09e00000000,0x3ff6a09dffffffff] and the
[0x3f3504f3,0x3fb504f2] intervals for double and float reductions
respectively (the exact threshold values are not critical)
* Remove the obsolete comment for the FLT_EVAL_METHOD!=0 case in log2f
(The same code is used for all eval methods now, on i386 slightly
simpler code could be used, but we have asm there anyway)
all:
* Fix signed int arithmetics (using unsigned for bitmanipulation)
* Fix various comments
2013-10-28 01:16:14 +00:00
|
|
|
return -1/(x*x); /* -inf with divbyzero */
|
2012-11-13 00:21:09 +01:00
|
|
|
return 0/0.0f; /* nan with invalid */
|
2012-03-13 01:17:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Separate mantissa from exponent.
|
|
|
|
Use frexp so that denormal numbers will be handled properly. */
|
|
|
|
x = frexpl(x, &e);
|
|
|
|
|
|
|
|
/* logarithm using log(x) = z + z^3 P(z)/Q(z),
|
|
|
|
where z = 2(x-1)/x+1) */
|
|
|
|
if (e > 2 || e < -2) {
|
|
|
|
if (x < SQRTH) { /* 2(2x-1)/(2x+1) */
|
|
|
|
e -= 1;
|
2012-03-19 23:41:19 +01:00
|
|
|
z = x - 0.5;
|
|
|
|
y = 0.5 * z + 0.5;
|
2012-03-13 01:17:53 -04:00
|
|
|
} else { /* 2 (x-1)/(x+1) */
|
2012-03-19 23:41:19 +01:00
|
|
|
z = x - 0.5;
|
|
|
|
z -= 0.5;
|
|
|
|
y = 0.5 * x + 0.5;
|
2012-03-13 01:17:53 -04:00
|
|
|
}
|
|
|
|
x = z / y;
|
|
|
|
z = x*x;
|
|
|
|
z = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3));
|
|
|
|
z = z + e * C2;
|
|
|
|
z = z + x;
|
|
|
|
z = z + e * C1;
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */
|
|
|
|
if (x < SQRTH) {
|
|
|
|
e -= 1;
|
|
|
|
if (e != 0)
|
2012-03-19 23:41:19 +01:00
|
|
|
x = 2.0 * x - 1.0;
|
2012-03-13 01:17:53 -04:00
|
|
|
else
|
|
|
|
x = xm1;
|
|
|
|
} else {
|
|
|
|
if (e != 0)
|
2012-03-19 23:41:19 +01:00
|
|
|
x = x - 1.0;
|
2012-03-13 01:17:53 -04:00
|
|
|
else
|
|
|
|
x = xm1;
|
|
|
|
}
|
|
|
|
z = x*x;
|
|
|
|
y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 6));
|
|
|
|
y = y + e * C2;
|
|
|
|
z = y - 0.5 * z;
|
|
|
|
z = z + x;
|
|
|
|
z = z + e * C1;
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
#endif
|