#include <stdio.h> #include <math.h> #include <stdint.h> #include <float.h> #define FLT_NAN (*(float*)(&_flt_nan__)) #define FLT_INF (*(float*)(&_flt_inf_positive__)) #define IsNan(_value) ((*(uint32_t*)&_value)==_flt_nan__) #define IsInf(_value) (((*(uint32_t*)&_value)&0x7fffffff) == _flt_inf_positive) uint32_t _flt_nan__ = 0x7fffffffL; uint32_t _flt_inf_positive__ = 0x7f800000L; uint32_t _flt_inf_negative__ = 0xff800000L; #define LOG2 (0.6931471805599453094172321214581765680755f) #define SQRT2 (1.4142135623737f) /** * @brief calculate the exponential. * @param [in] x input value of exp(x) * @return the result of exp(x) * @note Taylor deployment of exp function. */ float _expf(float x) { int i, k, negative = 0; float a, e, prev; // make x as -ln(2) < x < ln(2) k = (int)(x / LOG2 + (x >= 0) ? 0.5f : -0.5f); x -= k * LOG2; if (x < 0) { negative = 1; x = -x; } e = 1 + x; a = x; i = 2; do { a *= x / (i++); prev = e; e += a; } while (a > FLT_MIN); if (negative != 0) e = 1 / e; return _ldexpf(e, k); } /** * @brief personal version of ldexp * @param [in] x value x * @param [in] exp * @result x * 2^exp */ float _ldexpf(float x, int exp) { float twos_exponent; if (exp == 0) return x; exp += 127; if (exp >= 255 || exp <= 0) return FLT_NAN; exp <<= 23; twos_exponent = *(float*)(&exp); return x * twos_exponent; } /** * @brief separate the single real value as fraction and exponent */ float _frexpf(float x, int *exp) { uint32_t val = *(uint32_t*)(&x); int e = (val & 0x7f800000L) >> 23; uint32_t frac = val & 0x7fffffL; if (e == 0) { *exp = 0; return *(float*)(&val); } else if (e == 255) { *exp = 0; return FLT_NAN; } else { e -= 127; *exp = e + 1; uint32_t result = frac | (val & 0x80000000L); result |= ((-1) + 127) << 23; return *(float*)&result; } } /** * @brief personal version of fabs * @param [in] x value x * @return absolute value of x */ float _fabsf(float x) { uint32_t value = *(uint32_t*)(&x); value &= 0x7fffffffL; // make sign bit to zero return *(float*)(&value); } /** * @brief calculate ln * @param [in] x input value of ln(x) * @return the result of ln(x) * @note Euler transform of Taylor deployment of log function. */ float _logf(float x) { int ix, k; float u, u2, s, prev; if (x <= 0) return FLT_NAN; // error value // make x over than -1 and under than 1.0 to prevent emerging _frexpf(x / SQRT2, &k); // k = (int)(log2(y)-0.5) (we decrease the exponent by 0.5 to make easy to converge.) x /= _ldexpf(1.0f, k); // x = x / 2^k; u = (x - 1) / (x + 1); // get log u with u = (x - 1) / (x + 1) u2 = u * u; ix = 1; s = u; do { u *= u2; ix += 2; prev = s; s += u / ix; } while (_fabsf(prev - s) > FLT_MIN); return LOG2 * k + 2 * s; } /** * @brief calculate power of x^y * @param [in] x number to be raised * @param [in] y power of x^y * @return y th power of x */ float _powf(float x, float y) { if (y == (int)y) { float r = 1; int n = (int)((y > 0) ? y : (-y)); while (n != 0) { if (n & 1) r *= x; x *= x; n >>= 1; } if (y < 0) r = 1 / r; return r; } if (x > 0) { return _expf(y*_logf(x)); } else if (x != 0 || y <= 0) { return FLT_NAN; } return 0; } #if defined(_WIN32) || defined(_WIN64) /** * @brief Test program */ int main() { float val; float frac; for (int j = 0; j < 5; ++j) { for (int i = 0; i <= 20; ++i) { val = (float)i / 3.3f; frac = (float)j / 2.2f; printf("%.2f : %.2f : %.4f : %.4f\n", frac, val, powf(frac, val), _powf(frac, val)); } } getchar(); } #endif
_expf(float x) | exp(x)を求める |
_ldexpf(float x, int k) | x * 2^k を求める |
_frexpf(float x, int *exp) | 与えられた実数を、仮数部(0~0.5)と指数部に分解する |
_fabsf(float x) | 与えられた実数の絶対値を求める |
_logf(float x) | 与えられた実数の自然対数を求める |
_powf(float x, float y) | x^y を求める |