From b4fe7412f931135071066b010d9ca13c2cfa2443 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Sat, 4 Aug 2018 11:52:46 -0400 Subject: [PATCH] SDL_exp --- CMakeLists.txt | 2 +- VisualC/SDL/SDL.vcxproj | 1 + VisualC/SDL/SDL.vcxproj.filters | 1 + configure | 2 +- configure.in | 2 +- include/SDL_config.h.cmake | 2 + include/SDL_config.h.in | 2 + include/SDL_config_android.h | 2 + include/SDL_config_iphoneos.h | 2 + include/SDL_config_macosx.h | 2 + include/SDL_config_pandora.h | 1 + include/SDL_config_psp.h | 2 + include/SDL_config_windows.h | 2 + include/SDL_config_winrt.h | 2 + include/SDL_config_wiz.h | 2 + include/SDL_stdinc.h | 2 + src/dynapi/SDL_dynapi_overrides.h | 2 + src/dynapi/SDL_dynapi_procs.h | 2 + src/libm/e_exp.c | 182 ++++++++++++++++++++++++++++++ src/libm/math_libm.h | 1 + src/libm/math_private.h | 1 + src/stdlib/SDL_stdlib.c | 20 ++++ 22 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 src/libm/e_exp.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 608e9e2f44c63..492a5d0eded4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -650,7 +650,7 @@ if(LIBC) _ultoa strtol strtoul strtoll strtod atoi atof strcmp strncmp _stricmp _strnicmp sscanf acos acosf asin asinf atan atanf atan2 atan2f ceil ceilf - copysign copysignf cos cosf fabs fabsf floor floorf fmod fmodf + copysign copysignf cos cosf exp expf fabs fabsf floor floorf fmod fmodf log logf log10 log10f pow powf scalbn scalbnf sin sinf sqrt sqrtf tan tanf) string(TOUPPER ${_FN} _UPPER) set(HAVE_${_UPPER} 1) diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj index 847a2a441f50d..e2c1909b67f57 100644 --- a/VisualC/SDL/SDL.vcxproj +++ b/VisualC/SDL/SDL.vcxproj @@ -418,6 +418,7 @@ + diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters index 8d55a589653b1..e0ebb08116ee1 100644 --- a/VisualC/SDL/SDL.vcxproj.filters +++ b/VisualC/SDL/SDL.vcxproj.filters @@ -316,6 +316,7 @@ + diff --git a/configure b/configure index 8a0d73b0c0100..0cf2419625c3f 100755 --- a/configure +++ b/configure @@ -16699,7 +16699,7 @@ if test "x$ac_cv_lib_m_pow" = xyes; then : LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm" fi - for ac_func in acos acosf asin asinf atan atanf atan2 atan2f ceil ceilf copysign copysignf cos cosf fabs fabsf floor floorf fmod fmodf log logf log10 log10f pow powf scalbn scalbnf sin sinf sqrt sqrtf tan tanf + for ac_func in acos acosf asin asinf atan atanf atan2 atan2f ceil ceilf copysign copysignf cos cosf exp expf fabs fabsf floor floorf fmod fmodf log logf log10 log10f pow powf scalbn scalbnf sin sinf sqrt sqrtf tan tanf do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.in b/configure.in index e6f4b7d6e94f5..4f2b09b82618d 100644 --- a/configure.in +++ b/configure.in @@ -278,7 +278,7 @@ if test x$enable_libc = xyes; then AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove wcslen wcscmp strlen strlcpy strlcat _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp vsscanf vsnprintf fopen64 fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname getauxval poll) AC_CHECK_LIB(m, pow, [LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm"]) - AC_CHECK_FUNCS(acos acosf asin asinf atan atanf atan2 atan2f ceil ceilf copysign copysignf cos cosf fabs fabsf floor floorf fmod fmodf log logf log10 log10f pow powf scalbn scalbnf sin sinf sqrt sqrtf tan tanf) + AC_CHECK_FUNCS(acos acosf asin asinf atan atanf atan2 atan2f ceil ceilf copysign copysignf cos cosf exp expf fabs fabsf floor floorf fmod fmodf log logf log10 log10f pow powf scalbn scalbnf sin sinf sqrt sqrtf tan tanf) AC_CHECK_LIB(iconv, iconv_open, [LIBS="$LIBS -liconv"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -liconv"]) AC_CHECK_FUNCS(iconv) diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake index a8d230c46574e..e69c272dde1f8 100644 --- a/include/SDL_config.h.cmake +++ b/include/SDL_config.h.cmake @@ -144,6 +144,8 @@ #cmakedefine HAVE_COPYSIGNF 1 #cmakedefine HAVE_COS 1 #cmakedefine HAVE_COSF 1 +#cmakedefine HAVE_EXP 1 +#cmakedefine HAVE_EXPF 1 #cmakedefine HAVE_FABS 1 #cmakedefine HAVE_FABSF 1 #cmakedefine HAVE_FLOOR 1 diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 422f47f7810fd..abcf2f2f36d20 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -149,6 +149,8 @@ #undef HAVE_COPYSIGNF #undef HAVE_COS #undef HAVE_COSF +#undef HAVE_EXP +#undef HAVE_EXPF #undef HAVE_FABS #undef HAVE_FABSF #undef HAVE_FLOOR diff --git a/include/SDL_config_android.h b/include/SDL_config_android.h index 4c4da37ec6a5f..efe5203123add 100644 --- a/include/SDL_config_android.h +++ b/include/SDL_config_android.h @@ -98,6 +98,8 @@ #define HAVE_COPYSIGNF 1 #define HAVE_COS 1 #define HAVE_COSF 1 +#define HAVE_EXP 1 +#define HAVE_EXPF 1 #define HAVE_FABS 1 #define HAVE_FABSF 1 #define HAVE_FLOOR 1 diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h index 7b0a6ca2df24e..bc628ed30ea7a 100644 --- a/include/SDL_config_iphoneos.h +++ b/include/SDL_config_iphoneos.h @@ -99,6 +99,8 @@ #define HAVE_COPYSIGNF 1 #define HAVE_COS 1 #define HAVE_COSF 1 +#define HAVE_EXP 1 +#define HAVE_EXPF 1 #define HAVE_FABS 1 #define HAVE_FABSF 1 #define HAVE_FLOOR 1 diff --git a/include/SDL_config_macosx.h b/include/SDL_config_macosx.h index 29f583e101417..cb3d42f94341b 100644 --- a/include/SDL_config_macosx.h +++ b/include/SDL_config_macosx.h @@ -102,6 +102,8 @@ #define HAVE_COPYSIGNF 1 #define HAVE_COS 1 #define HAVE_COSF 1 +#define HAVE_EXP 1 +#define HAVE_EXPF 1 #define HAVE_FABS 1 #define HAVE_FABSF 1 #define HAVE_FLOOR 1 diff --git a/include/SDL_config_pandora.h b/include/SDL_config_pandora.h index be5a85c19aa7d..b5b53a3e128d0 100644 --- a/include/SDL_config_pandora.h +++ b/include/SDL_config_pandora.h @@ -90,6 +90,7 @@ #define HAVE_COPYSIGN 1 #define HAVE_COS 1 #define HAVE_COSF 1 +#define HAVE_EXP 1 #define HAVE_FABS 1 #define HAVE_FLOOR 1 #define HAVE_LOG 1 diff --git a/include/SDL_config_psp.h b/include/SDL_config_psp.h index 61c334978b4ca..0f835be6c846e 100644 --- a/include/SDL_config_psp.h +++ b/include/SDL_config_psp.h @@ -97,6 +97,8 @@ #define HAVE_COPYSIGNF 1 #define HAVE_COS 1 #define HAVE_COSF 1 +#define HAVE_EXP 1 +#define HAVE_EXPF 1 #define HAVE_FABS 1 #define HAVE_FABSF 1 #define HAVE_FLOOR 1 diff --git a/include/SDL_config_windows.h b/include/SDL_config_windows.h index 52a9ece161c4b..8631a2fe656d5 100644 --- a/include/SDL_config_windows.h +++ b/include/SDL_config_windows.h @@ -139,6 +139,8 @@ typedef unsigned int uintptr_t; #define HAVE__COPYSIGN 1 #define HAVE_COS 1 #define HAVE_COSF 1 +#define HAVE_EXP 1 +#define HAVE_EXPF 1 #define HAVE_FABS 1 #define HAVE_FABSF 1 #define HAVE_FLOOR 1 diff --git a/include/SDL_config_winrt.h b/include/SDL_config_winrt.h index aac0e6014b788..6760735cc5c50 100644 --- a/include/SDL_config_winrt.h +++ b/include/SDL_config_winrt.h @@ -155,6 +155,8 @@ typedef unsigned int uintptr_t; #define HAVE__COPYSIGN 1 #define HAVE_COS 1 #define HAVE_COSF 1 +#define HAVE_EXP 1 +#define HAVE_EXPF 1 #define HAVE_FABS 1 #define HAVE_FABSF 1 #define HAVE_FLOOR 1 diff --git a/include/SDL_config_wiz.h b/include/SDL_config_wiz.h index fe86d5ec37ea2..9b1f6338cc31e 100644 --- a/include/SDL_config_wiz.h +++ b/include/SDL_config_wiz.h @@ -94,6 +94,8 @@ #define HAVE_COPYSIGNF 1 #define HAVE_COS 1 #define HAVE_COSF 1 +#define HAVE_EXP 1 +#define HAVE_EXPF 1 #define HAVE_FABS 1 #define HAVE_FABSF 1 #define HAVE_FLOOR 1 diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h index 92fcbcc2b1c96..b2ca7ae97b879 100644 --- a/include/SDL_stdinc.h +++ b/include/SDL_stdinc.h @@ -513,6 +513,8 @@ extern DECLSPEC double SDLCALL SDL_copysign(double x, double y); extern DECLSPEC float SDLCALL SDL_copysignf(float x, float y); extern DECLSPEC double SDLCALL SDL_cos(double x); extern DECLSPEC float SDLCALL SDL_cosf(float x); +extern DECLSPEC double SDLCALL SDL_exp(double x); +extern DECLSPEC float SDLCALL SDL_expf(float x); extern DECLSPEC double SDLCALL SDL_fabs(double x); extern DECLSPEC float SDLCALL SDL_fabsf(float x); extern DECLSPEC double SDLCALL SDL_floor(double x); diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 48243d681a945..50a39be750864 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -675,3 +675,5 @@ #define SDL_IsChromebook SDL_IsChromebook_REAL #define SDL_IsDeXMode SDL_IsDeXMode_REAL #define SDL_AndroidBackButton SDL_AndroidBackButton_REAL +#define SDL_exp SDL_exp_REAL +#define SDL_expf SDL_expf_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 58246c30b6218..97cdab1bd6896 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -719,3 +719,5 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_IsDeXMode,(void),(),return) #ifdef __ANDROID__ SDL_DYNAPI_PROC(void,SDL_AndroidBackButton,(void),(),return) #endif +SDL_DYNAPI_PROC(double,SDL_exp,(double a),(a),return) +SDL_DYNAPI_PROC(float,SDL_expf,(float a),(a),return) diff --git a/src/libm/e_exp.c b/src/libm/e_exp.c new file mode 100644 index 0000000000000..07f630a331607 --- /dev/null +++ b/src/libm/e_exp.c @@ -0,0 +1,182 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* __ieee754_exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Reme algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ------- + * R - r + * r*R1(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - R1(r) + * where + * 2 4 10 + * R1(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then exp(x) overflow + * if x < -7.45133219101941108420e+02 then exp(x) underflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "math_libm.h" +#include "math_private.h" + +static const double +one = 1.0, +halF[2] = {0.5,-0.5,}, +huge = 1.0e+300, +twom1000= 9.33263618503218878990e-302, /* 2**-1000=0x01700000,0*/ +o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */ +u_threshold= -7.45133219101941108420e+02, /* 0xc0874910, 0xD52D3051 */ +ln2HI[2] ={ 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ + -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */ +ln2LO[2] ={ 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ + -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +double __ieee754_exp(double x) /* default IEEE double exp */ +{ + double y; + double hi = 0.0; + double lo = 0.0; + double c; + double t; + int32_t k=0; + int32_t xsb; + u_int32_t hx; + + GET_HIGH_WORD(hx,x); + xsb = (hx>>31)&1; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* filter out non-finite argument */ + if(hx >= 0x40862E42) { /* if |x|>=709.78... */ + if(hx>=0x7ff00000) { + u_int32_t lx; + GET_LOW_WORD(lx,x); + if(((hx&0xfffff)|lx)!=0) + return x+x; /* NaN */ + else return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */ + } + if(x > o_threshold) return huge*huge; /* overflow */ + if(x < u_threshold) return twom1000*twom1000; /* underflow */ + } + + /* argument reduction */ + if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb; + } else { + k = invln2*x+halF[xsb]; + t = k; + hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */ + lo = t*ln2LO[0]; + } + x = hi - lo; + } + else if(hx < 0x3e300000) { /* when |x|<2**-28 */ + if(huge+x>one) return one+x;/* trigger inexact */ + } + else k = 0; + + /* x is now in primary range */ + t = x*x; + c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + if(k==0) return one-((x*c)/(c-2.0)-x); + else y = one-((lo-(x*c)/(2.0-c))-hi); + if(k >= -1021) { + u_int32_t hy; + GET_HIGH_WORD(hy,y); + SET_HIGH_WORD(y,hy+(k<<20)); /* add k to y's exponent */ + return y; + } else { + u_int32_t hy; + GET_HIGH_WORD(hy,y); + SET_HIGH_WORD(y,hy+((k+1000)<<20)); /* add k to y's exponent */ + return y*twom1000; + } +} + +/* + * wrapper exp(x) + */ +#ifndef _IEEE_LIBM +double exp(double x) +{ + static const double o_threshold = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ + static const double u_threshold = -7.45133219101941108420e+02; /* 0xc0874910, 0xD52D3051 */ + + double z = __ieee754_exp(x); + if (_LIB_VERSION == _IEEE_) + return z; + if (isfinite(x)) { + if (x > o_threshold) + return __kernel_standard(x, x, 6); /* exp overflow */ + if (x < u_threshold) + return __kernel_standard(x, x, 7); /* exp underflow */ + } + return z; +} +#else +strong_alias(__ieee754_exp, exp) +#endif +libm_hidden_def(exp) diff --git a/src/libm/math_libm.h b/src/libm/math_libm.h index eb7bdd597da0e..67f8c6a7918c3 100644 --- a/src/libm/math_libm.h +++ b/src/libm/math_libm.h @@ -26,6 +26,7 @@ double SDL_uclibc_atan(double x); double SDL_uclibc_atan2(double y, double x); double SDL_uclibc_copysign(double x, double y); double SDL_uclibc_cos(double x); +double SDL_uclibc_exp(double x); double SDL_uclibc_fabs(double x); double SDL_uclibc_floor(double x); double SDL_uclibc_fmod(double x, double y); diff --git a/src/libm/math_private.h b/src/libm/math_private.h index 57bb6bfd76393..d5ff0c41c8c51 100644 --- a/src/libm/math_private.h +++ b/src/libm/math_private.h @@ -35,6 +35,7 @@ typedef unsigned int u_int32_t; #define __ieee754_atan2 SDL_uclibc_atan2 #define copysign SDL_uclibc_copysign #define cos SDL_uclibc_cos +#define __ieee754_exp SDL_uclibc_exp #define fabs SDL_uclibc_fabs #define floor SDL_uclibc_floor #define __ieee754_fmod SDL_uclibc_fmod diff --git a/src/stdlib/SDL_stdlib.c b/src/stdlib/SDL_stdlib.c index b36d83c79567a..9d07a4b0d1893 100644 --- a/src/stdlib/SDL_stdlib.c +++ b/src/stdlib/SDL_stdlib.c @@ -200,6 +200,26 @@ SDL_cosf(float x) #endif } +double +SDL_exp(double x) +{ +#if defined(HAVE_EXP) + return exp(x); +#else + return SDL_uclibc_exp(x); +#endif +} + +float +SDL_expf(float x) +{ +#if defined(HAVE_EXPF) + return expf(x); +#else + return (float)SDL_uclibc_exp((double)x); +#endif +} + double SDL_fabs(double x) {