varch/source/07_math/flmath.c

334 lines
11 KiB
C

/*********************************************************************************************************
* ------------------------------------------------------------------------------------------------------
* file description
* ------------------------------------------------------------------------------------------------------
* \file flmath.c
* \unit flmath
* \brief This is a simple large float number math calculate module for C language
* \author Lamdonn
* \version v1.0.1
* \license GPL-2.0
* \copyright Copyright (C) 2023 Lamdonn.
********************************************************************************************************/
#include "flmath.h"
// Number of terms in the Taylor series for trigonometric functions
static const int trig_terms = 15 * sizeof(floatl) / 8;
// Number of terms in the Taylor series for the exponential function
static const int exp_terms = 15 * sizeof(floatl) / 8;
// Number of terms in the Taylor series for the natural logarithm function
static const int ln_terms = 15 * sizeof(floatl) / 8;
/**
* \brief Calculates the factorial of an integer.
* \param n: The integer for which the factorial is to be calculated.
* \return A 'floatl' number representing the factorial of 'n'.
*/
static floatl floatl_int_fact(int n)
{
floatl result = FLOATL_CONST_1;
for (int i = 1; i <= n; i++)
{
result = floatl_mul(result, floatl(i));
}
return result;
}
/**
* \brief Calculates the power of a 'floatl' number with an integer exponent.
* \param base: The base 'floatl' number.
* \param exponent: The integer exponent.
* \return A 'floatl' number representing 'base' raised to the power of 'exponent'.
*/
static floatl floatl_int_power(floatl base, int exponent)
{
floatl result = FLOATL_CONST_1;
for (int i = 0; i < exponent; i++)
{
result = floatl_mul(result, base);
}
return result;
}
/**
* \brief Calculates the sine of a 'floatl' number using the Taylor series expansion.
* \param x: The 'floatl' number for which the sine is to be calculated.
* \return A 'floatl' number representing the sine of 'x'.
*/
floatl floatl_sin(floatl x)
{
floatl result = FLOATL_CONST_0;
// Normalize x to the range [-π, π]
while (floatl_gt(x, FLOATL_PI))
{
x = floatl_sub(x, FLOATL_PI);
x = floatl_sub(x, FLOATL_PI);
}
while (floatl_lt(x, floatl_neg(FLOATL_PI)))
{
x = floatl_add(x, FLOATL_PI);
x = floatl_add(x, FLOATL_PI);
}
for (int n = 0; n < trig_terms; n++)
{
floatl term = floatl_int_power(floatl_neg(FLOATL_CONST_1), n);
term = floatl_mul(term, floatl_int_power(x, 2 * n + 1));
term = floatl_div(term, floatl_int_fact(2 * n + 1));
result = floatl_add(result, term);
}
return result;
}
/**
* \brief Calculates the cosine of a 'floatl' number using the sine function.
* \param x: The 'floatl' number for which the cosine is to be calculated.
* \return A 'floatl' number representing the cosine of 'x'.
*/
floatl floatl_cos(floatl x)
{
x = floatl_add(x, floatl_mul(floatl(0.5), FLOATL_PI));
return floatl_sin(x);
}
/**
* \brief Calculates the secant of a 'floatl' number.
* \param x: The 'floatl' number for which the secant is to be calculated.
* \return A 'floatl' number representing the secant of 'x'.
*/
floatl floatl_sec(floatl x)
{
return floatl_div(FLOATL_CONST_1, floatl_cos(x));
}
/**
* \brief Calculates the cosecant of a 'floatl' number.
* \param x: The 'floatl' number for which the cosecant is to be calculated.
* \return A 'floatl' number representing the cosecant of 'x'.
*/
floatl floatl_csc(floatl x)
{
return floatl_div(FLOATL_CONST_1, floatl_sin(x));
}
/**
* \brief Calculates the tangent of a 'floatl' number.
* \param x: The 'floatl' number for which the tangent is to be calculated.
* \return A 'floatl' number representing the tangent of 'x'. Returns infinity or negative infinity
* if the cosine of 'x' is zero.
*/
floatl floatl_tan(floatl x)
{
floatl s = floatl_sin(x);
floatl c = floatl_cos(x);
if (floatl_eq(c, FLOATL_CONST_0))
{
return (floatl_gt(s, FLOATL_CONST_0)) ? FLOATL_INF : floatl_neg(FLOATL_INF);
}
return floatl_div(s, c);
}
/**
* \brief Calculates the cotangent of a 'floatl' number.
* \param x: The 'floatl' number for which the cotangent is to be calculated.
* \return A 'floatl' number representing the cotangent of 'x'.
*/
floatl floatl_cot(floatl x)
{
x = floatl_sub(floatl_mul(floatl(0.5), FLOATL_PI), x);
return floatl_tan(x);
}
/**
* \brief Calculates the exponential function of a 'floatl' number using the Taylor series expansion.
* \param x: The 'floatl' number for which the exponential is to be calculated.
* \return A 'floatl' number representing e raised to the power of 'x'.
*/
floatl floatl_exp(floatl x)
{
floatl result = FLOATL_CONST_0;
for (int n = 0; n < exp_terms; n++)
{
floatl term = floatl_int_power(x, n);
term = floatl_div(term, floatl_int_fact(n));
result = floatl_add(result, term);
}
return result;
}
/**
* \brief Calculates the natural logarithm of a 'floatl' number using the Taylor series expansion.
* \param x: The 'floatl' number for which the natural logarithm is to be calculated.
* \return A 'floatl' number representing the natural logarithm of 'x'. Returns -1 if 'x' is less than or equal to 0.
*/
floatl floatl_ln(floatl x)
{
if (floatl_le(x, FLOATL_CONST_0)) return floatl_neg(FLOATL_CONST_1);
floatl result = FLOATL_CONST_0;
// Transform x to the range (0, 2]
floatl y = floatl_sub(x, FLOATL_CONST_1);
y = floatl_div(y, floatl_add(x, FLOATL_CONST_1));
for (int n = 0; n < ln_terms; n++)
{
floatl term = floatl_int_power(y, 2 * n + 1);
term = floatl_div(term, floatl(2 * n + 1));
result = floatl_add(result, term);
}
result = floatl_mul(result, floatl(2.0));
return result;
}
/**
* \brief Calculates the logarithm of a 'floatl' number with a given base.
* \param x: The base 'floatl' number.
* \param y: The 'floatl' number for which the logarithm is to be calculated.
* \return A 'floatl' number representing the logarithm of 'y' with base 'x'. Returns negative infinity
* if 'x' is zero or 'y' is less than or equal to 0.
*/
floatl floatl_log(floatl x, floatl y)
{
if ((floatl_eq(x, FLOATL_CONST_0)) || (floatl_le(y, FLOATL_CONST_0))) return floatl_neg(FLOATL_INF);
return floatl_div(floatl_ln(y), floatl_ln(x));
}
/**
* \brief Calculates the logarithm of a 'floatl' number with base 2.
* \param x: The 'floatl' number for which the logarithm is to be calculated.
* \return A 'floatl' number representing the logarithm of 'x' with base 2. Returns negative infinity
* if 'x' is zero.
*/
floatl floatl_log2(floatl x)
{
if (floatl_eq(x, FLOATL_CONST_0)) return floatl_neg(FLOATL_INF);
return floatl_div(floatl_ln(x), floatl_ln(floatl(2.0)));
}
/**
* \brief Calculates the logarithm of a 'floatl' number with base 10.
* \param x: The 'floatl' number for which the logarithm is to be calculated.
* \return A 'floatl' number representing the logarithm of 'x' with base 10. Returns negative infinity
* if 'x' is zero.
*/
floatl floatl_log10(floatl x)
{
if (floatl_eq(x, FLOATL_CONST_0)) return floatl_neg(FLOATL_INF);
return floatl_div(floatl_ln(x), floatl_ln(floatl(10.0)));
}
/**
* \brief Calculates the sigmoid function of a 'floatl' number.
* \param x: The 'floatl' number for which the sigmoid is to be calculated.
* \return A 'floatl' number representing the sigmoid of 'x'.
*/
floatl floatl_sigmoid(floatl x)
{
return floatl_div(FLOATL_CONST_1, floatl_add(FLOATL_CONST_1, floatl_exp(floatl_neg(x))));
}
/**
* \brief Calculates the derivative of the sigmoid function of a 'floatl' number.
* \param x: The 'floatl' number for which the derivative of the sigmoid is to be calculated.
* \return A 'floatl' number representing the derivative of the sigmoid of 'x'.
*/
floatl floatl_dsigmoid(floatl x)
{
floatl s = floatl_sigmoid(x);
return floatl_mul(s, floatl_sub(FLOATL_CONST_1, s));
}
/**
* \brief Calculates the hyperbolic sine of a 'floatl' number.
* \param x: The 'floatl' number for which the hyperbolic sine is to be calculated.
* \return A 'floatl' number representing the hyperbolic sine of 'x'.
*/
floatl floatl_sinh(floatl x)
{
floatl a = floatl_exp(x);
return floatl_div(floatl_sub(a, floatl_div(FLOATL_CONST_1, a)), floatl(2.0));
}
/**
* \brief Calculates the hyperbolic cosine of a 'floatl' number.
* \param x: The 'floatl' number for which the hyperbolic cosine is to be calculated.
* \return A 'floatl' number representing the hyperbolic cosine of 'x'.
*/
floatl floatl_cosh(floatl x)
{
floatl a = floatl_exp(x);
return floatl_div(floatl_add(a, floatl_div(FLOATL_CONST_1, a)), floatl(2.0));
}
/**
* \brief Calculates the hyperbolic tangent of a 'floatl' number.
* \param x: The 'floatl' number for which the hyperbolic tangent is to be calculated.
* \return A 'floatl' number representing the hyperbolic tangent of 'x'.
*/
floatl floatl_tanh(floatl x)
{
floatl a = floatl_exp(x);
floatl b = floatl_div(FLOATL_CONST_1, a);
return floatl_div(floatl_sub(a, b), floatl_add(a, b));
}
/**
* \brief Calculates the hyperbolic cotangent of a 'floatl' number.
* \param x: The 'floatl' number for which the hyperbolic cotangent is to be calculated.
* \return A 'floatl' number representing the hyperbolic cotangent of 'x'.
*/
floatl floatl_coth(floatl x)
{
floatl a = floatl_exp(x);
floatl b = floatl_div(FLOATL_CONST_1, a);
return floatl_div(floatl_add(a, b), floatl_sub(a, b));
}
/**
* \brief Calculates the hyperbolic secant of a 'floatl' number.
* \param x: The 'floatl' number for which the hyperbolic secant is to be calculated.
* \return A 'floatl' number representing the hyperbolic secant of 'x'.
*/
floatl floatl_sech(floatl x)
{
floatl a = floatl_exp(x);
return floatl_div(floatl(2.0), floatl_add(a, floatl_div(FLOATL_CONST_1, a)));
}
/**
* \brief Calculates the hyperbolic cosecant of a 'floatl' number.
* \param x: The 'floatl' number for which the hyperbolic cosecant is to be calculated.
* \return A 'floatl' number representing the hyperbolic cosecant of 'x'.
*/
floatl floatl_csch(floatl x)
{
floatl a = floatl_exp(x);
return floatl_div(floatl(2.0), floatl_sub(a, floatl_div(FLOATL_CONST_1, a)));
}
/**
* \brief Calculates the square root of a 'floatl' number using the Newton - Raphson method.
* \param x: The 'floatl' number for which the square root is to be calculated.
* \return A 'floatl' number representing the square root of 'x'. Returns -1 if 'x' is less than 0.
*/
floatl floatl_sqrt(floatl x)
{
if (floatl_lt(x, FLOATL_CONST_0)) return floatl_neg(FLOATL_CONST_1);
floatl a = x; // Initial guess
floatl epsilon = floatl(1e-7); // Precision
while (floatl_gt(floatl_sub(floatl_mul(a, a), x), epsilon))
{
a = floatl_add(a, floatl_div(x, a));
a = floatl_div(a, floatl(2.0));
}
return a;
}
/**
* \brief Calculates the power of a 'floatl' number with another 'floatl' exponent.
* \param x: The base 'floatl' number.
* \param y: The exponent 'floatl' number.
* \return A 'floatl' number representing 'x' raised to the power of 'y'.
*/
floatl floatl_pow(floatl x, floatl y)
{
return floatl_exp(floatl_mul(y, floatl_ln(x)));
}