mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
86 lines
2.6 KiB
Plaintext
86 lines
2.6 KiB
Plaintext
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
|
|
|
|
const double LOG_LN2_HI = 6.93147180369123816490e-01;
|
|
const double LOG_LN2_LO = 1.90821492927058770002e-10;
|
|
const double LOG_L1 = 6.666666666666735130e-01;
|
|
const double LOG_L2 = 3.999999999940941908e-01;
|
|
const double LOG_L3 = 2.857142874366239149e-01;
|
|
const double LOG_L4 = 2.222219843214978396e-01;
|
|
const double LOG_L5 = 1.818357216161805012e-01;
|
|
const double LOG_L6 = 1.531383769920937332e-01;
|
|
/*--------------------------------------------*/
|
|
const float LOGF_LN2_HI = 6.9313812256e-01f;
|
|
const float LOGF_LN2_LO = 9.0580006145e-06f;
|
|
const float LOGF_L1 = 6.6666662693e-01f;
|
|
const float LOGF_L2 = 4.0000972152e-01f;
|
|
const float LOGF_L3 = 2.8498786688e-01f;
|
|
const float LOGF_L4 = 2.4279078841e-01f;
|
|
|
|
const double SQRT2 = 1.41421356237309504880;
|
|
const float SQRT2F = 1.41421356237309504880f;
|
|
|
|
fn double log(double x) @cname("log") @nostrip @weak
|
|
{
|
|
if (x != x) return x;
|
|
if (x < 0.0) return double.nan;
|
|
if (x == 0.0) return -double.inf;
|
|
if (x == double.inf) return double.inf;
|
|
|
|
int k;
|
|
double f = frexp(x, &k);
|
|
if (f < SQRT2 * 0.5)
|
|
{
|
|
f *= 2.0;
|
|
k--;
|
|
}
|
|
|
|
// polynomial approximation of log(1 + f), with f in [0, sqrt(2) - 1]
|
|
f -= 1.0;
|
|
double s = f / (2.0 + f);
|
|
double z = s * s;
|
|
double w = z * z;
|
|
|
|
// even-part polynomial terms (t1) and odd-part polynomial terms (t2)
|
|
double t1 = w * (LOG_L1 + w * (LOG_L3 + w * LOG_L5));
|
|
double t2 = z * (LOG_L2 + w * (LOG_L4 + w * LOG_L6));
|
|
double r = t1 + t2;
|
|
|
|
double hfsq = 0.5 * f * f;
|
|
|
|
return k * LOG_LN2_HI - ((hfsq - (s * (hfsq + r) + k * LOG_LN2_LO)) - f);
|
|
}
|
|
|
|
fn float logf(float x) @cname("logf") @nostrip @weak
|
|
{
|
|
if (x != x) return x;
|
|
if (x < 0.0f) return float.nan;
|
|
if (x == 0.0f) return -float.inf;
|
|
if (x == float.inf) return float.inf;
|
|
|
|
int k;
|
|
float f = frexpf(x, &k);
|
|
if (f < SQRT2F * 0.5f)
|
|
{
|
|
f *= 2.0f;
|
|
k--;
|
|
}
|
|
|
|
// polynomial approximation for log(1 + f)
|
|
f -= 1.0f;
|
|
float s = f / (2.0f + f);
|
|
float z = s * s;
|
|
float w = z * z;
|
|
|
|
/*
|
|
logf uses fewer terms in its polynomial approximation
|
|
compared to the double precision version because
|
|
single-precision floating point doesn't benefit from the additional terms.
|
|
LOGF_L1, ... ,LOGF_L4 provide sufficient accuracy for 32-bit float calculations.
|
|
*/
|
|
float t1 = w * (LOGF_L1 + w * LOGF_L3);
|
|
float t2 = z * (LOGF_L2 + w * LOGF_L4);
|
|
float r = t1 + t2;
|
|
|
|
float hfsq = 0.5f * f * f;
|
|
return k * LOGF_LN2_HI - ((hfsq - (s * (hfsq + r) + k * LOGF_LN2_LO)) - f);
|
|
} |