/**
|
|
* This code is available at
|
|
* http://www.mindspring.com/~pfilandr/C/fs_math/
|
|
* and it is believed to be public domain.
|
|
*/
|
|
|
|
/* BEGIN fs_math.c */
|
|
|
|
#include "libs/fs_math.h"
|
|
|
|
#include <float.h>
|
|
/*
|
|
** pi == (atan(1.0 / 3) + atan(1.0 / 2)) * 4
|
|
*/
|
|
static double fs_pi(void);
|
|
static long double fs_pil(void);
|
|
|
|
double fs_sqrt(double x)
|
|
{
|
|
int n;
|
|
double a, b;
|
|
|
|
if (x > 0 && DBL_MAX >= x) {
|
|
for (n = 0; x > 2; x /= 4) {
|
|
++n;
|
|
}
|
|
while (0.5 > x) {
|
|
--n;
|
|
x *= 4;
|
|
}
|
|
a = x;
|
|
b = (1 + x) / 2;
|
|
do {
|
|
x = b;
|
|
b = (a / x + x) / 2;
|
|
} while (x > b);
|
|
while (n > 0) {
|
|
x *= 2;
|
|
--n;
|
|
}
|
|
while (0 > n) {
|
|
x /= 2;
|
|
++n;
|
|
}
|
|
} else {
|
|
if (x != 0) {
|
|
x = DBL_MAX;
|
|
}
|
|
}
|
|
return x;
|
|
}
|
|
|
|
double fs_log(double x)
|
|
{
|
|
int n;
|
|
double a, b, c, epsilon;
|
|
static double A, B, C;
|
|
static int initialized;
|
|
|
|
if (x > 0 && DBL_MAX >= x) {
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
A = fs_sqrt(2);
|
|
B = A / 2;
|
|
C = fs_log(A);
|
|
}
|
|
for (n = 0; x > A; x /= 2) {
|
|
++n;
|
|
}
|
|
while (B > x) {
|
|
--n;
|
|
x *= 2;
|
|
}
|
|
a = (x - 1) / (x + 1);
|
|
x = C * n + a;
|
|
c = a * a;
|
|
n = 1;
|
|
epsilon = DBL_EPSILON * x;
|
|
if (0 > a) {
|
|
if (epsilon > 0) {
|
|
epsilon = -epsilon;
|
|
}
|
|
do {
|
|
n += 2;
|
|
a *= c;
|
|
b = a / n;
|
|
x += b;
|
|
} while (epsilon > b);
|
|
} else {
|
|
if (0 > epsilon) {
|
|
epsilon = -epsilon;
|
|
}
|
|
do {
|
|
n += 2;
|
|
a *= c;
|
|
b = a / n;
|
|
x += b;
|
|
} while (b > epsilon);
|
|
}
|
|
x *= 2;
|
|
} else {
|
|
x = -DBL_MAX;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
double fs_log10(double x)
|
|
{
|
|
static double log_10;
|
|
static int initialized;
|
|
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
log_10 = fs_log(10);
|
|
}
|
|
return x > 0 && DBL_MAX >= x ? fs_log(x) / log_10 : fs_log(x);
|
|
}
|
|
|
|
double fs_exp(double x)
|
|
{
|
|
unsigned n, square;
|
|
double b, e;
|
|
static double x_max, x_min, epsilon;
|
|
static int initialized;
|
|
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
x_max = fs_log(DBL_MAX);
|
|
x_min = fs_log(DBL_MIN);
|
|
epsilon = DBL_EPSILON / 4;
|
|
}
|
|
if (x_max >= x && x >= x_min) {
|
|
for (square = 0; x > 1; x /= 2) {
|
|
++square;
|
|
}
|
|
while (-1 > x) {
|
|
++square;
|
|
x /= 2;
|
|
}
|
|
e = b = n = 1;
|
|
do {
|
|
b /= n++;
|
|
b *= x;
|
|
e += b;
|
|
b /= n++;
|
|
b *= x;
|
|
e += b;
|
|
} while (b > epsilon);
|
|
while (square-- != 0) {
|
|
e *= e;
|
|
}
|
|
} else {
|
|
e = x > 0 ? DBL_MAX : 0;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
double fs_modf(double value, double *iptr)
|
|
{
|
|
double a, b;
|
|
const double c = value;
|
|
|
|
if (0 > c) {
|
|
value = -value;
|
|
}
|
|
if (DBL_MAX >= value) {
|
|
for (*iptr = 0; value >= 1; value -= b) {
|
|
a = value / 2;
|
|
b = 1;
|
|
while (a >= b) {
|
|
b *= 2;
|
|
}
|
|
*iptr += b;
|
|
}
|
|
} else {
|
|
*iptr = value;
|
|
value = 0;
|
|
}
|
|
if (0 > c) {
|
|
*iptr = -*iptr;
|
|
value = -value;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
double fs_fmod(double x, double y)
|
|
{
|
|
double a, b;
|
|
const double c = x;
|
|
|
|
if (0 > c) {
|
|
x = -x;
|
|
}
|
|
if (0 > y) {
|
|
y = -y;
|
|
}
|
|
if (y != 0 && DBL_MAX >= y && DBL_MAX >= x) {
|
|
while (x >= y) {
|
|
a = x / 2;
|
|
b = y;
|
|
while (a >= b) {
|
|
b *= 2;
|
|
}
|
|
x -= b;
|
|
}
|
|
} else {
|
|
x = 0;
|
|
}
|
|
return 0 > c ? -x : x;
|
|
}
|
|
|
|
double fs_pow(double x, double y)
|
|
{
|
|
double p = 0;
|
|
|
|
if (0 > x && fs_fmod(y, 1) == 0) {
|
|
if (fs_fmod(y, 2) == 0) {
|
|
p = fs_exp(fs_log(-x) * y);
|
|
} else {
|
|
p = -fs_exp(fs_log(-x) * y);
|
|
}
|
|
} else {
|
|
if (x != 0 || 0 >= y) {
|
|
p = fs_exp(fs_log( x) * y);
|
|
}
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static double fs_pi(void)
|
|
{
|
|
unsigned n;
|
|
double a, b, epsilon;
|
|
static double p;
|
|
static int initialized;
|
|
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
epsilon = DBL_EPSILON / 4;
|
|
n = 1;
|
|
a = 3;
|
|
do {
|
|
a /= 9;
|
|
b = a / n;
|
|
n += 2;
|
|
a /= 9;
|
|
b -= a / n;
|
|
n += 2;
|
|
p += b;
|
|
} while (b > epsilon);
|
|
epsilon = DBL_EPSILON / 2;
|
|
n = 1;
|
|
a = 2;
|
|
do {
|
|
a /= 4;
|
|
b = a / n;
|
|
n += 2;
|
|
a /= 4;
|
|
b -= a / n;
|
|
n += 2;
|
|
p += b;
|
|
} while (b > epsilon);
|
|
p *= 4;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
double fs_cos(double x)
|
|
{
|
|
unsigned n;
|
|
int negative, sine;
|
|
double a, b, c;
|
|
static double pi, two_pi, half_pi, third_pi, epsilon;
|
|
static int initialized;
|
|
|
|
if (0 > x) {
|
|
x = -x;
|
|
}
|
|
if (DBL_MAX >= x) {
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
pi = fs_pi();
|
|
two_pi = 2 * pi;
|
|
half_pi = pi / 2;
|
|
third_pi = pi / 3;
|
|
epsilon = DBL_EPSILON / 2;
|
|
}
|
|
if (x > two_pi) {
|
|
x = fs_fmod(x, two_pi);
|
|
}
|
|
if (x > pi) {
|
|
x = two_pi - x;
|
|
}
|
|
if (x > half_pi) {
|
|
x = pi - x;
|
|
negative = 1;
|
|
} else {
|
|
negative = 0;
|
|
}
|
|
if (x > third_pi) {
|
|
x = half_pi - x;
|
|
sine = 1;
|
|
} else {
|
|
sine = 0;
|
|
}
|
|
c = x * x;
|
|
x = n = 0;
|
|
a = 1;
|
|
do {
|
|
b = a;
|
|
a *= c;
|
|
a /= ++n;
|
|
a /= ++n;
|
|
b -= a;
|
|
a *= c;
|
|
a /= ++n;
|
|
a /= ++n;
|
|
x += b;
|
|
} while (b > epsilon);
|
|
if (sine) {
|
|
x = fs_sqrt((1 - x) * (1 + x));
|
|
}
|
|
if (negative) {
|
|
x = -x;
|
|
}
|
|
} else {
|
|
x = -DBL_MAX;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
double fs_log2(double x)
|
|
{
|
|
static double log_2;
|
|
static int initialized;
|
|
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
log_2 = fs_log(2);
|
|
}
|
|
return x > 0 && DBL_MAX >= x ? fs_log(x) / log_2 : fs_log(x);
|
|
}
|
|
|
|
double fs_exp2(double x)
|
|
{
|
|
static double log_2;
|
|
static int initialized;
|
|
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
log_2 = fs_log(2);
|
|
}
|
|
return fs_exp(x * log_2);
|
|
}
|
|
|
|
long double fs_powl(long double x, long double y)
|
|
{
|
|
long double p;
|
|
|
|
if (0 > x && fs_fmodl(y, 1) == 0) {
|
|
if (fs_fmodl(y, 2) == 0) {
|
|
p = fs_expl(fs_logl(-x) * y);
|
|
} else {
|
|
p = -fs_expl(fs_logl(-x) * y);
|
|
}
|
|
} else {
|
|
if (x != 0 || 0 >= y) {
|
|
p = fs_expl(fs_logl( x) * y);
|
|
} else {
|
|
p = 0;
|
|
}
|
|
}
|
|
return p;
|
|
}
|
|
|
|
long double fs_sqrtl(long double x)
|
|
{
|
|
long int n;
|
|
long double a, b;
|
|
|
|
if (x > 0 && LDBL_MAX >= x) {
|
|
for (n = 0; x > 2; x /= 4) {
|
|
++n;
|
|
}
|
|
while (0.5 > x) {
|
|
--n;
|
|
x *= 4;
|
|
}
|
|
a = x;
|
|
b = (1 + x) / 2;
|
|
do {
|
|
x = b;
|
|
b = (a / x + x) / 2;
|
|
} while (x > b);
|
|
while (n > 0) {
|
|
x *= 2;
|
|
--n;
|
|
}
|
|
while (0 > n) {
|
|
x /= 2;
|
|
++n;
|
|
}
|
|
} else {
|
|
if (x != 0) {
|
|
x = LDBL_MAX;
|
|
}
|
|
}
|
|
return x;
|
|
}
|
|
|
|
long double fs_logl(long double x)
|
|
{
|
|
long int n;
|
|
long double a, b, c, epsilon;
|
|
static long double A, B, C;
|
|
static int initialized;
|
|
|
|
if (x > 0 && LDBL_MAX >= x) {
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
B = 1.5;
|
|
do {
|
|
A = B;
|
|
B = 1 / A + A / 2;
|
|
} while (A > B);
|
|
B /= 2;
|
|
C = fs_logl(A);
|
|
}
|
|
for (n = 0; x > A; x /= 2) {
|
|
++n;
|
|
}
|
|
while (B > x) {
|
|
--n;
|
|
x *= 2;
|
|
}
|
|
a = (x - 1) / (x + 1);
|
|
x = C * n + a;
|
|
c = a * a;
|
|
n = 1;
|
|
epsilon = LDBL_EPSILON * x;
|
|
if (0 > a) {
|
|
if (epsilon > 0) {
|
|
epsilon = -epsilon;
|
|
}
|
|
do {
|
|
n += 2;
|
|
a *= c;
|
|
b = a / n;
|
|
x += b;
|
|
} while (epsilon > b);
|
|
} else {
|
|
if (0 > epsilon) {
|
|
epsilon = -epsilon;
|
|
}
|
|
do {
|
|
n += 2;
|
|
a *= c;
|
|
b = a / n;
|
|
x += b;
|
|
} while (b > epsilon);
|
|
}
|
|
x *= 2;
|
|
} else {
|
|
x = -LDBL_MAX;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
long double fs_expl(long double x)
|
|
{
|
|
long unsigned n, square;
|
|
long double b, e;
|
|
static long double x_max, x_min, epsilon;
|
|
static int initialized;
|
|
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
x_max = fs_logl(LDBL_MAX);
|
|
x_min = fs_logl(LDBL_MIN);
|
|
epsilon = LDBL_EPSILON / 4;
|
|
}
|
|
if (x_max >= x && x >= x_min) {
|
|
for (square = 0; x > 1; x /= 2) {
|
|
++square;
|
|
}
|
|
while (-1 > x) {
|
|
++square;
|
|
x /= 2;
|
|
}
|
|
e = b = n = 1;
|
|
do {
|
|
b /= n++;
|
|
b *= x;
|
|
e += b;
|
|
b /= n++;
|
|
b *= x;
|
|
e += b;
|
|
} while (b > epsilon);
|
|
while (square-- != 0) {
|
|
e *= e;
|
|
}
|
|
} else {
|
|
e = x > 0 ? LDBL_MAX : 0;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
static long double fs_pil(void)
|
|
{
|
|
long unsigned n;
|
|
long double a, b, epsilon;
|
|
static long double p;
|
|
static int initialized;
|
|
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
epsilon = LDBL_EPSILON / 4;
|
|
n = 1;
|
|
a = 3;
|
|
do {
|
|
a /= 9;
|
|
b = a / n;
|
|
n += 2;
|
|
a /= 9;
|
|
b -= a / n;
|
|
n += 2;
|
|
p += b;
|
|
} while (b > epsilon);
|
|
epsilon = LDBL_EPSILON / 2;
|
|
n = 1;
|
|
a = 2;
|
|
do {
|
|
a /= 4;
|
|
b = a / n;
|
|
n += 2;
|
|
a /= 4;
|
|
b -= a / n;
|
|
n += 2;
|
|
p += b;
|
|
} while (b > epsilon);
|
|
p *= 4;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
long double fs_cosl(long double x)
|
|
{
|
|
long unsigned n;
|
|
int negative, sine;
|
|
long double a, b, c;
|
|
static long double pi, two_pi, half_pi, third_pi, epsilon;
|
|
static int initialized;
|
|
|
|
if (0 > x) {
|
|
x = -x;
|
|
}
|
|
if (LDBL_MAX >= x) {
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
pi = fs_pil();
|
|
two_pi = 2 * pi;
|
|
half_pi = pi / 2;
|
|
third_pi = pi / 3;
|
|
epsilon = LDBL_EPSILON / 2;
|
|
}
|
|
if (x > two_pi) {
|
|
x = fs_fmodl(x, two_pi);
|
|
}
|
|
if (x > pi) {
|
|
x = two_pi - x;
|
|
}
|
|
if (x > half_pi) {
|
|
x = pi - x;
|
|
negative = 1;
|
|
} else {
|
|
negative = 0;
|
|
}
|
|
if (x > third_pi) {
|
|
x = half_pi - x;
|
|
sine = 1;
|
|
} else {
|
|
sine = 0;
|
|
}
|
|
c = x * x;
|
|
x = n = 0;
|
|
a = 1;
|
|
do {
|
|
b = a;
|
|
a *= c;
|
|
a /= ++n;
|
|
a /= ++n;
|
|
b -= a;
|
|
a *= c;
|
|
a /= ++n;
|
|
a /= ++n;
|
|
x += b;
|
|
} while (b > epsilon);
|
|
if (sine) {
|
|
x = fs_sqrtl((1 - x) * (1 + x));
|
|
}
|
|
if (negative) {
|
|
x = -x;
|
|
}
|
|
} else {
|
|
x = -LDBL_MAX;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
long double fs_fmodl(long double x, long double y)
|
|
{
|
|
long double a, b;
|
|
const long double c = x;
|
|
|
|
if (0 > c) {
|
|
x = -x;
|
|
}
|
|
if (0 > y) {
|
|
y = -y;
|
|
}
|
|
if (y != 0 && LDBL_MAX >= y && LDBL_MAX >= x) {
|
|
while (x >= y) {
|
|
a = x / 2;
|
|
b = y;
|
|
while (a >= b) {
|
|
b *= 2;
|
|
}
|
|
x -= b;
|
|
}
|
|
} else {
|
|
x = 0;
|
|
}
|
|
return 0 > c ? -x : x;
|
|
}
|
|
|
|
/* END fs_math.c */
|