CoolPotOS/apps/libs/math.c

807 lines
18 KiB
C
Raw Normal View History

2024-09-01 14:56:38 +08:00
#include "../include/math.h"
2024-09-01 16:43:58 +08:00
#include "../include/ctype.h"
2024-09-01 14:56:38 +08:00
2024-09-08 22:43:05 +08:00
static const double ivln10hi =
4.34294481878168880939e-01, /* 0x3fdbcb7b, 0x15200000 */
ivln10lo = 2.50829467116452752298e-11, /* 0x3dbb9438, 0xca9aadd5 */
log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
log10_2lo = 3.69423907715893078616e-13, /* 0x3D59FEF3, 0x11F12B36 */
Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
2024-09-01 14:56:38 +08:00
2024-09-08 22:43:05 +08:00
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subl %5,%1\n\tsbbl %3,%0" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "0" ((USItype) (ah)), \
"g" ((USItype) (bh)), \
"1" ((USItype) (al)), \
"g" ((USItype) (bl)))
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("mull %3" \
: "=a" ((USItype) (w0)), \
"=d" ((USItype) (w1)) \
: "%0" ((USItype) (u)), \
"rm" ((USItype) (v)))
#define udiv_qrnnd(q, r, n1, n0, dv) \
__asm__ ("divl %4" \
: "=a" ((USItype) (q)), \
"=d" ((USItype) (r)) \
: "0" ((USItype) (n0)), \
"1" ((USItype) (n1)), \
"rm" ((USItype) (dv)))
#define count_leading_zeros(count, x) \
do { \
USItype __cbtmp; \
__asm__ ("bsrl %1,%0" \
: "=r" (__cbtmp) : "rm" ((USItype) (x))); \
(count) = __cbtmp ^ 31; \
} while (0)
static unsigned rand_seed = 1;
static unsigned short max_bit = 32;
static unsigned short randlevel = 1;
#define __negdi2(a) (-(a))
static UDWtype __udivmoddi4(UDWtype n, UDWtype d, UDWtype *rp) {
DWunion ww;
DWunion nn, dd;
DWunion rr;
UWtype d0, d1, n0, n1, n2;
UWtype q0, q1;
UWtype b, bm;
nn.ll = n;
dd.ll = d;
d0 = dd.s.low;
d1 = dd.s.high;
n0 = nn.s.low;
n1 = nn.s.high;
#if !defined(UDIV_NEEDS_NORMALIZATION)
if (d1 == 0) {
if (d0 > n1) {
/* 0q = nn / 0D */
udiv_qrnnd(q0, n0, n1, n0, d0);
q1 = 0;
/* Remainder in n0. */
} else {
/* qq = NN / 0d */
if (d0 == 0)
d0 = 1 / d0; /* Divide intentionally by zero. */
udiv_qrnnd(q1, n1, 0, n1, d0);
udiv_qrnnd(q0, n0, n1, n0, d0);
/* Remainder in n0. */
}
if (rp != 0) {
rr.s.low = n0;
rr.s.high = 0;
*rp = rr.ll;
}
}
#else /* UDIV_NEEDS_NORMALIZATION */
if (d1 == 0)
{
if (d0 > n1)
{
/* 0q = nn / 0D */
count_leading_zeros (bm, d0);
if (bm != 0)
{
/* Normalize, i.e. make the most significant bit of the
denominator set. */
d0 = d0 << bm;
n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
n0 = n0 << bm;
}
udiv_qrnnd (q0, n0, n1, n0, d0);
q1 = 0;
/* Remainder in n0 >> bm. */
}
else
{
/* qq = NN / 0d */
if (d0 == 0)
d0 = 1 / d0; /* Divide intentionally by zero. */
count_leading_zeros (bm, d0);
if (bm == 0)
{
/* From (n1 >= d0) /\ (the most significant bit of d0 is set),
conclude (the most significant bit of n1 is set) /\ (the
leading quotient digit q1 = 1).
This special case is necessary, not an optimization.
(Shifts counts of W_TYPE_SIZE are undefined.) */
n1 -= d0;
q1 = 1;
}
else
{
/* Normalize. */
b = W_TYPE_SIZE - bm;
d0 = d0 << bm;
n2 = n1 >> b;
n1 = (n1 << bm) | (n0 >> b);
n0 = n0 << bm;
udiv_qrnnd (q1, n1, n2, n1, d0);
}
/* n1 != d0... */
udiv_qrnnd (q0, n0, n1, n0, d0);
/* Remainder in n0 >> bm. */
}
if (rp != 0)
{
rr.s.low = n0 >> bm;
rr.s.high = 0;
*rp = rr.ll;
}
}
#endif /* UDIV_NEEDS_NORMALIZATION */
else {
if (d1 > n1) {
/* 00 = nn / DD */
q0 = 0;
q1 = 0;
/* Remainder in n1n0. */
if (rp != 0) {
rr.s.low = n0;
rr.s.high = n1;
*rp = rr.ll;
}
} else {
/* 0q = NN / dd */
count_leading_zeros(bm, d1);
if (bm == 0) {
/* From (n1 >= d1) /\ (the most significant bit of d1 is set),
conclude (the most significant bit of n1 is set) /\ (the
quotient digit q0 = 0 or 1).
This special case is necessary, not an optimization. */
/* The condition on the next line takes advantage of that
n1 >= d1 (true due to program flow). */
if (n1 > d1 || n0 >= d0) {
q0 = 1;
sub_ddmmss(n1, n0, n1, n0, d1, d0);
} else
q0 = 0;
q1 = 0;
if (rp != 0) {
rr.s.low = n0;
rr.s.high = n1;
*rp = rr.ll;
}
} else {
UWtype m1, m0;
/* Normalize. */
b = W_TYPE_SIZE - bm;
d1 = (d1 << bm) | (d0 >> b);
d0 = d0 << bm;
n2 = n1 >> b;
n1 = (n1 << bm) | (n0 >> b);
n0 = n0 << bm;
udiv_qrnnd(q0, n1, n2, n1, d1);
umul_ppmm(m1, m0, q0, d0);
if (m1 > n1 || (m1 == n1 && m0 > n0)) {
q0--;
sub_ddmmss(m1, m0, m1, m0, d1, d0);
}
q1 = 0;
/* Remainder in (n1n0 - m1m0) >> bm. */
if (rp != 0) {
sub_ddmmss(n1, n0, n1, n0, m1, m0);
rr.s.low = (n1 << b) | (n0 >> bm);
rr.s.high = n1 >> bm;
*rp = rr.ll;
}
}
}
}
ww.s.low = q0;
ww.s.high = q1;
return ww.ll;
}
__attribute__((used)) long long __moddi3(long long u, long long v) {
int c = 0;
DWunion uu, vv;
DWtype w;
uu.ll = u;
vv.ll = v;
if (uu.s.high < 0) {
c = ~c;
uu.ll = __negdi2 (uu.ll);
}
if (vv.s.high < 0)
vv.ll = __negdi2 (vv.ll);
__udivmoddi4(uu.ll, vv.ll, (UDWtype *) &w);
if (c)
w = __negdi2 (w);
return w;
}
int rand() {
2024-09-01 14:56:38 +08:00
unsigned short i = 0;
2024-09-08 22:43:05 +08:00
while (i < randlevel)
rand_seed = rand_seed * 1103515245 + 12345, rand_seed <<= max_bit, i++;
return (rand_seed >>= max_bit);
2024-09-01 14:56:38 +08:00
}
2024-09-08 22:43:05 +08:00
void srand(unsigned seed) {
rand_seed = seed;
2024-09-01 14:56:38 +08:00
}
2024-09-08 22:43:05 +08:00
void smax(unsigned short max_b) {
max_b = (sizeof(unsigned long long) * 8) - (max_b % (sizeof(unsigned long long) * 8));
max_bit = (max_b == 0) ? (sizeof(unsigned long long) * 8 / 2) : (max_b);
2024-09-01 14:56:38 +08:00
}
2024-09-08 22:43:05 +08:00
void srandlevel(unsigned short randlevel_) {
if (randlevel_ != 0)
randlevel = randlevel_;
2024-09-01 14:56:38 +08:00
}
2024-09-08 22:43:05 +08:00
int32_t abs(int32_t x) {
return (x < 0) ? (-x) : (x);
2024-09-01 14:56:38 +08:00
}
2024-09-08 22:43:05 +08:00
double pow(double a, long long b) {
char t = 0;
if (b < 0)b = -b, t = 1;
double ans = 1;
while (b) {
if (b & 1)ans *= a;
a *= a;
b >>= 1;
2024-09-01 14:56:38 +08:00
}
2024-09-08 22:43:05 +08:00
if (t)return (1.0 / ans);
else return ans;
2024-09-01 14:56:38 +08:00
}
//快速整数平方
2024-09-08 22:43:05 +08:00
unsigned long long ull_pow(unsigned long long a, unsigned long long b) {
unsigned long long ans = 1;
while (b) {
if (b & 1)ans *= a;
a *= a;
b >>= 1;
2024-09-01 14:56:38 +08:00
}
2024-09-08 22:43:05 +08:00
return ans;
2024-09-01 14:56:38 +08:00
}
2024-09-08 22:43:05 +08:00
double sqrt(double x) {
if (x == 0)return 0.0;
double xk = 1.0, xk1 = 0.0;
while (xk != xk1)xk1 = xk, xk = (xk + x / xk) / 2.0;
return xk;
2024-09-01 14:56:38 +08:00
}
//快速求算数平方根(速度快,精度低)
2024-09-08 22:43:05 +08:00
float q_sqrt(float number) {
long i;
float x, y;
const float f = 1.5F;
x = number * 0.5F;
y = number;
i = *(long *) (&y);
i = 0x5f3759df - (i >> 1);
y = *(float *) (&i);
y = y * (f - (x * y * y));
y = y * (f - (x * y * y));
return number * y;
}
double mod(double x, double y) {
2024-09-01 16:43:58 +08:00
return x - (int32_t)(x / y) * y;
}
2024-09-08 22:43:05 +08:00
double sin(double x) {
x = mod(x, 2 * PI);
double sum = x;
double term = x;
int n = 1;
2024-09-01 16:43:58 +08:00
bool sign = true;
while (term > F64_EPSILON || term < -F64_EPSILON) {
2024-09-08 22:43:05 +08:00
n += 2;
2024-09-01 16:43:58 +08:00
term *= x * x / (n * (n - 1));
2024-09-08 22:43:05 +08:00
sum += sign ? -term : term;
sign = !sign;
2024-09-01 16:43:58 +08:00
}
return sum;
}
2024-09-08 22:43:05 +08:00
double cos(double x) {
x = mod(x, 2 * PI);
double sum = 1;
double term = 1;
int n = 0;
2024-09-01 16:43:58 +08:00
bool sign = true;
while (term > F64_EPSILON || term < -F64_EPSILON) {
2024-09-08 22:43:05 +08:00
n += 2;
2024-09-01 16:43:58 +08:00
term *= x * x / (n * (n - 1));
2024-09-08 22:43:05 +08:00
sum += sign ? -term : term;
sign = !sign;
2024-09-01 16:43:58 +08:00
}
return sum;
}
double tan(double x) {
return sin(x) / cos(x);
}
2024-09-08 22:43:05 +08:00
double asin(double x) {
double sum = x;
2024-09-01 16:43:58 +08:00
double term = x;
2024-09-08 22:43:05 +08:00
int n = 1;
2024-09-01 16:43:58 +08:00
while (term > F64_EPSILON || term < -F64_EPSILON) {
term *= (x * x * (2 * n - 1) * (2 * n - 1)) / (2 * n * (2 * n + 1));
2024-09-08 22:43:05 +08:00
sum += term;
2024-09-01 16:43:58 +08:00
n++;
}
return sum;
}
double acos(double x) {
return PI / 2 - asin(x);
}
2024-09-08 22:43:05 +08:00
double atan(double x) {
double sum = x;
double term = x;
int n = 1;
2024-09-01 16:43:58 +08:00
bool sign = true;
while (term > F64_EPSILON || term < -F64_EPSILON) {
term *= x * x * (2 * n - 1) / (2 * n + 1);
2024-09-08 22:43:05 +08:00
sum += sign ? -term : term;
sign = !sign;
2024-09-01 16:43:58 +08:00
n++;
}
return sum;
}
2024-09-08 22:43:05 +08:00
double atan2(double y, double x) {
2024-09-01 16:43:58 +08:00
if (x > 0) return atan(y / x);
if (x < 0 && y >= 0) return atan(y / x) + PI;
if (x < 0 && y < 0) return atan(y / x) - PI;
if (x == 0 && y > 0) return PI / 2;
if (x == 0 && y < 0) return -PI / 2;
return 0;
}
2024-09-08 22:43:05 +08:00
double floor(double x) {
int flag = 1;
if (fabs(x) == x) {
flag = 0;
}
if (flag) {
double r = (x); // 如果小于则返回x-1的整数部分
double s;
modf(r, &s);
return s - 1;
} else {
double r = (x); // 如果大于等于则返回x的整数部分
double s;
modf(r, &s);
return s;
}
}
double modf(double x, double *iptr) {
union {
double f;
uint64_t i;
} u = {x};
uint64_t mask;
int e = (int) (u.i >> 52 & 0x7ff) - 0x3ff;
/* no fractional part */
if (e >= 52) {
*iptr = x;
if (e == 0x400 && u.i << 12 != 0) /* nan */
return x;
u.i &= 1ULL << 63;
return u.f;
}
/* no integral part*/
if (e < 0) {
u.i &= 1ULL << 63;
*iptr = u.f;
return x;
}
mask = -1ULL >> 12 >> e;
if ((u.i & mask) == 0) {
*iptr = x;
u.i &= 1ULL << 63;
return u.f;
}
u.i &= ~mask;
*iptr = u.f;
return x - u.f;
}
double fabs(double x) {
union {
double f;
uint64_t i;
} u = {x};
u.i &= -1ULL / 2;
return u.f;
}
double ceil(double x) {
int flag = 0;
if (fabs(x) == x) {
flag = 1;
}
if (flag) {
double r = (x); // 如果小于则返回x-1的整数部分
double s;
modf(r, &s);
return s + 1;
} else {
double r = (x); // 如果大于等于则返回x的整数部分
double s;
modf(r, &s);
return s;
}
}
#define __negdi2(a) (-(a))
long long __divdi3(long long u, long long v) {
int c = 0;
DWunion uu, vv;
DWtype w;
uu.ll = u;
vv.ll = v;
if (uu.s.high < 0) {
c = ~c;
uu.ll = __negdi2 (uu.ll);
}
if (vv.s.high < 0) {
c = ~c;
vv.ll = __negdi2 (vv.ll);
}
w = __udivmoddi4(uu.ll, vv.ll, (UDWtype *) 0);
if (c)
w = __negdi2 (w);
return w;
}
double frexp(double x, int *e) {
union {
double d;
uint64_t i;
} y = {x};
int ee = y.i >> 52 & 0x7ff;
if (!ee) {
if (x) {
x = frexp(x * 0x1p64, e);
*e -= 64;
} else
*e = 0;
return x;
} else if (ee == 0x7ff) {
return x;
}
*e = ee - 0x3fe;
y.i &= 0x800fffffffffffffull;
y.i |= 0x3fe0000000000000ull;
return y.d;
}
double scalbn(double x, int n) {
union {
double f;
uint64_t i;
} u;
double y = x;
if (n > 1023) {
y *= 0x1p1023;
n -= 1023;
if (n > 1023) {
y *= 0x1p1023;
n -= 1023;
if (n > 1023)
n = 1023;
}
} else if (n < -1022) {
y *= 0x1p-1022;
n += 1022;
if (n < -1022) {
y *= 0x1p-1022;
n += 1022;
if (n < -1022)
n = -1022;
}
}
u.i = (uint64_t)(0x3ff + n) << 52;
x = y * u.f;
return x;
}
double scalbln(double x, long n) {
if (n > INT_MAX)
n = INT_MAX;
else if (n < INT_MIN)
n = INT_MIN;
return scalbn(x, n);
}
double ldexp(double x, int n) { return scalbn(x, n); }
float scalbnf(float x, int n) {
union {
float f;
uint32_t i;
} u;
float y = x;
if (n > 127) {
y *= 0x1p127f;
n -= 127;
if (n > 127) {
y *= 0x1p127f;
n -= 127;
if (n > 127)
n = 127;
}
} else if (n < -126) {
y *= 0x1p-126f * 0x1p24f;
n += 126 - 24;
if (n < -126) {
y *= 0x1p-126f * 0x1p24f;
n += 126 - 24;
if (n < -126)
n = -126;
}
}
u.i = (uint32_t)(0x7f + n) << 23;
x = y * u.f;
return x;
}
double fmod(double x, double y) {
return x - (x / y) * y;
/*
union {
double f;
uint64_t i;
} ux = {x}, uy = {y};
int ex = ux.i >> 52 & 0x7ff;
int ey = uy.i >> 52 & 0x7ff;
int sx = ux.i >> 63;
uint64_t i;
uint64_t uxi = ux.i;
if (uy.i << 1 == 0 || isnan(y) || ex == 0x7ff)
return (x * y) / (x * y);
if (uxi << 1 <= uy.i << 1) {
if (uxi << 1 == uy.i << 1)
return 0 * x;
return x;
}
if (!ex) {
for (i = uxi << 12; i >> 63 == 0; ex--, i <<= 1);
uxi <<= -ex + 1;
} else {
uxi &= -1ULL >> 12;
uxi |= 1ULL << 52;
}
if (!ey) {
for (i = uy.i << 12; i >> 63 == 0; ey--, i <<= 1);
uy.i <<= -ey + 1;
} else {
uy.i &= -1ULL >> 12;
uy.i |= 1ULL << 52;
}
for (; ex > ey; ex--) {
i = uxi - uy.i;
if (i >> 63 == 0) {
if (i == 0)
return 0 * x;
uxi = i;
}
uxi <<= 1;
}
i = uxi - uy.i;
if (i >> 63 == 0) {
if (i == 0)
return 0 * x;
uxi = i;
}
for (; uxi >> 52 == 0; uxi <<= 1, ex--);
if (ex > 0) {
uxi -= 1ULL << 52;
uxi |= (uint64_t) ex << 52;
} else {
uxi >>= -ex + 1;
}
uxi |= (uint64_t) sx << 63;
ux.i = uxi;
return ux.f;
*/
}
double exp(double x) {
x = 1.0 + x / 256;
x *= x;
x *= x;
x *= x;
x *= x;
x *= x;
x *= x;
x *= x;
x *= x;
return x;
}
double log10(double x) {
union {
double f;
uint64_t i;
} u = {x};
double hfsq, f, s, z, R, w, t1, t2, dk, y, hi, lo, val_hi, val_lo;
uint32_t hx;
int k;
hx = u.i >> 32;
k = 0;
if (hx < 0x00100000 || hx >> 31) {
if (u.i << 1 == 0)
return -1 / (x * x); /* log(+-0)=-inf */
if (hx >> 31)
return (x - x) / 0.0; /* log(-#) = NaN */
/* subnormal number, scale x up */
k -= 54;
x *= 0x1p54;
u.f = x;
hx = u.i >> 32;
} else if (hx >= 0x7ff00000) {
return x;
} else if (hx == 0x3ff00000 && u.i << 32 == 0)
return 0;
/* reduce x into [sqrt(2)/2, sqrt(2)] */
hx += 0x3ff00000 - 0x3fe6a09e;
k += (int) (hx >> 20) - 0x3ff;
hx = (hx & 0x000fffff) + 0x3fe6a09e;
u.i = (uint64_t) hx << 32 | (u.i & 0xffffffff);
x = u.f;
f = x - 1.0;
hfsq = 0.5 * f * f;
s = f / (2.0 + f);
z = s * s;
w = z * z;
t1 = w * (Lg2 + w * (Lg4 + w * Lg6));
t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7)));
R = t2 + t1;
/* See log2.c for details. */
/* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */
hi = f - hfsq;
u.f = hi;
u.i &= (uint64_t) - 1 << 32;
hi = u.f;
lo = f - hi - hfsq + s * (hfsq + R);
/* val_hi+val_lo ~ log10(1+f) + k*log10(2) */
val_hi = hi * ivln10hi;
dk = k;
y = dk * log10_2hi;
val_lo = dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi;
/*
* Extra precision in for adding y is not strictly needed
* since there is no very large cancellation near x = sqrt(2) or
* x = 1/sqrt(2), but we do it anyway since it costs little on CPUs
* with some parallelism and it reduces the error for many args.
*/
w = y + val_hi;
val_lo += (y - w) + val_hi;
val_hi = w;
return val_lo + val_hi;
}
double log2(float x) {
long *a;
double o;
a = (long *) &x;
o = (double) *a;
o = o / POW223 - 126.928071372;
return o;
}
double log(double a) {
int N = 15;//我们取了前15+1项来估算
int k, nk;
double x, xx, y;
x = (a - 1) / (a + 1);
xx = x * x;
nk = 2 * N + 1;
y = 1.0 / nk;
for (k = N; k > 0; k--) {
nk = nk - 2;
y = 1.0 / nk + xx * y;
}
return 2.0 * x * y;
}
unsigned long long __udivdi3(unsigned long long u, unsigned long long v) {
return __udivmoddi4(u, v, (UDWtype *) 0);
}
unsigned long long __umoddi3(unsigned long long u, unsigned long long v) {
UDWtype w;
__udivmoddi4(u, v, &w);
return w;
}