mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 14:58:30 +00:00
Make quality improvements
- Write some more unit tests - memcpy() on ARM is now faster - Address the Musl complex math FIXME comments - Some libm funcs like pow() now support setting errno - Import the latest and greatest math functions from ARM - Use more accurate atan2f() and log1pf() implementations - atoi() and atol() will no longer saturate or clobber errno
This commit is contained in:
parent
af8f2bd19f
commit
592f6ebc20
122 changed files with 6305 additions and 3859 deletions
|
@ -1,9 +1,9 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi │
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╚──────────────────────────────────────────────────────────────────────────────╝
|
||||
│ │
|
||||
│ Musl Libc │
|
||||
│ Copyright © 2005-2014 Rich Felker, et al. │
|
||||
│ Optimized Routines │
|
||||
│ Copyright (c) 2018-2024, Arm Limited. │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files (the │
|
||||
|
@ -25,33 +25,135 @@
|
|||
│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
||||
│ │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/math.h"
|
||||
__static_yoink("musl_libc_notice");
|
||||
#include "libc/tinymath/arm.internal.h"
|
||||
__static_yoink("arm_optimized_routines_notice");
|
||||
|
||||
#define N (1 << EXP_TABLE_BITS)
|
||||
#define IndexMask (N - 1)
|
||||
#define OFlowBound 0x1.34413509f79ffp8 /* log10(DBL_MAX). */
|
||||
#define UFlowBound -0x1.5ep+8 /* -350. */
|
||||
#define SmallTop 0x3c6 /* top12(0x1p-57). */
|
||||
#define BigTop 0x407 /* top12(0x1p8). */
|
||||
#define Thresh 0x41 /* BigTop - SmallTop. */
|
||||
#define Shift __exp_data.shift
|
||||
#define C(i) __exp_data.exp10_poly[i]
|
||||
|
||||
static double
|
||||
special_case (uint64_t sbits, double_t tmp, uint64_t ki)
|
||||
{
|
||||
double_t scale, y;
|
||||
|
||||
if (ki - (1ull << 16) < 0x80000000)
|
||||
{
|
||||
/* The exponent of scale might have overflowed by 1. */
|
||||
sbits -= 1ull << 52;
|
||||
scale = asdouble (sbits);
|
||||
y = 2 * (scale + scale * tmp);
|
||||
return check_oflow (eval_as_double (y));
|
||||
}
|
||||
|
||||
/* n < 0, need special care in the subnormal range. */
|
||||
sbits += 1022ull << 52;
|
||||
scale = asdouble (sbits);
|
||||
y = scale + scale * tmp;
|
||||
|
||||
if (y < 1.0)
|
||||
{
|
||||
/* Round y to the right precision before scaling it into the subnormal
|
||||
range to avoid double rounding that can cause 0.5+E/2 ulp error where
|
||||
E is the worst-case ulp error outside the subnormal range. So this
|
||||
is only useful if the goal is better than 1 ulp worst-case error. */
|
||||
double_t lo = scale - y + scale * tmp;
|
||||
double_t hi = 1.0 + y;
|
||||
lo = 1.0 - hi + y + lo;
|
||||
y = eval_as_double (hi + lo) - 1.0;
|
||||
/* Avoid -0.0 with downward rounding. */
|
||||
if (WANT_ROUNDING && y == 0.0)
|
||||
y = 0.0;
|
||||
/* The underflow exception needs to be signaled explicitly. */
|
||||
force_eval_double (opt_barrier_double (0x1p-1022) * 0x1p-1022);
|
||||
}
|
||||
y = 0x1p-1022 * y;
|
||||
|
||||
return check_uflow (y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 10ˣ.
|
||||
*
|
||||
* The largest observed error is ~0.513 ULP.
|
||||
*/
|
||||
double exp10(double x)
|
||||
double
|
||||
exp10 (double x)
|
||||
{
|
||||
static const double p10[] = {
|
||||
1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10,
|
||||
1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
|
||||
1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
|
||||
1e10, 1e11, 1e12, 1e13, 1e14, 1e15
|
||||
};
|
||||
double n, y = modf(x, &n);
|
||||
union {double f; uint64_t i;} u = {n};
|
||||
/* fabs(n) < 16 without raising invalid on nan */
|
||||
if ((u.i>>52 & 0x7ff) < 0x3ff+4) {
|
||||
if (!y) return p10[(int)n+15];
|
||||
y = exp2(3.32192809488736234787031942948939 * y);
|
||||
return y * p10[(int)n+15];
|
||||
}
|
||||
return pow(10.0, x);
|
||||
uint64_t ix = asuint64 (x);
|
||||
uint32_t abstop = (ix >> 52) & 0x7ff;
|
||||
|
||||
if (unlikely (abstop - SmallTop >= Thresh))
|
||||
{
|
||||
if (abstop - SmallTop >= 0x80000000)
|
||||
/* Avoid spurious underflow for tiny x.
|
||||
Note: 0 is common input. */
|
||||
return x + 1;
|
||||
if (abstop == 0x7ff)
|
||||
return ix == asuint64 (-INFINITY) ? 0.0 : x + 1.0;
|
||||
if (x >= OFlowBound)
|
||||
return __math_oflow (0);
|
||||
if (x < UFlowBound)
|
||||
return __math_uflow (0);
|
||||
|
||||
/* Large x is special-cased below. */
|
||||
abstop = 0;
|
||||
}
|
||||
|
||||
/* Reduce x: z = x * N / log10(2), k = round(z). */
|
||||
double_t z = __exp_data.invlog10_2N * x;
|
||||
double_t kd;
|
||||
int64_t ki;
|
||||
#if TOINT_INTRINSICS
|
||||
kd = roundtoint (z);
|
||||
ki = converttoint (z);
|
||||
#else
|
||||
kd = eval_as_double (z + Shift);
|
||||
kd -= Shift;
|
||||
ki = kd;
|
||||
#endif
|
||||
|
||||
/* r = x - k * log10(2), r in [-0.5, 0.5]. */
|
||||
double_t r = x;
|
||||
r = __exp_data.neglog10_2hiN * kd + r;
|
||||
r = __exp_data.neglog10_2loN * kd + r;
|
||||
|
||||
/* exp10(x) = 2^(k/N) * 2^(r/N).
|
||||
Approximate the two components separately. */
|
||||
|
||||
/* s = 2^(k/N), using lookup table. */
|
||||
uint64_t e = ki << (52 - EXP_TABLE_BITS);
|
||||
uint64_t i = (ki & IndexMask) * 2;
|
||||
uint64_t u = __exp_data.tab[i + 1];
|
||||
uint64_t sbits = u + e;
|
||||
|
||||
double_t tail = asdouble (__exp_data.tab[i]);
|
||||
|
||||
/* 2^(r/N) ~= 1 + r * Poly(r). */
|
||||
double_t r2 = r * r;
|
||||
double_t p = C (0) + r * C (1);
|
||||
double_t y = C (2) + r * C (3);
|
||||
y = y + r2 * C (4);
|
||||
y = p + r2 * y;
|
||||
y = tail + y * r;
|
||||
|
||||
if (unlikely (abstop == 0))
|
||||
return special_case (sbits, y, ki);
|
||||
|
||||
/* Assemble components:
|
||||
y = 2^(r/N) * 2^(k/N)
|
||||
~= (y + 1) * s. */
|
||||
double_t s = asdouble (sbits);
|
||||
return eval_as_double (s * y + s);
|
||||
}
|
||||
|
||||
__strong_reference(exp10, pow10);
|
||||
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
||||
__weak_reference(exp10, exp10l);
|
||||
__weak_reference(exp10, pow10l);
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue