/******************************************************************************** * * * M a t h F u n c t i o n s * * * ********************************************************************************* * Copyright (C) 2015,2024 by Jeroen van der Zijp. All Rights Reserved. * ********************************************************************************* * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public License * * along with this program. If not, see * ********************************************************************************/ #ifndef FXMATH_H #define FXMATH_H // Remove macros #undef fabs #undef fabsf #undef fmod #undef fmodf #undef ceil #undef ceilf #undef floor #undef floorf #undef round #undef roundf #undef trunc #undef truncf #undef nearbyint #undef nearbyintf #undef rint #undef rintf #undef sin #undef sinf #undef cos #undef cosf #undef tan #undef tanf #undef asin #undef asinf #undef acos #undef acosf #undef atan #undef atanf #undef atan2 #undef atan2f #undef sincos #undef sincosf #undef sinh #undef sinhf #undef cosh #undef coshf #undef tanh #undef tanhf #undef asinh #undef asinhf #undef acosh #undef acoshf #undef atanh #undef atanhf #undef pow #undef powf #undef pow10 #undef pow10f #undef exp #undef expf #undef expm1 #undef expm1f #undef exp2 #undef exp2f #undef exp10 #undef exp10f #undef log #undef logf #undef log1p #undef log1pf #undef log2 #undef log2f #undef log10 #undef log10f #undef sqrt #undef sqrtf #undef cbrt #undef cbrtf #undef sqr #undef sqrf #undef cub #undef cubf #undef max #undef min #undef fmax #undef fmaxf #undef fmin #undef fminf #undef copysign #undef copysignf #undef hypot #undef hypotf // Switch on remedial math on Windows with VC++ #if defined(WIN32) && (defined(_MSC_VER) || defined(__MINGW32__)) #define NO_CEILF #define NO_FLOORF #define NO_ROUNDF #define NO_ROUND #define NO_TRUNCF #define NO_TRUNC #define NO_NEARBYINTF #define NO_NEARBYINT #define NO_RINTF #define NO_RINT #define NO_EXPM1F #define NO_EXPM1 #define NO_EXP2F #define NO_EXP2 #define NO_EXP10F #define NO_EXP10 #define NO_POW10F #define NO_POW10 #define NO_LOG1PF #define NO_LOG1P #define NO_LOG2F #define NO_LOG2 #define NO_CBRTF #define NO_CBRT #define NO_SINHF #define NO_SINH #define NO_COSHF #define NO_COSH #define NO_TANHF #define NO_TANH #define NO_ASINHF #define NO_ASINH #define NO_ACOSHF #define NO_ACOSH #define NO_ATANHF #define NO_ATANH #define NO_FMAXF #define NO_FMAX #define NO_FMINF #define NO_FMIN #define NO_COPYSIGNF #define NO_COPYSIGN #define NO_HYPOTF #define NO_HYPOT #define NO_FDIMF #define NO_FDIM #define NO_SINCOS #define NO_SINCOSF #define NO_LRINT #define NO_LRINTF #endif // Systems below are missing these functions #if defined(__sun__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__) #define NO_EXP10F #define NO_EXP10 #endif // Apple is missing sincos #if defined(__APPLE__) #define NO_SINCOS #define NO_SINCOSF #endif namespace FX { /********************************* Constants *********************************/ /// Pi const FXdouble PI=3.1415926535897932384626433833; /// Euler constant const FXdouble EULER=2.7182818284590452353602874713; /// Multiplier for degrees to radians const FXdouble DTOR=0.0174532925199432957692369077; /// Multiplier for radians to degrees const FXdouble RTOD=57.295779513082320876798154814; /// Feigenbaum constant const FXdouble FEIGENBAUM=4.6692016091029906718532038215; /// Golden ratio const FXdouble GOLDENRATIO=1.6180339887498948482045868343; /********************************* Functions *********************************/ // FOX math functions live here namespace Math { /// All bits of single precision floating point number static inline FXuint fpBits(FXfloat x){ union{ FXfloat f; FXuint u; } z={x}; return z.u; } /// All bits of double precision floating point number static inline FXulong fpBits(FXdouble x){ union{ FXdouble f; FXulong u; } z={x}; return z.u; } /// Sign of single precision float point number (0..1) static inline FXint fpSign(FXfloat x){ FXint sign=fpBits(x)>>31; return sign; } /// Sign of double precision float point number (0..1) static inline FXlong fpSign(FXdouble x){ FXlong sign=fpBits(x)>>63; return sign; } /// Signed exponent of single precision float point number (-126..128) static inline FXint fpExponent(FXfloat x){ FXint exponent=(fpBits(x)>>23)&0xff; FXint bias=126-(-exponent>>31); return exponent-bias; } /// Signed exponent of double precision float point number (-1022..1024) static inline FXlong fpExponent(FXdouble x){ FXlong exponent=(fpBits(x)>>52)&0x7ff; FXlong bias=1022-(-exponent>>63); return exponent-bias; } /// Mantissa of single precision float point number (including hidden bit) static inline FXint fpMantissa(FXfloat x){ FXint mantissa=fpBits(x)&0x007fffff; FXint exponent=fpBits(x)&0x7f800000; FXint extrabit=-(-exponent>>31); // 1 if exponent!=0 return mantissa|(extrabit<<23); } /// Mantissa of double precision float point number (including hidden bit) static inline FXlong fpMantissa(FXdouble x){ FXlong mantissa=fpBits(x)&FXLONG(0x000fffffffffffff); FXlong exponent=fpBits(x)&FXLONG(0x7ff0000000000000); FXlong extrabit=-(-exponent>>63); // 1 if exponent!=0 return mantissa|(extrabit<<52); } /// Single precision floating point number is finite static inline FXbool fpFinite(FXfloat x){ return ((fpBits(x)&0x7fffffff)<0x7f800000); } /// Double precision floating point number is finite static inline FXbool fpFinite(FXdouble x){ return ((fpBits(x)&FXULONG(0x7fffffffffffffff))y)?x:y; } /// Maximum of two unsigned integers static inline FXuint imax(FXuint x,FXuint y){ return (x>y)?x:y; } /// Maximum of two longs static inline FXlong imax(FXlong x,FXlong y){ return (x>y)?x:y; } /// Maximum of two unsigned longs static inline FXulong imax(FXulong x,FXulong y){ return (x>y)?x:y; } /// Absolute value of short static inline FXshort iabs(FXshort x){ return 00 static inline FXint iclamp(FXint x,FXint lim){ return imin(imax(x,-lim),lim); } /// Long clamp of long x to [-lim..lim], where lim>0 static inline FXlong iclamp(FXlong x,FXlong lim){ return imin(imax(x,-lim),lim); } /// Sign of integer, return -1 if x is <0, +1 if x>0, and zero otherwise static inline FXint isign(FXint x){ return (x>0)-(x<0); } /// Sign of integer, return -1 if x is <0, +1 if x>0, and zero otherwise static inline FXlong isign(FXlong x){ return (x>0)-(x<0); } /// Single precision minimum of two static inline FXfloat fmin(FXfloat x,FXfloat y){ #if defined(NO_FMINF) return (xy)?x:y; #else return ::fmaxf(x,y); #endif } /// Double precision maximum of two static inline FXdouble fmax(FXdouble x,FXdouble y){ #if defined(NO_FMAX) return (x>y)?x:y; #else return ::fmax(x,y); #endif } /// Single precision absolute value static inline FXfloat fabs(FXfloat x){ #if defined(NO_FABSF) return (x<0.0f) ? -x : x; #else return ::fabsf(x); #endif } /// Double precision absolute value static inline FXdouble fabs(FXdouble x){ return ::fabs(x); } /// Single precision clamp of number x to lie within range [lo..hi] static inline FXfloat fclamp(FXfloat lo,FXfloat x,FXfloat hi){ return Math::fmin(Math::fmax(x,lo),hi); } /// Double precision clamp of number x to lie within range [lo..hi] static inline FXdouble fclamp(FXdouble lo,FXdouble x,FXdouble hi){ return Math::fmin(Math::fmax(x,lo),hi); } /// Single precision clamp of number x to [-lim..lim], where lim>0 static inline FXfloat fclamp(FXfloat x,FXfloat lim){ return fmin(fmax(x,-lim),lim); } /// Double precision clamp of number x to [-lim..lim], where lim>0 static inline FXdouble fclamp(FXdouble x,FXdouble lim){ return fmin(fmax(x,-lim),lim); } /// Single precision positive difference static inline FXfloat fdim(FXfloat x,FXfloat y){ #if defined(NO_FDIMF) return Math::fmax(x-y,0.0f); #else return ::fdimf(x,y); #endif } /// Double precision positive difference static inline FXdouble fdim(FXdouble x,FXdouble y){ #if defined(NO_FDIM) return Math::fmax(x-y,0.0); #else return ::fdim(x,y); #endif } /// Single precision floating point remainder static inline FXfloat fmod(FXfloat x,FXfloat y){ return ::fmodf(x,y); } /// Double precision floating point remainder static inline FXdouble fmod(FXdouble x,FXdouble y){ return ::fmod(x,y); } /// Evaluate single-precision (a < b) ? x : y static inline FXfloat fblend(FXfloat a,FXfloat b,FXfloat x,FXfloat y){ return a0) static inline FXfloat stepify(FXfloat x,FXfloat s){ return Math::nearbyint(x/s)*s; } /// Stepify double precision x into multiples of step s (where s>0) static inline FXdouble stepify(FXdouble x,FXdouble s){ return Math::nearbyint(x/s)*s; } /// Single precision zig-zag function, period 1 static inline FXfloat zigzag(FXfloat x){ return Math::fabs(2.0f*(x-Math::nearbyint(x))); } /// Single precision zig-zag function, period 1 static inline FXdouble zigzag(FXdouble x){ return Math::fabs(2.0*(x-Math::nearbyint(x))); } /// Single precision sawtooth function, period 1 static inline FXfloat sawtooth(FXfloat x){ return x-Math::floor(x); } /// Single precision sawtooth function, period 1 static inline FXdouble sawtooth(FXdouble x){ return x-Math::floor(x); } /// Single precision revserse sawtooth function, period 1 static inline FXfloat rsawtooth(FXfloat x){ return Math::ceil(x)-x; } /// Single precision revserse sawtooth function, period 1 static inline FXdouble rsawtooth(FXdouble x){ return Math::ceil(x)-x; } /// Single precision sine static inline FXfloat sin(FXfloat x){ return ::sinf(x); } /// Double precision sine static inline FXdouble sin(FXdouble x){ return ::sin(x); } /// Single precision cosine static inline FXfloat cos(FXfloat x){ return ::cosf(x); } /// Double precision cosine static inline FXdouble cos(FXdouble x){ return ::cos(x); } /// Single precision tangent static inline FXfloat tan(FXfloat x){ return ::tanf(x); } /// Double precision tangent static inline FXdouble tan(FXdouble x){ return ::tan(x); } /// Single precision arc sine static inline FXfloat asin(FXfloat x){ return ::asinf(x); } /// Double precision arc sine static inline FXdouble asin(FXdouble x){ return ::asin(x); } /// Single precision arc cosine static inline FXfloat acos(FXfloat x){ return ::acosf(x); } /// Double precision arc cosine static inline FXdouble acos(FXdouble x){ return ::acos(x); } /// Single precision arc tangent static inline FXfloat atan(FXfloat x){ return ::atanf(x); } /// Double precision arc tangent static inline FXdouble atan(FXdouble x){ return ::atan(x); } /// Single precision arc tangent static inline FXfloat atan2(FXfloat y,FXfloat x){ return ::atan2f(y,x); } /// Double precision arc tangent static inline FXdouble atan2(FXdouble y,FXdouble x){ return ::atan2(y,x); } /// Single precision sincos static inline void sincos(FXfloat x,FXfloat& s,FXfloat& c){ #if defined(NO_SINCOSF) s=Math::sin(x); c=Math::cos(x); #else ::sincosf(x,&s,&c); #endif } /// Double precision sincos static inline void sincos(FXdouble x,FXdouble& s,FXdouble& c){ #if defined(NO_SINCOS) s=Math::sin(x); c=Math::cos(x); #else ::sincos(x,&s,&c); #endif } /// Single precision hyperbolic sine #if defined(NO_SINHF) extern FXAPI FXfloat sinh(FXfloat x); #else static inline FXfloat sinh(FXfloat x){ return ::sinhf(x); } #endif /// Double precision hyperbolic sine #if defined(NO_SINH) extern FXAPI FXdouble sinh(FXdouble x); #else static inline FXdouble sinh(FXdouble x){ return ::sinh(x); } #endif /// Single precision hyperbolic cosine #if defined(NO_COSHF) extern FXAPI FXfloat cosh(FXfloat x); #else static inline FXfloat cosh(FXfloat x){ return ::coshf(x); } #endif /// Double precision hyperbolic cosine #if defined(NO_COSH) extern FXAPI FXdouble cosh(FXdouble x); #else static inline FXdouble cosh(FXdouble x){ return ::cosh(x); } #endif /// Single precision hyperbolic tangent #if defined(NO_TANHF) extern FXAPI FXfloat tanh(FXfloat x); #else static inline FXfloat tanh(FXfloat x){ return ::tanhf(x); } #endif /// Double precision hyperbolic tangent #if defined(NO_TANH) extern FXAPI FXdouble tanh(FXdouble x); #else static inline FXdouble tanh(FXdouble x){ return ::tanh(x); } #endif /// Single precision hyperbolic arc sine #if defined(NO_ASINHF) extern FXAPI FXfloat asinh(FXfloat x); #else static inline FXfloat asinh(FXfloat x){ return ::asinhf(x); } #endif /// Double precision hyperbolic arc sine #if defined(NO_ASINH) extern FXAPI FXdouble asinh(FXdouble x); #else static inline FXdouble asinh(FXdouble x){ return ::asinh(x); } #endif /// Single precision hyperbolic arc cosine #if defined(NO_ACOSHF) extern FXAPI FXfloat acosh(FXfloat x); #else static inline FXfloat acosh(FXfloat x){ return ::acoshf(x); } #endif /// Double precision hyperbolic arc cosine #if defined(NO_ACOSH) extern FXAPI FXdouble acosh(FXdouble x); #else static inline FXdouble acosh(FXdouble x){ return ::acosh(x); } #endif /// Single precision hyperbolic arc tangent #if defined(NO_ATANHF) extern FXAPI FXfloat atanh(FXfloat x); #else static inline FXfloat atanh(FXfloat x){ return ::atanhf(x); } #endif /// Double precision hyperbolic arc tangent #if defined(NO_ATANH) extern FXAPI FXdouble atanh(FXdouble x); #else static inline FXdouble atanh(FXdouble x){ return ::atanh(x); } #endif /// Single precision square root static inline FXfloat sqrt(FXfloat x){ return ::sqrtf(x); } /// Double precision square root static inline FXdouble sqrt(FXdouble x){ return ::sqrt(x); } /// Safe single precision square root static inline FXfloat safesqrt(FXfloat x){ return Math::sqrt(Math::fmax(x,0.0f)); } /// Safe double precision square root static inline FXdouble safesqrt(FXdouble x){ return Math::sqrt(Math::fmax(x,0.0)); } /// Single precision cube root static inline FXfloat cbrt(FXfloat x){ #if defined(NO_CBRTF) return ::powf(x,0.333333333333333333333333333333f); #else return ::cbrtf(x); #endif } /// Double precision cube root static inline FXdouble cbrt(FXdouble x){ #if defined(NO_CBRT) return ::pow(x,0.333333333333333333333333333333); #else return ::cbrt(x); #endif } /// Single precision square static inline FXfloat sqr(FXfloat x){ return x*x; } /// Double precision square static inline FXdouble sqr(FXdouble x){ return x*x; } /// Single precision cube static inline FXfloat cub(FXfloat x){ return x*x*x; } /// Double precision cube static inline FXdouble cub(FXdouble x){ return x*x*x; } /// Single precision reciprocal square root static inline FXfloat rsqrt(FXfloat x){ return 1.0f/Math::sqrt(x); } /// Double precision reciprocal square root static inline FXdouble rsqrt(FXdouble x){ return 1.0/Math::sqrt(x); } /// Single precision reciprocal static inline FXfloat recip(FXfloat x){ return 1.0f/x; } /// Double precision reciprocal static inline FXdouble recip(FXdouble x){ return 1.0/x; } /// Single precision calculate hypothenuse sqrt(x^2+y^2) static inline FXfloat hypot(FXfloat x,FXfloat y){ #if defined(NO_HYPOTF) return Math::sqrt(Math::sqr(x)+Math::sqr(y)); #else return ::hypotf(x,y); #endif } /// Double precision calculate hypothenuse sqrt(x^2+y^2) static inline FXdouble hypot(FXdouble x,FXdouble y){ #if defined(NO_HYPOT) return Math::sqrt(Math::sqr(x)+Math::sqr(y)); #else return ::hypot(x,y); #endif } /// Linearly interpolate between u and v as f goes from 0...1 static inline FXfloat lerp(FXfloat u,FXfloat v,FXfloat f){ return (v-u)*f+u; } /// Linearly interpolate between u and v as f goes from 0...1 static inline FXdouble lerp(FXdouble u,FXdouble v,FXdouble f){ return (v-u)*f+u; } /// Smooth transition from 0 to 1 as f goes from 0...1 static inline FXfloat smoothstep(FXfloat f){ return (3.0f-2.0f*f)*f*f; } /// Smooth transition from 0 to 1 as f goes from 0...1 static inline FXdouble smoothstep(FXdouble f){ return (3.0-2.0*f)*f*f; } /// Single precision base E exponential static inline FXfloat exp(FXfloat x){ return ::expf(x); } /// Double precision base E exponential static inline FXdouble exp(FXdouble x){ return ::exp(x); } /// Single precision base E exponential - 1 static inline FXfloat expm1(FXfloat x){ #if defined(NO_EXPM1F) return ::expf(x)-1.0f; #else return ::expm1f(x); #endif } /// Double precision base E exponential - 1 static inline FXdouble expm1(FXdouble x){ #if defined(NO_EXPM1) return ::exp(x)-1.0; #else return ::expm1(x); #endif } /// Single precision power x^y static inline FXfloat pow(FXfloat x,FXfloat y){ return ::powf(x,y); } /// Double precision power x^y static inline FXdouble pow(FXdouble x,FXdouble y){ return ::pow(x,y); } /// Single precision base 2 exponential static inline FXfloat exp2(FXfloat x){ #if defined(NO_EXP2F) return Math::pow(2.0f,x); #else return ::exp2f(x); #endif } /// Double precision base 2 exponential static inline FXdouble exp2(FXdouble x){ #if defined(NO_EXP2) return Math::pow(2.0,x); #else return ::exp2(x); #endif } /// Single precision base 10 exponential static inline FXfloat exp10(FXfloat x){ #if defined(NO_EXP10F) return Math::pow(10.0f,x); #else return ::exp10f(x); #endif } /// Double precision base 10 exponential static inline FXdouble exp10(FXdouble x){ #if defined(NO_EXP10) return Math::pow(10.0,x); #else return ::exp10(x); #endif } /// Single precision 10^x static inline FXfloat pow10(FXfloat x){ return Math::exp10(x); } /// Double precision 10^x static inline FXdouble pow10(FXdouble x){ return Math::exp10(x); } /// Double precision integer power of 10 extern FXAPI FXdouble pow10i(FXint ex); /// Single precision integer power extern FXAPI FXfloat powi(FXfloat base,FXint ex); /// Double precision integer power extern FXAPI FXdouble powi(FXdouble base,FXint ex); /// Single precision natural logarithm static inline FXfloat log(FXfloat x){ return ::logf(x); } /// Double precision natural logarithm static inline FXdouble log(FXdouble x){ return ::log(x); } /// Single precision logarithm of 1+x static inline FXfloat log1p(FXfloat x){ #if defined(NO_LOG1PF) return Math::log(1.0f+x); #else return ::log1pf(x); #endif } /// Double precision logarithm of 1+x static inline FXdouble log1p(FXdouble x){ #if defined(NO_LOG1P) return Math::log(1.0+x); #else return ::log1p(x); #endif } /// Single precision base 2 logarithm static inline FXfloat log2(FXfloat x){ #if defined(NO_LOG2F) return Math::log(x)*1.442695040888963407359924681001892137f; #else return ::log2f(x); #endif } /// Double precision base 2 logarithm static inline FXdouble log2(FXdouble x){ #if defined(NO_LOG2) return Math::log(x)*1.442695040888963407359924681001892137; #else return ::log2(x); #endif } /// Single precision base 10 logarithm static inline FXfloat log10(FXfloat x){ return ::log10f(x); } /// Double precision base 10 logarithm static inline FXdouble log10(FXdouble x){ return ::log10(x); } /// Single precision error function extern FXAPI FXfloat erf(FXfloat x); /// Double precision error function extern FXAPI FXdouble erf(FXdouble x); /// Single precision complementary error function extern FXAPI FXfloat erfc(FXfloat x); /// Double precision complementary error function extern FXAPI FXdouble erfc(FXdouble x); /// Single precision inverse error function extern FXAPI FXfloat inverf(FXfloat x); /// Double precision inverse error function extern FXAPI FXdouble inverf(FXdouble x); /// Single precision inverse complementary error function extern FXAPI FXfloat inverfc(FXfloat x); /// Double precision inverse complementary error function extern FXAPI FXdouble inverfc(FXdouble x); } } #endif