Let’s be honest, I’m never gonna use it in its current form.legacy
| @@ -21,8 +21,7 @@ bluenoise_CPPFLAGS = $(AM_CPPFLAGS) | |||
| bluenoise_DEPENDENCIES = @LOL_DEPS@ | |||
| benchsuite_SOURCES = benchsuite.cpp \ | |||
| benchmark/vector.cpp benchmark/half.cpp benchmark/trig.cpp \ | |||
| benchmark/real.cpp | |||
| benchmark/vector.cpp benchmark/half.cpp benchmark/real.cpp | |||
| benchsuite_CPPFLAGS = $(AM_CPPFLAGS) | |||
| benchsuite_DEPENDENCIES = @LOL_DEPS@ | |||
| @@ -1,192 +0,0 @@ | |||
| // | |||
| // Lol Engine — Benchmark program | |||
| // | |||
| // Copyright © 2005—2018 Sam Hocevar <sam@hocevar.net> | |||
| // | |||
| // This program is free software. It comes without any warranty, to | |||
| // the extent permitted by applicable law. You can redistribute it | |||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||
| // See http://www.wtfpl.net/ for more details. | |||
| // | |||
| #if HAVE_CONFIG_H | |||
| # include "config.h" | |||
| #endif | |||
| #include <cstdio> | |||
| #if HAVE_FASTMATH_H | |||
| # include <fastmath.h> | |||
| #endif | |||
| #include <lol/engine.h> | |||
| using namespace lol; | |||
| static size_t const TRIG_TABLE_SIZE = 128 * 1024; | |||
| static size_t const TRIG_RUNS = 50; | |||
| void bench_trig(int mode) | |||
| { | |||
| float result[12] = { 0.0f }; | |||
| lol::timer timer; | |||
| /* Set up tables */ | |||
| float *pf = new float[TRIG_TABLE_SIZE]; | |||
| float *pf2 = new float[TRIG_TABLE_SIZE]; | |||
| float *pf3 = new float[TRIG_TABLE_SIZE]; | |||
| for (size_t run = 0; run < TRIG_RUNS; run++) | |||
| { | |||
| switch (mode) | |||
| { | |||
| case 1: | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| pf[i] = rand(-1e5f, 1e5f); | |||
| break; | |||
| case 2: | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| pf[i] = rand(-F_PI, F_PI); | |||
| break; | |||
| case 3: | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| pf[i] = rand(-1e-2f, 1e-2f); | |||
| break; | |||
| } | |||
| /* Sin */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| #if __GNUC__ && !__SNC__ | |||
| pf2[i] = __builtin_sinf(pf[i]); | |||
| #else | |||
| pf2[i] = sinf(pf[i]); | |||
| #endif | |||
| result[0] += timer.get(); | |||
| /* Fast sin */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| #if HAVE_FASTMATH_H && !__native_client__ && !EMSCRIPTEN | |||
| pf2[i] = f_sinf(pf[i]); | |||
| #else | |||
| pf2[i] = sinf(pf[i]); | |||
| #endif | |||
| result[1] += timer.get(); | |||
| /* Lol sin */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| pf2[i] = lol_sin(pf[i]); | |||
| result[2] += timer.get(); | |||
| /* Cos */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| #if __GNUC__ && !__SNC__ | |||
| pf2[i] = __builtin_cosf(pf[i]); | |||
| #else | |||
| pf2[i] = cosf(pf[i]); | |||
| #endif | |||
| result[3] += timer.get(); | |||
| /* Fast cos */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| #if HAVE_FASTMATH_H && !__native_client__ && !EMSCRIPTEN | |||
| pf2[i] = f_cosf(pf[i]); | |||
| #else | |||
| pf2[i] = cosf(pf[i]); | |||
| #endif | |||
| result[4] += timer.get(); | |||
| /* Lol cos */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| pf2[i] = lol_cos(pf[i]); | |||
| result[5] += timer.get(); | |||
| /* Sin & cos */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| { | |||
| #if __GNUC__ && !__SNC__ | |||
| pf2[i] = __builtin_sinf(pf[i]); | |||
| pf3[i] = __builtin_cosf(pf[i]); | |||
| #else | |||
| pf2[i] = sinf(pf[i]); | |||
| pf3[i] = cosf(pf[i]); | |||
| #endif | |||
| } | |||
| result[6] += timer.get(); | |||
| /* Fast sin & cos */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| { | |||
| #if HAVE_FASTMATH_H && !__native_client__ && !EMSCRIPTEN | |||
| pf2[i] = f_sinf(pf[i]); | |||
| pf3[i] = f_cosf(pf[i]); | |||
| #else | |||
| pf2[i] = sinf(pf[i]); | |||
| pf3[i] = cosf(pf[i]); | |||
| #endif | |||
| } | |||
| result[7] += timer.get(); | |||
| /* Lol sincos */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| lol_sincos(pf[i], &pf2[i], &pf3[i]); | |||
| result[8] += timer.get(); | |||
| /* Tan */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| #if __GNUC__ && !__SNC__ | |||
| pf2[i] = __builtin_tanf(pf[i]); | |||
| #else | |||
| pf2[i] = tanf(pf[i]); | |||
| #endif | |||
| result[9] += timer.get(); | |||
| /* Fast tan */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| #if HAVE_FASTMATH_H && !__native_client__ && !EMSCRIPTEN | |||
| pf2[i] = f_tanf(pf[i]); | |||
| #else | |||
| pf2[i] = tanf(pf[i]); | |||
| #endif | |||
| result[10] += timer.get(); | |||
| /* Lol tan */ | |||
| timer.get(); | |||
| for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) | |||
| pf2[i] = lol_tan(pf[i]); | |||
| result[11] += timer.get(); | |||
| } | |||
| delete[] pf; | |||
| delete[] pf2; | |||
| delete[] pf3; | |||
| for (size_t i = 0; i < sizeof(result) / sizeof(*result); i++) | |||
| result[i] *= 1e9f / (TRIG_TABLE_SIZE * TRIG_RUNS); | |||
| msg::info(" ns/elem\n"); | |||
| msg::info("float = sinf(float) %7.3f\n", result[0]); | |||
| msg::info("float = f_sinf(float) %7.3f\n", result[1]); | |||
| msg::info("float = lol_sin(float) %7.3f\n", result[2]); | |||
| msg::info("float = cosf(float) %7.3f\n", result[3]); | |||
| msg::info("float = f_cosf(float) %7.3f\n", result[4]); | |||
| msg::info("float = lol_cos(float) %7.3f\n", result[5]); | |||
| msg::info("float = sinf,cosf(float) %7.3f\n", result[6]); | |||
| msg::info("float = f_sinf,f_cosf(float) %7.3f\n", result[7]); | |||
| msg::info("float = lol_sincos(float) %7.3f\n", result[8]); | |||
| msg::info("float = tanf(float) %7.3f\n", result[9]); | |||
| msg::info("float = f_tanf(float) %7.3f\n", result[10]); | |||
| msg::info("float = lol_tanf(float) %7.3f\n", result[11]); | |||
| } | |||
| @@ -21,7 +21,6 @@ | |||
| using namespace lol; | |||
| void bench_real(int mode); | |||
| void bench_trig(int mode); | |||
| void bench_matrix(int mode); | |||
| void bench_half(int mode); | |||
| @@ -34,21 +33,6 @@ int main(int argc, char **argv) | |||
| msg::info("-----------------------\n"); | |||
| bench_real(1); | |||
| msg::info("--------------------------\n"); | |||
| msg::info(" Trigonometry [-1e5, 1e5]\n"); | |||
| msg::info("--------------------------\n"); | |||
| bench_trig(1); | |||
| msg::info("------------------------\n"); | |||
| msg::info(" Trigonometry [-pi, pi]\n"); | |||
| msg::info("------------------------\n"); | |||
| bench_trig(2); | |||
| msg::info("----------------------------\n"); | |||
| msg::info(" Trigonometry [-1e-2, 1e-2]\n"); | |||
| msg::info("----------------------------\n"); | |||
| bench_trig(3); | |||
| msg::info("----------------------------\n"); | |||
| msg::info(" Float matrices [-2.0, 2.0]\n"); | |||
| msg::info("----------------------------\n"); | |||
| @@ -33,7 +33,6 @@ | |||
| <ItemGroup> | |||
| <ClCompile Include="benchmark\half.cpp" /> | |||
| <ClCompile Include="benchmark\real.cpp" /> | |||
| <ClCompile Include="benchmark\trig.cpp" /> | |||
| <ClCompile Include="benchmark\vector.cpp" /> | |||
| <ClCompile Include="benchsuite.cpp" /> | |||
| </ItemGroup> | |||
| @@ -92,8 +92,8 @@ liblol_core_sources = \ | |||
| \ | |||
| base/assert.cpp base/log.cpp base/string.cpp base/enum.cpp \ | |||
| \ | |||
| math/vector.cpp math/matrix.cpp math/transform.cpp math/trig.cpp \ | |||
| math/constants.cpp math/geometry.cpp math/real.cpp math/half.cpp \ | |||
| math/vector.cpp math/matrix.cpp math/transform.cpp math/half.cpp \ | |||
| math/constants.cpp math/geometry.cpp math/real.cpp \ | |||
| \ | |||
| gpu/shader.cpp gpu/indexbuffer.cpp gpu/vertexbuffer.cpp \ | |||
| gpu/framebuffer.cpp gpu/texture.cpp gpu/renderer.cpp \ | |||
| @@ -161,7 +161,6 @@ | |||
| <ClCompile Include="math\matrix.cpp" /> | |||
| <ClCompile Include="math\real.cpp" /> | |||
| <ClCompile Include="math\transform.cpp" /> | |||
| <ClCompile Include="math\trig.cpp" /> | |||
| <ClCompile Include="math\vector.cpp" /> | |||
| <ClCompile Include="mesh\mesh.cpp" /> | |||
| <ClCompile Include="mesh\primitivemesh.cpp" /> | |||
| @@ -141,9 +141,6 @@ | |||
| <ClCompile Include="math\transform.cpp"> | |||
| <Filter>math</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="math\trig.cpp"> | |||
| <Filter>math</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="math\vector.cpp"> | |||
| <Filter>math</Filter> | |||
| </ClCompile> | |||
| @@ -22,8 +22,6 @@ | |||
| */ | |||
| #define LOL_FEATURE_THREADS 1 | |||
| #define LOL_FEATURE_CHEAP_BRANCHES 1 | |||
| #define LOL_FEATURE_VERY_CHEAP_BRANCHES 0 | |||
| #define LOL_FEATURE_VISUAL_STUDIO_THAT_FUCKING_PIECE_OF_SHIT_COMPILER 0 | |||
| #if defined EMSCRIPTEN | |||
| @@ -172,17 +172,6 @@ LOL_ATTR_NODISCARD static inline ldouble lerp(ldouble const &a, ldouble const &b | |||
| return mix(a, b, x); | |||
| } | |||
| /* These accelerated functions will be merged into the above, one day */ | |||
| LOL_ATTR_NODISCARD double lol_sin(double); | |||
| LOL_ATTR_NODISCARD double lol_cos(double); | |||
| LOL_ATTR_NODISCARD double lol_tan(double); | |||
| void lol_sincos(double, double*, double*); | |||
| void lol_sincos(float, float*, float*); | |||
| LOL_ATTR_NODISCARD double lol_asin(double); | |||
| LOL_ATTR_NODISCARD double lol_acos(double); | |||
| LOL_ATTR_NODISCARD double lol_atan(double); | |||
| LOL_ATTR_NODISCARD double lol_atan2(double, double); | |||
| /* C++ doesn't define abs() and fmod() for all types; we add these for | |||
| * convenience to avoid adding complexity to vector.h. */ | |||
| LOL_ATTR_NODISCARD static inline int8_t abs(int8_t x) { return std::abs(x); } | |||
| @@ -1,387 +0,0 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; you can redistribute it and/or | |||
| // modify it under the terms of the Do What The Fuck You Want To | |||
| // Public License, Version 2, as published by Sam Hocevar. See | |||
| // http://www.wtfpl.net/ for more details. | |||
| // | |||
| #include <lol/engine-internal.h> | |||
| #if defined HAVE_FASTMATH_H | |||
| # include <fastmath.h> | |||
| #endif | |||
| // Optimisation helpers | |||
| #if defined __GNUC__ | |||
| # define __likely(x) __builtin_expect(!!(x), 1) | |||
| # define __unlikely(x) __builtin_expect(!!(x), 0) | |||
| # define INLINEATTR __attribute__((always_inline)) | |||
| # if defined __x86_64__ | |||
| # define FP_USE(x) __asm__("" : "+x" (x)) | |||
| # elif defined __i386__ /* FIXME: this isn't good */ | |||
| # define FP_USE(x) __asm__("" : "+m" (x)) | |||
| # else | |||
| # define FP_USE(x) (void)(x) | |||
| # endif | |||
| #else | |||
| # define __likely(x) x | |||
| # define __unlikely(x) x | |||
| # define INLINEATTR | |||
| # define FP_USE(x) (void)(x) | |||
| #endif | |||
| namespace lol | |||
| { | |||
| static const double PI_2 = 1.57079632679489661923132; | |||
| static const double PI_4 = 0.785398163397448309615661; | |||
| static const double INV_PI = 0.318309886183790671537768; | |||
| static const double ROOT3 = 1.73205080756887729352745; | |||
| static const double ZERO = 0.0; | |||
| static const double ONE = 1.0; | |||
| static const double NEG_ONE = -1.0; | |||
| static const double HALF = 0.5; | |||
| static const double QUARTER = 0.25; | |||
| static const double TWO = 2.0; | |||
| #if defined __GNUC__ | |||
| static const double VERY_SMALL_NUMBER = 0x1.0p-128; | |||
| #else | |||
| static const double VERY_SMALL_NUMBER = 3e-39; | |||
| #endif | |||
| static const double TWO_EXP_52 = 4503599627370496.0; | |||
| static const double TWO_EXP_54 = 18014398509481984.0; | |||
| /** sin Taylor series coefficients. */ | |||
| static const double SC[] = | |||
| { | |||
| -1.6449340668482264364724e-0, // π^2/3! | |||
| +8.1174242528335364363700e-1, // π^4/5! | |||
| -1.9075182412208421369647e-1, // π^6/7! | |||
| +2.6147847817654800504653e-2, // π^8/9! | |||
| -2.3460810354558236375089e-3, // π^10/11! | |||
| +1.4842879303107100368487e-4, // π^12/13! | |||
| -6.9758736616563804745344e-6, // π^14/15! | |||
| +2.5312174041370276513517e-7, // π^16/17! | |||
| }; | |||
| /* Note: the last value should be -1.3878952462213772114468e-7 (ie. | |||
| * π^18/18!) but we tweak it in order to get the better average precision | |||
| * required for tan() computations when close to π/2+kπ values. */ | |||
| static const double CC[] = | |||
| { | |||
| -4.9348022005446793094172e-0, // π^2/2! | |||
| +4.0587121264167682181850e-0, // π^4/4! | |||
| -1.3352627688545894958753e-0, // π^6/6! | |||
| +2.3533063035889320454188e-1, // π^8/8! | |||
| -2.5806891390014060012598e-2, // π^10/10! | |||
| +1.9295743094039230479033e-3, // π^12/12! | |||
| -1.0463810492484570711802e-4, // π^14/14! | |||
| +4.3030695870329470072978e-6, // π^16/16! | |||
| -1.3777e-7, | |||
| }; | |||
| /* These coefficients use Sloane’s http://oeis.org/A002430 and | |||
| * http://oeis.org/A036279 sequences for the Taylor series of tan(). | |||
| * Note: the last value should be 2.12485922978838540352881e5 (ie. | |||
| * 443861162*π^18/1856156927625), but we tweak it in order to get | |||
| * sub 1e-11 average precision in a larger range. */ | |||
| static const double TC[] = | |||
| { | |||
| 3.28986813369645287294483e0, // π^2/3 | |||
| 1.29878788045336582981920e1, // 2*π^4/15 | |||
| 5.18844961612069061254404e1, // 17*π^6/315 | |||
| 2.07509320280908496804928e2, // 62*π^8/2835 | |||
| 8.30024701695986756361561e2, // 1382*π^10/155925 | |||
| 3.32009324029001216460018e3, // 21844*π^12/6081075 | |||
| 1.32803704909665483598490e4, // 929569*π^14/638512875 | |||
| 5.31214808666037709352112e4, // 6404582*π^16/10854718875 | |||
| 2.373e5, | |||
| }; | |||
| static inline double lol_fabs(double x) INLINEATTR; | |||
| #if defined __GNUC__ | |||
| static inline double lol_round(double x) INLINEATTR; | |||
| static inline double lol_trunc(double x) INLINEATTR; | |||
| #endif | |||
| static inline double lol_fabs(double x) | |||
| { | |||
| #if defined __GNUC__ | |||
| return __builtin_fabs(x); | |||
| #else | |||
| using std::fabs; | |||
| return fabs(x); | |||
| #endif | |||
| } | |||
| #if defined __GNUC__ | |||
| static inline double lol_round(double x) | |||
| { | |||
| return __builtin_round(x); | |||
| } | |||
| static inline double lol_trunc(double x) | |||
| { | |||
| return __builtin_trunc(x); | |||
| } | |||
| #endif | |||
| double lol_sin(double x) | |||
| { | |||
| double absx = lol_fabs(x * INV_PI); | |||
| /* If branches are cheap, skip the cycle count when |x| < π/4, | |||
| * and only do the Taylor series up to the required precision. */ | |||
| #if LOL_FEATURE_CHEAP_BRANCHES | |||
| if (absx < QUARTER) | |||
| { | |||
| /* Computing x^4 is one multiplication too many we do, but it helps | |||
| * interleave the Taylor series operations a lot better. */ | |||
| double x2 = absx * absx; | |||
| double x4 = x2 * x2; | |||
| double sub1 = (SC[3] * x4 + SC[1]) * x4 + ONE; | |||
| double sub2 = (SC[4] * x4 + SC[2]) * x4 + SC[0]; | |||
| double taylor = sub2 * x2 + sub1; | |||
| return x * taylor; | |||
| } | |||
| #endif | |||
| /* Wrap |x| to the range [-1, 1] and keep track of the number of | |||
| * cycles required. If odd, we'll need to change the sign of the | |||
| * result. */ | |||
| double num_cycles = absx + TWO_EXP_52; | |||
| FP_USE(num_cycles); num_cycles -= TWO_EXP_52; | |||
| double is_even = TWO * num_cycles - ONE; | |||
| FP_USE(is_even); is_even += TWO_EXP_54; | |||
| FP_USE(is_even); is_even -= TWO_EXP_54; | |||
| FP_USE(is_even); | |||
| is_even -= TWO * num_cycles - ONE; | |||
| double sign = is_even; | |||
| absx -= num_cycles; | |||
| /* If branches are very cheap, we have the option to do the Taylor | |||
| * series at a much lower degree by splitting. */ | |||
| #if LOL_FEATURE_VERY_CHEAP_BRANCHES | |||
| if (lol_fabs(absx) > QUARTER) | |||
| { | |||
| sign = (x * absx >= 0.0) ? sign : -sign; | |||
| double x1 = HALF - lol_fabs(absx); | |||
| double x2 = x1 * x1; | |||
| double x4 = x2 * x2; | |||
| double sub1 = ((CC[5] * x4 + CC[3]) * x4 + CC[1]) * x4 + ONE; | |||
| double sub2 = (CC[4] * x4 + CC[2]) * x4 + CC[0]; | |||
| double taylor = sub2 * x2 + sub1; | |||
| return taylor * sign; | |||
| } | |||
| #endif | |||
| sign *= (x >= 0.0) ? D_PI : -D_PI; | |||
| /* Compute a Tailor series for sin() and combine sign information. */ | |||
| double x2 = absx * absx; | |||
| double x4 = x2 * x2; | |||
| #if LOL_FEATURE_VERY_CHEAP_BRANCHES | |||
| double sub1 = (SC[3] * x4 + SC[1]) * x4 + ONE; | |||
| double sub2 = (SC[4] * x4 + SC[2]) * x4 + SC[0]; | |||
| #else | |||
| double sub1 = (((SC[7] * x4 + SC[5]) * x4 + SC[3]) * x4 + SC[1]) * x4 + ONE; | |||
| double sub2 = ((SC[6] * x4 + SC[4]) * x4 + SC[2]) * x4 + SC[0]; | |||
| #endif | |||
| double taylor = sub2 * x2 + sub1; | |||
| return absx * taylor * sign; | |||
| } | |||
| double lol_cos(double x) | |||
| { | |||
| double absx = lol_fabs(x * INV_PI); | |||
| #if LOL_FEATURE_CHEAP_BRANCHES | |||
| if (absx < QUARTER) | |||
| { | |||
| double x2 = absx * absx; | |||
| double x4 = x2 * x2; | |||
| double sub1 = (CC[5] * x4 + CC[3]) * x4 + CC[1]; | |||
| double sub2 = (CC[4] * x4 + CC[2]) * x4 + CC[0]; | |||
| double taylor = (sub1 * x2 + sub2) * x2 + ONE; | |||
| return taylor; | |||
| } | |||
| #endif | |||
| double num_cycles = absx + TWO_EXP_52; | |||
| FP_USE(num_cycles); num_cycles -= TWO_EXP_52; | |||
| double is_even = TWO * num_cycles - ONE; | |||
| FP_USE(is_even); is_even += TWO_EXP_54; | |||
| FP_USE(is_even); is_even -= TWO_EXP_54; | |||
| FP_USE(is_even); | |||
| is_even -= TWO * num_cycles - ONE; | |||
| double sign = is_even; | |||
| absx -= num_cycles; | |||
| #if LOL_FEATURE_VERY_CHEAP_BRANCHES | |||
| if (lol_fabs(absx) > QUARTER) | |||
| { | |||
| double x1 = HALF - lol_fabs(absx); | |||
| double x2 = x1 * x1; | |||
| double x4 = x2 * x2; | |||
| double sub1 = (SC[3] * x4 + SC[1]) * x4 + ONE; | |||
| double sub2 = (SC[4] * x4 + SC[2]) * x4 + SC[0]; | |||
| double taylor = sub2 * x2 + sub1; | |||
| return x1 * taylor * sign * D_PI; | |||
| } | |||
| #endif | |||
| double x2 = absx * absx; | |||
| double x4 = x2 * x2; | |||
| #if LOL_FEATURE_VERY_CHEAP_BRANCHES | |||
| double sub1 = ((CC[5] * x4 + CC[3]) * x4 + CC[1]) * x4 + ONE; | |||
| double sub2 = (CC[4] * x4 + CC[2]) * x4 + CC[0]; | |||
| #else | |||
| double sub1 = (((CC[7] * x4 + CC[5]) * x4 + CC[3]) * x4 + CC[1]) * x4 + ONE; | |||
| double sub2 = ((CC[6] * x4 + CC[4]) * x4 + CC[2]) * x4 + CC[0]; | |||
| #endif | |||
| double taylor = sub2 * x2 + sub1; | |||
| return taylor * sign; | |||
| } | |||
| void lol_sincos(double x, double *sinx, double *cosx) | |||
| { | |||
| double absx = lol_fabs(x * INV_PI); | |||
| #if LOL_FEATURE_CHEAP_BRANCHES | |||
| if (absx < QUARTER) | |||
| { | |||
| double x2 = absx * absx; | |||
| double x4 = x2 * x2; | |||
| /* Computing the Taylor series to the 11th order is enough to get | |||
| * x * 1e-11 precision, but we push it to the 13th order so that | |||
| * tan() has a better precision. */ | |||
| double subs1 = ((SC[5] * x4 + SC[3]) * x4 + SC[1]) * x4 + ONE; | |||
| double subs2 = (SC[4] * x4 + SC[2]) * x4 + SC[0]; | |||
| double taylors = subs2 * x2 + subs1; | |||
| *sinx = x * taylors; | |||
| double subc1 = (CC[5] * x4 + CC[3]) * x4 + CC[1]; | |||
| double subc2 = (CC[4] * x4 + CC[2]) * x4 + CC[0]; | |||
| double taylorc = (subc1 * x2 + subc2) * x2 + ONE; | |||
| *cosx = taylorc; | |||
| return; | |||
| } | |||
| #endif | |||
| double num_cycles = absx + TWO_EXP_52; | |||
| FP_USE(num_cycles); num_cycles -= TWO_EXP_52; | |||
| double is_even = TWO * num_cycles - ONE; | |||
| FP_USE(is_even); is_even += TWO_EXP_54; | |||
| FP_USE(is_even); is_even -= TWO_EXP_54; | |||
| FP_USE(is_even); | |||
| is_even -= TWO * num_cycles - ONE; | |||
| double sin_sign = is_even; | |||
| double cos_sign = is_even; | |||
| absx -= num_cycles; | |||
| #if LOL_FEATURE_VERY_CHEAP_BRANCHES | |||
| if (lol_fabs(absx) > QUARTER) | |||
| { | |||
| cos_sign = sin_sign; | |||
| sin_sign = (x * absx >= 0.0) ? sin_sign : -sin_sign; | |||
| double x1 = HALF - lol_fabs(absx); | |||
| double x2 = x1 * x1; | |||
| double x4 = x2 * x2; | |||
| double subs1 = ((CC[5] * x4 + CC[3]) * x4 + CC[1]) * x4 + ONE; | |||
| double subs2 = (CC[4] * x4 + CC[2]) * x4 + CC[0]; | |||
| double taylors = subs2 * x2 + subs1; | |||
| *sinx = taylors * sin_sign; | |||
| double subc1 = ((SC[5] * x4 + SC[3]) * x4 + SC[1]) * x4 + ONE; | |||
| double subc2 = (SC[4] * x4 + SC[2]) * x4 + SC[0]; | |||
| double taylorc = subc2 * x2 + subc1; | |||
| *cosx = x1 * taylorc * cos_sign * D_PI; | |||
| return; | |||
| } | |||
| #endif | |||
| sin_sign *= (x >= 0.0) ? D_PI : -D_PI; | |||
| double x2 = absx * absx; | |||
| double x4 = x2 * x2; | |||
| #if LOL_FEATURE_VERY_CHEAP_BRANCHES | |||
| double subs1 = ((SC[5] * x4 + SC[3]) * x4 + SC[1]) * x4 + ONE; | |||
| double subs2 = (SC[4] * x4 + SC[2]) * x4 + SC[0]; | |||
| double subc1 = ((CC[5] * x4 + CC[3]) * x4 + CC[1]) * x4 + ONE; | |||
| double subc2 = (CC[4] * x4 + CC[2]) * x4 + CC[0]; | |||
| #else | |||
| double subs1 = (((SC[7] * x4 + SC[5]) * x4 + SC[3]) * x4 + SC[1]) * x4 + ONE; | |||
| double subs2 = ((SC[6] * x4 + SC[4]) * x4 + SC[2]) * x4 + SC[0]; | |||
| /* Push Taylor series to the 19th order to enhance tan() accuracy. */ | |||
| double subc1 = (((CC[7] * x4 + CC[5]) * x4 + CC[3]) * x4 + CC[1]) * x4 + ONE; | |||
| double subc2 = (((CC[8] * x4 + CC[6]) * x4 + CC[4]) * x4 + CC[2]) * x4 + CC[0]; | |||
| #endif | |||
| double taylors = subs2 * x2 + subs1; | |||
| *sinx = absx * taylors * sin_sign; | |||
| double taylorc = subc2 * x2 + subc1; | |||
| *cosx = taylorc * cos_sign; | |||
| } | |||
| void lol_sincos(float x, float *sinx, float *cosx) | |||
| { | |||
| double x2 = static_cast<double>(x); | |||
| double s2, c2; | |||
| lol_sincos(x2, &s2, &c2); | |||
| *sinx = static_cast<float>(s2); | |||
| *cosx = static_cast<float>(c2); | |||
| } | |||
| double lol_tan(double x) | |||
| { | |||
| #if LOL_FEATURE_CHEAP_BRANCHES | |||
| double absx = lol_fabs(x * INV_PI); | |||
| /* This value was determined empirically to ensure an error of no | |||
| * more than x * 1e-11 in this range. */ | |||
| if (absx < 0.163) | |||
| { | |||
| double x2 = absx * absx; | |||
| double x4 = x2 * x2; | |||
| double sub1 = (((TC[7] * x4 + TC[5]) * x4 | |||
| + TC[3]) * x4 + TC[1]) * x4 + ONE; | |||
| double sub2 = (((TC[8] * x4 + TC[6]) * x4 | |||
| + TC[4]) * x4 + TC[2]) * x4 + TC[0]; | |||
| double taylor = sub2 * x2 + sub1; | |||
| return x * taylor; | |||
| } | |||
| #endif | |||
| double sinx, cosx; | |||
| lol_sincos(x, &sinx, &cosx); | |||
| /* Ensure cosx isn't zero. FIXME: we lose the cosx sign here. */ | |||
| double absc = lol_fabs(cosx); | |||
| if (__unlikely(absc < VERY_SMALL_NUMBER)) | |||
| cosx = VERY_SMALL_NUMBER; | |||
| return sinx / cosx; | |||
| } | |||
| } /* namespace lol */ | |||
| @@ -29,6 +29,13 @@ lolunit_declare_fixture(gcd_test) | |||
| lolunit_assert_equal(18913, lol::gcd(624129, 2061517)); | |||
| } | |||
| lolunit_declare_test(gcd_double) | |||
| { | |||
| lolunit_assert_equal(2.0, lol::gcd(4.0, 6.0)); | |||
| lolunit_assert_equal(2.5, lol::gcd(5.0, 7.5)); | |||
| lolunit_assert_equal(0.125, lol::gcd(4.625, 75.0)); | |||
| } | |||
| lolunit_declare_test(gcd_negative) | |||
| { | |||
| lolunit_assert_equal(2, lol::gcd(4, -6)); | |||
| @@ -60,148 +60,6 @@ lolunit_declare_fixture(trig_test) | |||
| lolunit_assert_doubles_equal(degrees((uint64_t)1), degrees(1.0), 1e-5); | |||
| lolunit_assert_doubles_equal(degrees((int64_t)1), degrees(1.0), 1e-5); | |||
| } | |||
| lolunit_declare_test(sin) | |||
| { | |||
| using std::fabs; | |||
| for (int i = -10000; i < 10000; i++) | |||
| { | |||
| double f = (double)i * (1.0 / 1000.0); | |||
| #if defined __GNUC__ && !defined __SNC__ | |||
| double a = __builtin_sin(f); | |||
| #else | |||
| double a = std::sin(f); | |||
| #endif | |||
| double b = lol_sin(f); | |||
| lolunit_set_context(f); | |||
| lolunit_assert_doubles_equal(a, b, fabs(f) * 1e-11); | |||
| } | |||
| for (int i = -10000; i < 10000; i++) | |||
| { | |||
| double f = (double)i * (1.0 / 100000.0); | |||
| #if defined __GNUC__ && !defined __SNC__ | |||
| double a = __builtin_sin(f); | |||
| #else | |||
| double a = std::sin(f); | |||
| #endif | |||
| double b = lol_sin(f); | |||
| lolunit_set_context(f); | |||
| lolunit_assert_doubles_equal(a, b, fabs(f) * 1e-11); | |||
| } | |||
| } | |||
| lolunit_declare_test(cos) | |||
| { | |||
| using std::fabs; | |||
| for (int i = -10000; i < 10000; i++) | |||
| { | |||
| double f = (double)i * (1.0 / 1000.0); | |||
| #if defined __GNUC__ && !defined __SNC__ | |||
| double a = __builtin_cos(f); | |||
| #else | |||
| double a = std::cos(f); | |||
| #endif | |||
| double b = lol_cos(f); | |||
| lolunit_set_context(f); | |||
| lolunit_assert_doubles_equal(a, b, fabs(f) * 1e-11); | |||
| } | |||
| for (int i = -10000; i < 10000; i++) | |||
| { | |||
| double f = (double)i * (1.0 / 100000.0); | |||
| #if defined __GNUC__ && !defined __SNC__ | |||
| double a = __builtin_cos(f); | |||
| #else | |||
| double a = std::cos(f); | |||
| #endif | |||
| double b = lol_cos(f); | |||
| lolunit_set_context(f); | |||
| lolunit_assert_doubles_equal(a, b, fabs(f) * 1e-11); | |||
| } | |||
| } | |||
| lolunit_declare_test(sin_cos) | |||
| { | |||
| using std::fabs; | |||
| for (int i = -10000; i < 10000; i++) | |||
| { | |||
| double f = (double)i * (1.0 / 1000.0); | |||
| #if defined __GNUC__ && !defined __SNC__ | |||
| double a1 = __builtin_sin(f); | |||
| double a2 = __builtin_cos(f); | |||
| #else | |||
| double a1 = std::sin(f); | |||
| double a2 = std::cos(f); | |||
| #endif | |||
| double b1, b2; | |||
| lol_sincos(f, &b1, &b2); | |||
| lolunit_set_context(f); | |||
| lolunit_assert_doubles_equal(a1, b1, fabs(f) * 1e-11); | |||
| lolunit_assert_doubles_equal(a2, b2, fabs(f) * 1e-11); | |||
| } | |||
| for (int i = -10000; i < 10000; i++) | |||
| { | |||
| double f = (double)i * (1.0 / 100000.0); | |||
| #if defined __GNUC__ && !defined __SNC__ | |||
| double a1 = __builtin_sin(f); | |||
| double a2 = __builtin_cos(f); | |||
| #else | |||
| double a1 = std::sin(f); | |||
| double a2 = std::cos(f); | |||
| #endif | |||
| double b1, b2; | |||
| lol_sincos(f, &b1, &b2); | |||
| lolunit_set_context(f); | |||
| lolunit_assert_doubles_equal(a1, b1, fabs(f) * 1e-11); | |||
| lolunit_assert_doubles_equal(a2, b2, fabs(f) * 1e-11); | |||
| } | |||
| } | |||
| lolunit_declare_test(tan) | |||
| { | |||
| using std::fabs; | |||
| for (int i = -100000; i < 100000; i++) | |||
| { | |||
| double f = (double)i * (1.0 / 10000.0); | |||
| #if defined __GNUC__ && !defined __SNC__ | |||
| double a = __builtin_tan(f); | |||
| #else | |||
| double a = std::tan(f); | |||
| #endif | |||
| double b = lol_tan(f); | |||
| lolunit_set_context(f); | |||
| if (fabs(a) > 1e4) | |||
| lolunit_assert_doubles_equal(a, b, fabs(a) * fabs(a) * 1e-11); | |||
| else if (fabs(a) > 1.0) | |||
| lolunit_assert_doubles_equal(a, b, fabs(a) * 1e-11); | |||
| else | |||
| lolunit_assert_doubles_equal(a, b, fabs(f) * 1e-11); | |||
| } | |||
| for (int i = -10000; i < 10000; i++) | |||
| { | |||
| double f = (double)i * (1.0 / 100000.0); | |||
| #if defined __GNUC__ && !defined __SNC__ | |||
| double a = __builtin_tan(f); | |||
| #else | |||
| double a = std::tan(f); | |||
| #endif | |||
| double b = lol_tan(f); | |||
| lolunit_set_context(f); | |||
| if (fabs(a) > 1e4) | |||
| lolunit_assert_doubles_equal(a, b, fabs(a) * fabs(a) * 1e-11); | |||
| else if (fabs(a) > 1.0) | |||
| lolunit_assert_doubles_equal(a, b, fabs(a) * 1e-11); | |||
| else | |||
| lolunit_assert_doubles_equal(a, b, fabs(f) * 1e-11); | |||
| } | |||
| } | |||
| }; | |||
| } /* namespace lol */ | |||