From 6101e4b20e9a2c9f01e7b07d0f189478e94c818b Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 7 Jun 2014 18:20:01 -0700 Subject: [PATCH] Added SDL_sqrtf(), SDL_tan(), SDL_tanf() --- configure | 2 +- configure.in | 2 +- include/SDL_config.h.cmake | 3 + include/SDL_config.h.in | 3 + include/SDL_config_android.h | 3 + include/SDL_config_iphoneos.h | 3 + include/SDL_config_macosx.h | 3 + include/SDL_config_pandora.h | 3 + include/SDL_config_psp.h | 3 + include/SDL_config_windows.h | 3 + include/SDL_config_winrt.h | 3 + include/SDL_config_wiz.h | 3 + include/SDL_stdinc.h | 3 + src/dynapi/SDL_dynapi_overrides.h | 3 + src/dynapi/SDL_dynapi_procs.h | 3 + src/libm/k_tan.c | 118 ++++++++++++++++++++++++++++++ src/libm/math_libm.h | 1 + src/libm/math_private.h | 1 + src/libm/s_tan.c | 67 +++++++++++++++++ src/stdlib/SDL_stdlib.c | 30 ++++++++ 20 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 src/libm/k_tan.c create mode 100644 src/libm/s_tan.c diff --git a/configure b/configure index 58cbd7520..4ce116362 100755 --- a/configure +++ b/configure @@ -16639,7 +16639,7 @@ if test "x$ac_cv_lib_m_pow" = xyes; then : LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm" fi - for ac_func in atan atan2 acos asin ceil copysign cos cosf fabs floor log pow scalbn sin sinf sqrt + for ac_func in atan atan2 acos asin ceil copysign cos cosf fabs floor log pow scalbn sin sinf sqrt 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 40b968864..2604fa280 100644 --- a/configure.in +++ b/configure.in @@ -271,7 +271,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 strlen strlcpy strlcat strdup _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 fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname) AC_CHECK_LIB(m, pow, [LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm"]) - AC_CHECK_FUNCS(atan atan2 acos asin ceil copysign cos cosf fabs floor log pow scalbn sin sinf sqrt) + AC_CHECK_FUNCS(atan atan2 acos asin ceil copysign cos cosf fabs floor log pow scalbn sin sinf sqrt 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 9b394220e..2c9ce6c6c 100644 --- a/include/SDL_config.h.cmake +++ b/include/SDL_config.h.cmake @@ -145,6 +145,9 @@ #cmakedefine HAVE_SIN 1 #cmakedefine HAVE_SINF 1 #cmakedefine HAVE_SQRT 1 +#cmakedefine HAVE_SQRTF 1 +#cmakedefine HAVE_TAN 1 +#cmakedefine HAVE_TANF 1 #cmakedefine HAVE_FSEEKO 1 #cmakedefine HAVE_FSEEKO64 1 #cmakedefine HAVE_SIGACTION 1 diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 5f1d0db9b..53ecfcb19 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -150,6 +150,9 @@ #undef HAVE_SIN #undef HAVE_SINF #undef HAVE_SQRT +#undef HAVE_SQRTF +#undef HAVE_TAN +#undef HAVE_TANF #undef HAVE_FSEEKO #undef HAVE_FSEEKO64 #undef HAVE_SIGACTION diff --git a/include/SDL_config_android.h b/include/SDL_config_android.h index 738dd94cc..7310601fb 100644 --- a/include/SDL_config_android.h +++ b/include/SDL_config_android.h @@ -100,6 +100,9 @@ #define HAVE_SIN 1 #define HAVE_SINF 1 #define HAVE_SQRT 1 +#define HAVE_SQRTF 1 +#define HAVE_TAN 1 +#define HAVE_TANF 1 #define HAVE_SIGACTION 1 #define HAVE_SETJMP 1 #define HAVE_NANOSLEEP 1 diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h index a0f55b6a7..8b268b7f6 100644 --- a/include/SDL_config_iphoneos.h +++ b/include/SDL_config_iphoneos.h @@ -98,6 +98,9 @@ #define HAVE_SIN 1 #define HAVE_SINF 1 #define HAVE_SQRT 1 +#define HAVE_SQRTF 1 +#define HAVE_TAN 1 +#define HAVE_TANF 1 #define HAVE_SIGACTION 1 #define HAVE_SETJMP 1 #define HAVE_NANOSLEEP 1 diff --git a/include/SDL_config_macosx.h b/include/SDL_config_macosx.h index e627aef26..b6af492d4 100644 --- a/include/SDL_config_macosx.h +++ b/include/SDL_config_macosx.h @@ -96,6 +96,9 @@ #define HAVE_SIN 1 #define HAVE_SINF 1 #define HAVE_SQRT 1 +#define HAVE_SQRTF 1 +#define HAVE_TAN 1 +#define HAVE_TANF 1 #define HAVE_SIGACTION 1 #define HAVE_SETJMP 1 #define HAVE_NANOSLEEP 1 diff --git a/include/SDL_config_pandora.h b/include/SDL_config_pandora.h index ac8b08508..aead1ff9f 100644 --- a/include/SDL_config_pandora.h +++ b/include/SDL_config_pandora.h @@ -95,6 +95,9 @@ #define HAVE_SIN 1 #define HAVE_SINF 1 #define HAVE_SQRT 1 +#define HAVE_SQRTF 1 +#define HAVE_TAN 1 +#define HAVE_TANF 1 #define HAVE_SIGACTION 1 #define HAVE_SETJMP 1 #define HAVE_NANOSLEEP 1 diff --git a/include/SDL_config_psp.h b/include/SDL_config_psp.h index 2f9d023c5..617d691f2 100644 --- a/include/SDL_config_psp.h +++ b/include/SDL_config_psp.h @@ -98,6 +98,9 @@ #define HAVE_SIN 1 #define HAVE_SINF 1 #define HAVE_SQRT 1 +#define HAVE_SQRTF 1 +#define HAVE_TAN 1 +#define HAVE_TANF 1 #define HAVE_SETJMP 1 #define HAVE_NANOSLEEP 1 /* #define HAVE_SYSCONF 1 */ diff --git a/include/SDL_config_windows.h b/include/SDL_config_windows.h index 1157270f7..29e5a47fe 100644 --- a/include/SDL_config_windows.h +++ b/include/SDL_config_windows.h @@ -132,6 +132,9 @@ typedef unsigned int uintptr_t; #define HAVE_SIN 1 #define HAVE_SINF 1 #define HAVE_SQRT 1 +#define HAVE_SQRTF 1 +#define HAVE_TAN 1 +#define HAVE_TANF 1 #if _MSC_VER >= 1800 #define HAVE_STRTOLL 1 #define HAVE_VSSCANF 1 diff --git a/include/SDL_config_winrt.h b/include/SDL_config_winrt.h index 48d44ee55..97c51405f 100644 --- a/include/SDL_config_winrt.h +++ b/include/SDL_config_winrt.h @@ -137,6 +137,9 @@ typedef unsigned int uintptr_t; #define HAVE_SIN 1 #define HAVE_SINF 1 #define HAVE_SQRT 1 +#define HAVE_SQRTF 1 +#define HAVE_TAN 1 +#define HAVE_TANF 1 #define HAVE__FSEEKI64 1 /* Enable various audio drivers */ diff --git a/include/SDL_config_wiz.h b/include/SDL_config_wiz.h index 7efc20bc9..9204567c6 100644 --- a/include/SDL_config_wiz.h +++ b/include/SDL_config_wiz.h @@ -89,6 +89,9 @@ #define HAVE_SIN 1 #define HAVE_SINF 1 #define HAVE_SQRT 1 +#define HAVE_SQRTF 1 +#define HAVE_TAN 1 +#define HAVE_TANF 1 #define HAVE_SIGACTION 1 #define HAVE_SETJMP 1 #define HAVE_NANOSLEEP 1 diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h index 9c79ca56f..1b470ce48 100644 --- a/include/SDL_stdinc.h +++ b/include/SDL_stdinc.h @@ -411,6 +411,9 @@ extern DECLSPEC double SDLCALL SDL_scalbn(double x, int n); extern DECLSPEC double SDLCALL SDL_sin(double x); extern DECLSPEC float SDLCALL SDL_sinf(float x); extern DECLSPEC double SDLCALL SDL_sqrt(double x); +extern DECLSPEC float SDLCALL SDL_sqrtf(float x); +extern DECLSPEC double SDLCALL SDL_tan(double x); +extern DECLSPEC float SDLCALL SDL_tanf(float x); /* The SDL implementation of iconv() returns these error codes */ #define SDL_ICONV_ERROR (size_t)-1 diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 4b26185a8..40ae7dd3b 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -581,3 +581,6 @@ #define SDL_WinRTGetFSPathUNICODE SDL_WinRTGetFSPathUNICODE_REAL #define SDL_WinRTGetFSPathUTF8 SDL_WinRTGetFSPathUTF8_REAL #define SDL_WinRTRunApp SDL_WinRTRunApp_REAL +#define SDL_sqrtf SDL_sqrtf_REAL +#define SDL_tan SDL_tan_REAL +#define SDL_tanf SDL_tanf_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 44b9fd21f..217fcd57c 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -613,3 +613,6 @@ SDL_DYNAPI_PROC(const wchar_t*,SDL_WinRTGetFSPathUNICODE,(SDL_WinRT_Path a),(a), SDL_DYNAPI_PROC(const char*,SDL_WinRTGetFSPathUTF8,(SDL_WinRT_Path a),(a),return) #endif SDL_DYNAPI_PROC(void,SDL_WarpMouseGlobal,(int a, int b),(a,b),) +SDL_DYNAPI_PROC(float,SDL_sqrtf,(float a),(a),return) +SDL_DYNAPI_PROC(double,SDL_tan,(double a),(a),return) +SDL_DYNAPI_PROC(float,SDL_tanf,(float a),(a),return) diff --git a/src/libm/k_tan.c b/src/libm/k_tan.c new file mode 100644 index 000000000..27e6639b0 --- /dev/null +++ b/src/libm/k_tan.c @@ -0,0 +1,118 @@ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +/* __kernel_tan( x, y, k ) + * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input k indicates whether tan (if k=1) or + * -1/tan (if k= -1) is returned. + * + * Algorithm + * 1. Since tan(-x) = -tan(x), we need only to consider positive x. + * 2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0. + * 3. tan(x) is approximated by a odd polynomial of degree 27 on + * [0,0.67434] + * 3 27 + * tan(x) ~ x + T1*x + ... + T13*x + * where + * + * |tan(x) 2 4 26 | -59.2 + * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 + * | x | + * + * Note: tan(x+y) = tan(x) + tan'(x)*y + * ~ tan(x) + (1+x*x)*y + * Therefore, for better accuracy in computing tan(x+y), let + * 3 2 2 2 2 + * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) + * then + * 3 2 + * tan(x+y) = x + (T1*x + (x *(r+y)+y)) + * + * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then + * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) + * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) + */ + +#include "math_libm.h" +#include "math_private.h" + +static const double +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +pio4 = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */ +pio4lo= 3.06161699786838301793e-17, /* 0x3C81A626, 0x33145C07 */ +T[] = { + 3.33333333333334091986e-01, /* 0x3FD55555, 0x55555563 */ + 1.33333333333201242699e-01, /* 0x3FC11111, 0x1110FE7A */ + 5.39682539762260521377e-02, /* 0x3FABA1BA, 0x1BB341FE */ + 2.18694882948595424599e-02, /* 0x3F9664F4, 0x8406D637 */ + 8.86323982359930005737e-03, /* 0x3F8226E3, 0xE96E8493 */ + 3.59207910759131235356e-03, /* 0x3F6D6D22, 0xC9560328 */ + 1.45620945432529025516e-03, /* 0x3F57DBC8, 0xFEE08315 */ + 5.88041240820264096874e-04, /* 0x3F4344D8, 0xF2F26501 */ + 2.46463134818469906812e-04, /* 0x3F3026F7, 0x1A8D1068 */ + 7.81794442939557092300e-05, /* 0x3F147E88, 0xA03792A6 */ + 7.14072491382608190305e-05, /* 0x3F12B80F, 0x32F0A7E9 */ + -1.85586374855275456654e-05, /* 0xBEF375CB, 0xDB605373 */ + 2.59073051863633712884e-05, /* 0x3EFB2A70, 0x74BF7AD4 */ +}; + +double __kernel_tan(double x, double y, int iy) +{ + double z,r,v,w,s; + int32_t ix,hx; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; /* high word of |x| */ + if(ix<0x3e300000) /* x < 2**-28 */ + {if((int)x==0) { /* generate inexact */ + u_int32_t low; + GET_LOW_WORD(low,x); + if(((ix|low)|(iy+1))==0) return one/fabs(x); + else return (iy==1)? x: -one/x; + } + } + if(ix>=0x3FE59428) { /* |x|>=0.6744 */ + if(hx<0) {x = -x; y = -y;} + z = pio4-x; + w = pio4lo-y; + x = z+w; y = 0.0; + } + z = x*x; + w = z*z; + /* Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11])))); + v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12]))))); + s = z*x; + r = y + z*(s*(r+v)+y); + r += T[0]*s; + w = x+r; + if(ix>=0x3FE59428) { + v = (double)iy; + return (double)(1-((hx>>30)&2))*(v-2.0*(x-(w*w/(w+v)-r))); + } + if(iy==1) return w; + else { /* if allow error up to 2 ulp, + simply return -1.0/(x+r) here */ + /* compute -1.0/(x+r) accurately */ + double a,t; + z = w; + SET_LOW_WORD(z,0); + v = r-(z - x); /* z+v = r+x */ + t = a = -1.0/w; /* a = -1.0/w */ + SET_LOW_WORD(t,0); + s = 1.0+t*z; + return t+a*(s+t*v); + } +} diff --git a/src/libm/math_libm.h b/src/libm/math_libm.h index 20432bd28..6b479f44d 100644 --- a/src/libm/math_libm.h +++ b/src/libm/math_libm.h @@ -33,5 +33,6 @@ double SDL_uclibc_pow(double x, double y); double SDL_uclibc_scalbn(double x, int n); double SDL_uclibc_sin(double x); double SDL_uclibc_sqrt(double x); +double SDL_uclibc_tan(double x); /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/libm/math_private.h b/src/libm/math_private.h index 6ab0f35fd..74c8b3d45 100644 --- a/src/libm/math_private.h +++ b/src/libm/math_private.h @@ -40,6 +40,7 @@ typedef unsigned int u_int32_t; #define scalbn SDL_uclibc_scalbn #define sin SDL_uclibc_sin #define __ieee754_sqrt SDL_uclibc_sqrt +#define tan SDL_uclibc_tan /* The original fdlibm code used statements like: n0 = ((*(int*)&one)>>29)^1; * index of high word * diff --git a/src/libm/s_tan.c b/src/libm/s_tan.c new file mode 100644 index 000000000..5a2bc930c --- /dev/null +++ b/src/libm/s_tan.c @@ -0,0 +1,67 @@ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +/* tan(x) + * Return tangent function of x. + * + * kernel function: + * __kernel_tan ... tangent function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "math.h" +#include "math_private.h" + +double tan(double x) +{ + double y[2],z=0.0; + int32_t n, ix; + + /* High word of x. */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3fe921fb) return __kernel_tan(x,z,1); + + /* tan(Inf or NaN) is NaN */ + else if (ix>=0x7ff00000) return x-x; /* NaN */ + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2(x,y); + return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even + -1 -- n odd */ + } +} +libm_hidden_def(tan) diff --git a/src/stdlib/SDL_stdlib.c b/src/stdlib/SDL_stdlib.c index 11f778a37..c5f5e9d87 100644 --- a/src/stdlib/SDL_stdlib.c +++ b/src/stdlib/SDL_stdlib.c @@ -211,6 +211,36 @@ SDL_sqrt(double x) #endif } +float +SDL_sqrtf(float x) +{ +#if defined(HAVE_SQRTF) + return sqrtf(x); +#else + return (float)SDL_sqrt((double)x); +#endif +} + +double +SDL_tan(double x) +{ +#if defined(HAVE_TAN) + return tan(x); +#else + return SDL_uclibc_tan(x); +#endif +} + +float +SDL_tanf(float x) +{ +#if defined(HAVE_TANF) + return tanf(x); +#else + return (float)SDL_tan((double)x); +#endif +} + int SDL_abs(int x) { #ifdef HAVE_ABS