mirror of
https://gitee.com/Lamdonn/varch.git
synced 2025-12-06 16:56:42 +08:00
334 lines
11 KiB
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.0
|
|
* \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)));
|
|
}
|