From 51fc7cd2b3359aa93c2aec216e9af8e97280948c Mon Sep 17 00:00:00 2001 From: jatin Date: Mon, 9 Oct 2023 23:49:45 -0700 Subject: [PATCH 01/10] Set up benchmarks --- bench/CMakeLists.txt | 1 + bench/TrigBench.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 bench/TrigBench.cpp diff --git a/bench/CMakeLists.txt b/bench/CMakeLists.txt index a1aee8b32..cf665174f 100644 --- a/bench/CMakeLists.txt +++ b/bench/CMakeLists.txt @@ -30,3 +30,4 @@ setup_benchmark(MatrixOpsBench MatrixOpsBench.cpp chowdsp_math juce_dsp) setup_benchmark(BufferBench BufferBench.cpp chowdsp_filters juce_dsp) setup_benchmark(DecibelsBench DecibelsBench.cpp chowdsp_math juce_audio_basics) setup_benchmark(AbstractTreeBench AbstractTreeBench.cpp chowdsp_data_structures) +setup_benchmark(TrigBench TrigBench.cpp chowdsp_math juce_dsp) diff --git a/bench/TrigBench.cpp b/bench/TrigBench.cpp new file mode 100644 index 000000000..68cf14957 --- /dev/null +++ b/bench/TrigBench.cpp @@ -0,0 +1,47 @@ +#include + +#include +#include + +static constexpr size_t N = 2048; +static constexpr auto data_mpi_pi = [] +{ + std::array angle_values {}; + for (size_t i = 0; i < N; ++i) + angle_values[i] = -juce::MathConstants::pi + juce::MathConstants::twoPi * (float) i / float (N - 1); + return angle_values; +}(); + +static constexpr auto data_m10pi_10pi = [] +{ + std::array angle_values {}; + for (size_t i = 0; i < N; ++i) + angle_values[i] = -10.0f * (juce::MathConstants::pi + juce::MathConstants::twoPi * (float) i / float (N - 1)); + return angle_values; +}(); + +#define TRIG_BENCH_RANGE(name, range, op) \ + static void name (benchmark::State& state) \ + { \ + for (auto _ : state) \ + { \ + for (const auto& x : range) \ + op \ + } \ + } \ + BENCHMARK (name)->MinTime (1) + +#define TRIG_BENCH(name, op) \ + TRIG_BENCH_RANGE (name ## _mpi_pi, data_mpi_pi, op); \ + TRIG_BENCH_RANGE (name ## _m10pi_10pi, data_m10pi_10pi, op) + +#define SIN_BENCH(name, op) \ + TRIG_BENCH(name ## _sin, { \ + const auto s = op (x); \ + benchmark::DoNotOptimize (s);\ + }) + +SIN_BENCH (std, std::sin); +SIN_BENCH (juce, juce::dsp::FastMathApproximations::sin); + +BENCHMARK_MAIN(); From b73957949e9664665f4733315121a111ed0bdb53 Mon Sep 17 00:00:00 2001 From: jatin Date: Tue, 10 Oct 2023 00:37:48 -0700 Subject: [PATCH 02/10] Starting my own sine approx implementations --- bench/TrigBench.cpp | 28 +++--- .../chowdsp_math/Math/chowdsp_TrigApprox.h | 90 +++++++++++++++++++ modules/dsp/chowdsp_math/chowdsp_math.h | 1 + 3 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h diff --git a/bench/TrigBench.cpp b/bench/TrigBench.cpp index 68cf14957..dd213d8f6 100644 --- a/bench/TrigBench.cpp +++ b/bench/TrigBench.cpp @@ -31,17 +31,21 @@ static constexpr auto data_m10pi_10pi = [] } \ BENCHMARK (name)->MinTime (1) -#define TRIG_BENCH(name, op) \ - TRIG_BENCH_RANGE (name ## _mpi_pi, data_mpi_pi, op); \ - TRIG_BENCH_RANGE (name ## _m10pi_10pi, data_m10pi_10pi, op) - -#define SIN_BENCH(name, op) \ - TRIG_BENCH(name ## _sin, { \ - const auto s = op (x); \ - benchmark::DoNotOptimize (s);\ - }) - -SIN_BENCH (std, std::sin); -SIN_BENCH (juce, juce::dsp::FastMathApproximations::sin); +#define TRIG_BENCH(name, op_mpi_pi, op_full_range) \ + TRIG_BENCH_RANGE (name##_mpi_pi, data_mpi_pi, op_mpi_pi); \ + TRIG_BENCH_RANGE (name##_m10pi_10pi, data_m10pi_10pi, op_full_range) + +#define SIN_BENCH(name, op_mpi_pi, op_full_range) \ + TRIG_BENCH ( \ + name##_sin, { \ + const auto s = op_mpi_pi (x); \ + benchmark::DoNotOptimize (s); }, { \ + const auto s = op_full_range (x); \ + benchmark::DoNotOptimize (s); }) + +SIN_BENCH (std, std::sin, std::sin); +SIN_BENCH (juce, juce::dsp::FastMathApproximations::sin, std::sin); // JUCE approximation is range-limited +SIN_BENCH (bhaskara, chowdsp::TrigApprox::sin_bhaskara_mpi_pi, chowdsp::TrigApprox::sin_bhaskara); +SIN_BENCH (order1, chowdsp::TrigApprox::sin_1st_order_mpi_pi, chowdsp::TrigApprox::sin_1st_order); BENCHMARK_MAIN(); diff --git a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h new file mode 100644 index 000000000..43113294e --- /dev/null +++ b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h @@ -0,0 +1,90 @@ +#pragma once + +namespace chowdsp +{ +/** + * Approximation functions for trigonometric functions. + */ +namespace TrigApprox +{ + namespace detail + { + template + static constexpr auto recip_2pi = (T) 1 / juce::MathConstants::twoPi; + + /** Fast method to wrap a value into the range [-pi, pi] */ + template + T fast_mod_mpi_pi (T x) + { + x += juce::MathConstants::pi; + const auto mod = x - juce::MathConstants::twoPi * T ((int) (x * recip_2pi) ); + return (x >= (T) 0 ? mod : mod + juce::MathConstants::twoPi) - juce::MathConstants::pi; + } + } + + /** + * Bhaskara I's sine approximation valid for x in [-pi, pi] + * + * Max error: 1.64e-3 + * + * Reference: https://en.wikipedia.org/wiki/Bh%C4%81skara_I%27s_sine_approximation_formula + */ + template + T sin_bhaskara_mpi_pi (T x) + { + static constexpr auto pi = juce::MathConstants::pi; + jassert (SIMDUtils::all (x <= pi) + && SIMDUtils::all (x >= -pi)); + + CHOWDSP_USING_XSIMD_STD (abs); + const auto abs_x = abs (x); + const auto x_pi_minus_x = abs_x * (pi - abs_x); + const auto numerator = (T) 16 * x_pi_minus_x; + + static constexpr auto five_pi_sq = (T) 5 * pi * pi; + const auto denominator = five_pi_sq - (T) 4 * x_pi_minus_x; + + const auto result = numerator / denominator; + return SIMDUtils::select (x >= 0, result, -result); + } + + /** Bhaskara I's sine approximation valid across the whole range. */ + template + T sin_bhaskara (T x) + { + return sin_bhaskara_mpi_pi (detail::fast_mod_mpi_pi (x)); + } + + /** + * First-order sine approximation. + * + * Max error: 5.6e-2 + */ + template + T sin_1st_order_mpi_pi (T x) + { + static constexpr auto pi = juce::MathConstants::pi; + jassert (SIMDUtils::all (x <= pi) + && SIMDUtils::all (x >= -pi)); + + CHOWDSP_USING_XSIMD_STD (abs); + static constexpr auto four_over_pi_sq = (T) 4 / (pi * pi); + const auto abs_x = abs (x); + + return four_over_pi_sq * x * (pi - abs_x); + } + + template + T sin_1st_order (T x) + { + return sin_1st_order_mpi_pi (detail::fast_mod_mpi_pi (x)); + } + + // @TODO: + // - triple-angle approximations + // - better docs + // - cosine + // - sine/cosine together + // - tests +} // namespace TrigApprox +} // namespace chowdsp diff --git a/modules/dsp/chowdsp_math/chowdsp_math.h b/modules/dsp/chowdsp_math/chowdsp_math.h index 924434cd3..3bd6baa34 100644 --- a/modules/dsp/chowdsp_math/chowdsp_math.h +++ b/modules/dsp/chowdsp_math/chowdsp_math.h @@ -43,6 +43,7 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE #include "Math/chowdsp_LogApprox.h" #include "Math/chowdsp_PowApprox.h" #include "Math/chowdsp_DecibelsApprox.h" +#include "Math/chowdsp_TrigApprox.h" #if JUCE_MODULE_AVAILABLE_chowdsp_buffers #include From 0af122ae869d04a62789a91bc33a4e1dfd0a02b8 Mon Sep 17 00:00:00 2001 From: jatin Date: Tue, 10 Oct 2023 09:39:06 -0700 Subject: [PATCH 03/10] Working sine approximations --- bench/TrigBench.cpp | 4 + .../chowdsp_math/Math/chowdsp_TrigApprox.h | 104 ++++++++++++++++-- .../chowdsp_math_test/CMakeLists.txt | 1 + .../chowdsp_math_test/TrigApproxTest.cpp | 32 ++++++ 4 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp diff --git a/bench/TrigBench.cpp b/bench/TrigBench.cpp index dd213d8f6..b6dc883d1 100644 --- a/bench/TrigBench.cpp +++ b/bench/TrigBench.cpp @@ -47,5 +47,9 @@ SIN_BENCH (std, std::sin, std::sin); SIN_BENCH (juce, juce::dsp::FastMathApproximations::sin, std::sin); // JUCE approximation is range-limited SIN_BENCH (bhaskara, chowdsp::TrigApprox::sin_bhaskara_mpi_pi, chowdsp::TrigApprox::sin_bhaskara); SIN_BENCH (order1, chowdsp::TrigApprox::sin_1st_order_mpi_pi, chowdsp::TrigApprox::sin_1st_order); +SIN_BENCH (tri_angle_9, chowdsp::TrigApprox::sin_3angle_mpi_pi<9>, chowdsp::TrigApprox::sin_3angle<9>); +SIN_BENCH (tri_angle_7, chowdsp::TrigApprox::sin_3angle_mpi_pi<7>, chowdsp::TrigApprox::sin_3angle<7>); +SIN_BENCH (tri_angle_5, chowdsp::TrigApprox::sin_3angle_mpi_pi<5>, chowdsp::TrigApprox::sin_3angle<5>); +SIN_BENCH (tri_angle_3, chowdsp::TrigApprox::sin_3angle_mpi_pi<3>, chowdsp::TrigApprox::sin_3angle<3>); BENCHMARK_MAIN(); diff --git a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h index 43113294e..c89f57572 100644 --- a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h +++ b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h @@ -7,20 +7,68 @@ namespace chowdsp */ namespace TrigApprox { +#ifndef DOXYGEN namespace detail { template static constexpr auto recip_2pi = (T) 1 / juce::MathConstants::twoPi; + template + T truncate (T x) + { + return T ((int) x); + } + + template + xsimd::batch truncate (xsimd::batch x) + { + return xsimd::to_float (xsimd::to_int (x)); + } + /** Fast method to wrap a value into the range [-pi, pi] */ template T fast_mod_mpi_pi (T x) { - x += juce::MathConstants::pi; - const auto mod = x - juce::MathConstants::twoPi * T ((int) (x * recip_2pi) ); - return (x >= (T) 0 ? mod : mod + juce::MathConstants::twoPi) - juce::MathConstants::pi; + using NumericType = SampleTypeHelpers::NumericType; + x += juce::MathConstants::pi; + const auto mod = x - juce::MathConstants::twoPi * truncate (x * recip_2pi); + return SIMDUtils::select (x >= (T) 0, mod, mod + juce::MathConstants::twoPi) - juce::MathConstants::pi; } - } + + template + T sin_o3 (T theta, T theta_sq, [[maybe_unused]] T theta_quad) + { + using NumericType = SampleTypeHelpers::NumericType; + static_assert (order % 2 == 1 && order > 1 && order <= 9, "Order must be an odd integer within [3,9]"); + + if constexpr (order == 9) + { + const auto s1 = NumericType (1) + NumericType (-1.66666662492e-1) * theta_sq; + const auto s2 = NumericType (8.33330303755e-3) + NumericType (-1.98339763113e-4) * theta_sq; + const auto s3 = NumericType (2.68396896919e-6) * theta_quad; + return theta * (s1 + (s2 + s3) * theta_quad); + } + else if constexpr (order == 7) + { + const auto s1 = NumericType (1) + NumericType (-1.66664550673e-1) * theta_sq; + const auto s2 = NumericType (8.32622561667e-3) + NumericType (-1.90698699142e-4) * theta_sq; + return theta * (s1 + s2 * theta_quad); + } + else if constexpr (order == 5) + { + const auto s1 = NumericType (1) + NumericType (-1.66531874421e-1) * theta_sq; + const auto s2 = NumericType (7.99611485830e-3) * theta_quad; + return theta * (s1 + s2); + } + else if constexpr (order == 3) + { + + const auto s1 = NumericType (1) + NumericType (-1.57763153266e-1) * theta_sq; + return theta * s1; + } + } + } // namespace detail +#endif // DOXYGEN /** * Bhaskara I's sine approximation valid for x in [-pi, pi] @@ -32,17 +80,18 @@ namespace TrigApprox template T sin_bhaskara_mpi_pi (T x) { - static constexpr auto pi = juce::MathConstants::pi; + using NumericType = SampleTypeHelpers::NumericType; + static constexpr auto pi = juce::MathConstants::pi; jassert (SIMDUtils::all (x <= pi) && SIMDUtils::all (x >= -pi)); CHOWDSP_USING_XSIMD_STD (abs); const auto abs_x = abs (x); const auto x_pi_minus_x = abs_x * (pi - abs_x); - const auto numerator = (T) 16 * x_pi_minus_x; + const auto numerator = (NumericType) 16 * x_pi_minus_x; - static constexpr auto five_pi_sq = (T) 5 * pi * pi; - const auto denominator = five_pi_sq - (T) 4 * x_pi_minus_x; + static constexpr auto five_pi_sq = (NumericType) 5 * pi * pi; + const auto denominator = five_pi_sq - (NumericType) 4 * x_pi_minus_x; const auto result = numerator / denominator; return SIMDUtils::select (x >= 0, result, -result); @@ -63,12 +112,13 @@ namespace TrigApprox template T sin_1st_order_mpi_pi (T x) { - static constexpr auto pi = juce::MathConstants::pi; + using NumericType = SampleTypeHelpers::NumericType; + static constexpr auto pi = juce::MathConstants::pi; jassert (SIMDUtils::all (x <= pi) && SIMDUtils::all (x >= -pi)); CHOWDSP_USING_XSIMD_STD (abs); - static constexpr auto four_over_pi_sq = (T) 4 / (pi * pi); + static constexpr auto four_over_pi_sq = (NumericType) 4 / (pi * pi); const auto abs_x = abs (x); return four_over_pi_sq * x * (pi - abs_x); @@ -80,6 +130,40 @@ namespace TrigApprox return sin_1st_order_mpi_pi (detail::fast_mod_mpi_pi (x)); } + /** + * Sine approximation using a Taylor approximation on the + * range [-pi/3, pi/3], expanded to [-pi, pi] using the + * triple angle formula. + * + * The approximation is parameterized on the order of + * the Taylor approximation, which _must_ be an odd integer. + * + * Max error (9th-order): 3.5e-10 + * Max error (7th-order): 1.142e-7 + * Max error (5th-order): 4.3e-5 + * Max error (3th-order): 7.3e-3 + */ + template + T sin_3angle_mpi_pi (T x) + { + using NumericType = SampleTypeHelpers::NumericType; + [[maybe_unused]] static constexpr auto pi = juce::MathConstants::pi; + jassert (SIMDUtils::all (x <= pi) + && SIMDUtils::all (x >= -pi)); + + const auto theta_o3 = x * NumericType (1.0 / 3.0); + const auto theta_o3_sq = theta_o3 * theta_o3; + const auto theta_o3_quad = theta_o3_sq * theta_o3_sq; + const auto sin_o3 = detail::sin_o3 (theta_o3, theta_o3_sq, theta_o3_quad); + return sin_o3 * ((NumericType) 3 + (NumericType) -4 * sin_o3 * sin_o3); + } + + template + T sin_3angle (T x) + { + return sin_3angle_mpi_pi (detail::fast_mod_mpi_pi (x)); + } + // @TODO: // - triple-angle approximations // - better docs diff --git a/tests/dsp_tests/chowdsp_math_test/CMakeLists.txt b/tests/dsp_tests/chowdsp_math_test/CMakeLists.txt index 84be7dd34..67c42f81d 100644 --- a/tests/dsp_tests/chowdsp_math_test/CMakeLists.txt +++ b/tests/dsp_tests/chowdsp_math_test/CMakeLists.txt @@ -14,4 +14,5 @@ target_sources(chowdsp_math_test LogApproxTest.cpp PowApproxTest.cpp DecibelsApproxTest.cpp + TrigApproxTest.cpp ) diff --git a/tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp b/tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp new file mode 100644 index 000000000..4a469c33b --- /dev/null +++ b/tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp @@ -0,0 +1,32 @@ +#include +#include + +namespace ta = chowdsp::TrigApprox; + +TEMPLATE_TEST_CASE ("Trig Approx Test", "[dsp][math][simd]", float, double, xsimd::batch, xsimd::batch) +{ + using FloatType = TestType; + using NumericType = chowdsp::SampleTypeHelpers::NumericType; + + SECTION ("Sine") + { + const auto tester = [] (FloatType (*testFunc) (FloatType), NumericType margin) + { + static constexpr auto pi10 = (NumericType) 10 * juce::MathConstants::pi; + static constexpr auto inc = (NumericType) 0.001 * juce::MathConstants::pi; + for (auto x = -pi10; x < pi10; x += inc) + { + const auto ref = std::sin (x); + const auto input = (FloatType) x; + REQUIRE (testFunc (input) == SIMDApprox { ref }.margin (margin)); + } + }; + + tester (&ta::sin_bhaskara, (NumericType) 1.65e-3); + tester (&ta::sin_1st_order, (NumericType) 5.65e-2); + tester (&ta::sin_3angle<9>, (NumericType) 3.5e-10); + tester (&ta::sin_3angle<7>, (NumericType) 1.15e-7); + tester (&ta::sin_3angle<5>, (NumericType) 4.35e-5); + tester (&ta::sin_3angle<3>, (NumericType) 7.35e-3); + } +} From b9148f41cc16fc0275f2deade23b7e6be40897cd Mon Sep 17 00:00:00 2001 From: jatin Date: Tue, 10 Oct 2023 09:41:32 -0700 Subject: [PATCH 04/10] Cleaning up comments --- modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h index c89f57572..f1ab0a238 100644 --- a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h +++ b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h @@ -4,6 +4,10 @@ namespace chowdsp { /** * Approximation functions for trigonometric functions. + * + * References: + * - Sine plots: https://www.desmos.com/calculator/rnsmcx6wb5 + * - Taylor polynomials for sine triple-angle approx.: https://www.wolframcloud.com/env/chowdsp/sin_approx.nb */ namespace TrigApprox { @@ -124,6 +128,7 @@ namespace TrigApprox return four_over_pi_sq * x * (pi - abs_x); } + /** Full-range first-order sine approximation. */ template T sin_1st_order (T x) { @@ -158,6 +163,7 @@ namespace TrigApprox return sin_o3 * ((NumericType) 3 + (NumericType) -4 * sin_o3 * sin_o3); } + /** Full-range triple-angle sine approximation. */ template T sin_3angle (T x) { @@ -165,10 +171,9 @@ namespace TrigApprox } // @TODO: - // - triple-angle approximations - // - better docs // - cosine // - sine/cosine together - // - tests + // - more tests + // - combined sine function with enum template? } // namespace TrigApprox } // namespace chowdsp From 535f8b8af50e2c148f87b18ddf31f56ac4626049 Mon Sep 17 00:00:00 2001 From: jatin Date: Tue, 10 Oct 2023 13:07:17 -0700 Subject: [PATCH 05/10] Add cosine approximations --- .../chowdsp_math/Math/chowdsp_TrigApprox.h | 147 +++++++++++++++++- .../chowdsp_math_test/TrigApproxTest.cpp | 35 ++++- 2 files changed, 175 insertions(+), 7 deletions(-) diff --git a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h index f1ab0a238..c1f556a49 100644 --- a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h +++ b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h @@ -7,7 +7,6 @@ namespace chowdsp * * References: * - Sine plots: https://www.desmos.com/calculator/rnsmcx6wb5 - * - Taylor polynomials for sine triple-angle approx.: https://www.wolframcloud.com/env/chowdsp/sin_approx.nb */ namespace TrigApprox { @@ -39,6 +38,24 @@ namespace TrigApprox return SIMDUtils::select (x >= (T) 0, mod, mod + juce::MathConstants::twoPi) - juce::MathConstants::pi; } + /** Shifts range [-pi, pi] to [-pi/2, 3pi/2] for cosine calculations */ + template + T shift_cosine_range (T x) + { + using NumericType = SampleTypeHelpers::NumericType; + return SIMDUtils::select (x >= -juce::MathConstants::halfPi, + x, + x + juce::MathConstants::twoPi); + } + + /** + * Polynomial approximations of sine for [-pi/3, pi] + * + * Starts as a Taylor approximation, but then tries to fix the end-points, + * minimize max error. + * + * Reference: https://www.wolframcloud.com/env/chowdsp/sin_approx.nb + */ template T sin_o3 (T theta, T theta_sq, [[maybe_unused]] T theta_quad) { @@ -71,6 +88,41 @@ namespace TrigApprox return theta * s1; } } + + /** + * Polynomial approximations of cosine for [-pi/3, pi] + * + * Starts as a Taylor approximation, but then tries to fix the end-points, + * minimize max error. + * + * Reference: https://www.wolframcloud.com/env/chowdsp/cos_approx.nb + * + * @TODO: I think I can get the error for these down a bit lower, just need some more math/Mathematica tricks + */ + template + T cos_o3 ([[maybe_unused]] T theta, T theta_sq, [[maybe_unused]] T theta_quad) + { + using NumericType = SampleTypeHelpers::NumericType; + static_assert (order % 2 == 0 && order > 2 && order <= 8, "Order must be an odd integer within [2,8]"); + + if constexpr (order == 8) + { + const auto c1 = (NumericType) -0.5 + (NumericType) 4.1666570372109e-2 * theta_sq; + const auto c2 = (NumericType) -1.3884536712849e-3 + (NumericType) 2.4185513623303e-5 * theta_sq; + return (NumericType) 1 + theta_sq * (c1 + c2 * theta_quad); + } + else if constexpr (order == 6) + { + const auto c1 = (NumericType) -0.5 + (NumericType) 4.165121515e-2 * theta_sq; + const auto c2 = (NumericType) -1.348103430e-3 * theta_quad; + return (NumericType) 1 + theta_sq * (c1 + c2); + } + else if constexpr (order == 4) + { + const auto c1 = (NumericType) -0.5 + (NumericType) 4.017380231e-2 * theta_sq; + return (NumericType) 1 + theta_sq * c1; + } + } } // namespace detail #endif // DOXYGEN @@ -170,10 +222,99 @@ namespace TrigApprox return sin_3angle_mpi_pi (detail::fast_mod_mpi_pi (x)); } + /** + * Bhaskara I's cosine approximation valid for x in [-pi, pi] + * + * Max error: 1.64e-3 + * + * Reference: https://en.wikipedia.org/wiki/Bh%C4%81skara_I%27s_sine_approximation_formula + */ + template + T cos_bhaskara_mpi_pi (T x) + { + using NumericType = SampleTypeHelpers::NumericType; + static constexpr auto pi = juce::MathConstants::pi; + jassert (SIMDUtils::all (x <= pi) + && SIMDUtils::all (x >= -pi)); + + x = detail::shift_cosine_range (x); + const auto needs_flip = x > juce::MathConstants::halfPi; + + x = SIMDUtils::select (needs_flip, x - pi, x); + + static constexpr auto pi_sq = pi * pi; + const auto x_sq = x * x; + const auto result = (pi_sq - (NumericType) 4 * x_sq) / (pi_sq + x_sq); + return SIMDUtils::select (needs_flip, -result, result); + } + + /** Bhaskara I's cosine approximation valid across the whole range. */ + template + T cos_bhaskara (T x) + { + return cos_bhaskara_mpi_pi (detail::fast_mod_mpi_pi (x)); + } + + /** + * First-order cosine approximation. + * + * Max error: 5.6e-2 + */ + template + T cos_1st_order_mpi_pi (T x) + { + using NumericType = SampleTypeHelpers::NumericType; + [[maybe_unused]] static constexpr auto pi = juce::MathConstants::pi; + jassert (SIMDUtils::all (x <= pi) + && SIMDUtils::all (x >= -pi)); + + x = detail::shift_cosine_range (x); + return -sin_1st_order_mpi_pi (x - juce::MathConstants::halfPi); + } + + /** Full-range first-order cosine approximation. */ + template + T cos_1st_order (T x) + { + return cos_1st_order_mpi_pi (detail::fast_mod_mpi_pi (x)); + } + + /** + * Sine approximation using a Taylor approximation on the + * range [-pi/3, pi/3], expanded to [-pi, pi] using the + * triple angle formula. + * + * The approximation is parameterized on the order of + * the Taylor approximation, which _must_ be an odd integer. + * + * Max error (8th-order): 8.7e-9 + * Max error (6th-order): 2.82e-6 + * Max error (4th-order): 7.93e-4 + */ + template + T cos_3angle_mpi_pi (T x) + { + using NumericType = SampleTypeHelpers::NumericType; + [[maybe_unused]] static constexpr auto pi = juce::MathConstants::pi; + jassert (SIMDUtils::all (x <= pi) + && SIMDUtils::all (x >= -pi)); + + const auto theta_o3 = x * NumericType (1.0 / 3.0); + const auto theta_o3_sq = theta_o3 * theta_o3; + const auto theta_o3_quad = theta_o3_sq * theta_o3_sq; + const auto cos_o3 = detail::cos_o3 (theta_o3, theta_o3_sq, theta_o3_quad); + return cos_o3 * ((NumericType) -3 + (NumericType) 4 * cos_o3 * cos_o3); + } + + /** Full-range triple-angle sine approximation. */ + template + T cos_3angle (T x) + { + return cos_3angle_mpi_pi (detail::fast_mod_mpi_pi (x)); + } + // @TODO: - // - cosine // - sine/cosine together - // - more tests // - combined sine function with enum template? } // namespace TrigApprox } // namespace chowdsp diff --git a/tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp b/tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp index 4a469c33b..3712ee85f 100644 --- a/tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp +++ b/tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp @@ -12,6 +12,9 @@ TEMPLATE_TEST_CASE ("Trig Approx Test", "[dsp][math][simd]", float, double, xsim { const auto tester = [] (FloatType (*testFunc) (FloatType), NumericType margin) { + if constexpr (std::is_same_v) + margin = std::sqrt (margin); + static constexpr auto pi10 = (NumericType) 10 * juce::MathConstants::pi; static constexpr auto inc = (NumericType) 0.001 * juce::MathConstants::pi; for (auto x = -pi10; x < pi10; x += inc) @@ -24,9 +27,33 @@ TEMPLATE_TEST_CASE ("Trig Approx Test", "[dsp][math][simd]", float, double, xsim tester (&ta::sin_bhaskara, (NumericType) 1.65e-3); tester (&ta::sin_1st_order, (NumericType) 5.65e-2); - tester (&ta::sin_3angle<9>, (NumericType) 3.5e-10); - tester (&ta::sin_3angle<7>, (NumericType) 1.15e-7); - tester (&ta::sin_3angle<5>, (NumericType) 4.35e-5); - tester (&ta::sin_3angle<3>, (NumericType) 7.35e-3); + tester (&ta::sin_3angle<9, FloatType>, (NumericType) 3.5e-10); + tester (&ta::sin_3angle<7, FloatType>, (NumericType) 1.15e-7); + tester (&ta::sin_3angle<5, FloatType>, (NumericType) 4.35e-5); + tester (&ta::sin_3angle<3, FloatType>, (NumericType) 7.35e-3); + } + + SECTION ("Cosine") + { + const auto tester = [] (FloatType (*testFunc) (FloatType), NumericType margin) + { + if constexpr (std::is_same_v) + margin = std::sqrt (margin); + + static constexpr auto pi10 = (NumericType) 10 * juce::MathConstants::pi; + static constexpr auto inc = (NumericType) 0.001 * juce::MathConstants::pi; + for (auto x = -pi10; x < pi10; x += inc) + { + const auto ref = std::cos (x); + const auto input = (FloatType) x; + REQUIRE (testFunc (input) == SIMDApprox { ref }.margin (margin)); + } + }; + + tester (&ta::cos_bhaskara, (NumericType) 1.65e-3); + tester (&ta::cos_1st_order, (NumericType) 5.65e-2); + tester (&ta::cos_3angle<8, FloatType>, (NumericType) 8.7e-9); + tester (&ta::cos_3angle<6, FloatType>, (NumericType) 2.82e-6); + tester (&ta::cos_3angle<4, FloatType>, (NumericType) 7.93e-4); } } From 41ac237d98ee0dbf40f3db6a4ceed7d027a908dd Mon Sep 17 00:00:00 2001 From: jatin Date: Tue, 10 Oct 2023 17:45:25 -0700 Subject: [PATCH 06/10] Add sine/cosine combination methods --- bench/TrigBench.cpp | 52 +++++++++++++++--- .../chowdsp_math/Math/chowdsp_TrigApprox.h | 55 +++++++++++++++---- .../chowdsp_math_test/TrigApproxTest.cpp | 29 +++++++++- 3 files changed, 113 insertions(+), 23 deletions(-) diff --git a/bench/TrigBench.cpp b/bench/TrigBench.cpp index b6dc883d1..d479b587e 100644 --- a/bench/TrigBench.cpp +++ b/bench/TrigBench.cpp @@ -29,7 +29,7 @@ static constexpr auto data_m10pi_10pi = [] op \ } \ } \ - BENCHMARK (name)->MinTime (1) + BENCHMARK (name)->MinTime (5) #define TRIG_BENCH(name, op_mpi_pi, op_full_range) \ TRIG_BENCH_RANGE (name##_mpi_pi, data_mpi_pi, op_mpi_pi); \ @@ -43,13 +43,47 @@ static constexpr auto data_m10pi_10pi = [] const auto s = op_full_range (x); \ benchmark::DoNotOptimize (s); }) -SIN_BENCH (std, std::sin, std::sin); -SIN_BENCH (juce, juce::dsp::FastMathApproximations::sin, std::sin); // JUCE approximation is range-limited -SIN_BENCH (bhaskara, chowdsp::TrigApprox::sin_bhaskara_mpi_pi, chowdsp::TrigApprox::sin_bhaskara); -SIN_BENCH (order1, chowdsp::TrigApprox::sin_1st_order_mpi_pi, chowdsp::TrigApprox::sin_1st_order); -SIN_BENCH (tri_angle_9, chowdsp::TrigApprox::sin_3angle_mpi_pi<9>, chowdsp::TrigApprox::sin_3angle<9>); -SIN_BENCH (tri_angle_7, chowdsp::TrigApprox::sin_3angle_mpi_pi<7>, chowdsp::TrigApprox::sin_3angle<7>); -SIN_BENCH (tri_angle_5, chowdsp::TrigApprox::sin_3angle_mpi_pi<5>, chowdsp::TrigApprox::sin_3angle<5>); -SIN_BENCH (tri_angle_3, chowdsp::TrigApprox::sin_3angle_mpi_pi<3>, chowdsp::TrigApprox::sin_3angle<3>); +//SIN_BENCH (std, std::sin, std::sin); +//SIN_BENCH (juce, juce::dsp::FastMathApproximations::sin, std::sin); // JUCE approximation is range-limited +//SIN_BENCH (bhaskara, chowdsp::TrigApprox::sin_bhaskara_mpi_pi, chowdsp::TrigApprox::sin_bhaskara); +//SIN_BENCH (order1, chowdsp::TrigApprox::sin_1st_order_mpi_pi, chowdsp::TrigApprox::sin_1st_order); +//SIN_BENCH (tri_angle_9, chowdsp::TrigApprox::sin_3angle_mpi_pi<9>, chowdsp::TrigApprox::sin_3angle<9>); +//SIN_BENCH (tri_angle_7, chowdsp::TrigApprox::sin_3angle_mpi_pi<7>, chowdsp::TrigApprox::sin_3angle<7>); +//SIN_BENCH (tri_angle_5, chowdsp::TrigApprox::sin_3angle_mpi_pi<5>, chowdsp::TrigApprox::sin_3angle<5>); +//SIN_BENCH (tri_angle_3, chowdsp::TrigApprox::sin_3angle_mpi_pi<3>, chowdsp::TrigApprox::sin_3angle<3>); + +#define COS_BENCH(name, op_mpi_pi, op_full_range) \ + TRIG_BENCH ( \ + name##_cos, { \ + const auto c = op_mpi_pi (x); \ + benchmark::DoNotOptimize (c); }, { \ + const auto c = op_full_range (x); \ + benchmark::DoNotOptimize (c); }) + +//COS_BENCH (std, std::cos, std::cos); +//COS_BENCH (juce, juce::dsp::FastMathApproximations::cos, std::cos); // JUCE approximation is range-limited +//COS_BENCH (bhaskara, chowdsp::TrigApprox::cos_bhaskara_mpi_pi, chowdsp::TrigApprox::cos_bhaskara); +//COS_BENCH (order1, chowdsp::TrigApprox::cos_1st_order_mpi_pi, chowdsp::TrigApprox::cos_1st_order); +//COS_BENCH (tri_angle_8, chowdsp::TrigApprox::cos_3angle_mpi_pi<8>, chowdsp::TrigApprox::cos_3angle<8>); +//COS_BENCH (tri_angle_6, chowdsp::TrigApprox::cos_3angle_mpi_pi<6>, chowdsp::TrigApprox::cos_3angle<6>); +//COS_BENCH (tri_angle_4, chowdsp::TrigApprox::cos_3angle_mpi_pi<4>, chowdsp::TrigApprox::cos_3angle<4>); + +#define SIN_COS_BENCH(name, op_mpi_pi, op_full_range) \ + TRIG_BENCH ( \ + name##_sin_cos, { \ + const auto sc = op_mpi_pi (x); \ + benchmark::DoNotOptimize (sc); }, { \ + const auto sc = op_full_range (x); \ + benchmark::DoNotOptimize (sc); }) + +const auto std_sin_cos = [] (float x) +{ + return std::make_tuple (std::sin (x), std::cos (x)); +}; + +SIN_COS_BENCH (std, std_sin_cos, std_sin_cos); +SIN_COS_BENCH (tri_angle_7_8, (chowdsp::TrigApprox::sin_cos_3angle_mpi_pi<7, 8>), (chowdsp::TrigApprox::sin_cos_3angle<7, 8>)); +SIN_COS_BENCH (tri_angle_5_6, (chowdsp::TrigApprox::sin_cos_3angle_mpi_pi<5, 6>), (chowdsp::TrigApprox::sin_cos_3angle<5, 6>)); +SIN_COS_BENCH (tri_angle_3_4, (chowdsp::TrigApprox::sin_cos_3angle_mpi_pi<3, 4>), (chowdsp::TrigApprox::sin_cos_3angle<3, 4>)); BENCHMARK_MAIN(); diff --git a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h index c1f556a49..d23e97986 100644 --- a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h +++ b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h @@ -83,7 +83,6 @@ namespace TrigApprox } else if constexpr (order == 3) { - const auto s1 = NumericType (1) + NumericType (-1.57763153266e-1) * theta_sq; return theta * s1; } @@ -96,8 +95,6 @@ namespace TrigApprox * minimize max error. * * Reference: https://www.wolframcloud.com/env/chowdsp/cos_approx.nb - * - * @TODO: I think I can get the error for these down a bit lower, just need some more math/Mathematica tricks */ template T cos_o3 ([[maybe_unused]] T theta, T theta_sq, [[maybe_unused]] T theta_quad) @@ -107,19 +104,19 @@ namespace TrigApprox if constexpr (order == 8) { - const auto c1 = (NumericType) -0.5 + (NumericType) 4.1666570372109e-2 * theta_sq; - const auto c2 = (NumericType) -1.3884536712849e-3 + (NumericType) 2.4185513623303e-5 * theta_sq; + const auto c1 = (NumericType) -0.5 + (NumericType) 4.16666094252e-2 * theta_sq; + const auto c2 = (NumericType) -1.38854590421e-3 + (NumericType) 2.42367173361e-5 * theta_sq; return (NumericType) 1 + theta_sq * (c1 + c2 * theta_quad); } else if constexpr (order == 6) { - const auto c1 = (NumericType) -0.5 + (NumericType) 4.165121515e-2 * theta_sq; - const auto c2 = (NumericType) -1.348103430e-3 * theta_quad; + const auto c1 = (NumericType) -0.5 + (NumericType) 4.16527333677e-2 * theta_sq; + const auto c2 = (NumericType) -1.34931392239e-3 * theta_quad; return (NumericType) 1 + theta_sq * (c1 + c2); } else if constexpr (order == 4) { - const auto c1 = (NumericType) -0.5 + (NumericType) 4.017380231e-2 * theta_sq; + const auto c1 = (NumericType) -0.5 + (NumericType) 4.01730450758e-2 * theta_sq; return (NumericType) 1 + theta_sq * c1; } } @@ -280,15 +277,15 @@ namespace TrigApprox } /** - * Sine approximation using a Taylor approximation on the + * Cosine approximation using a Taylor approximation on the * range [-pi/3, pi/3], expanded to [-pi, pi] using the * triple angle formula. * * The approximation is parameterized on the order of * the Taylor approximation, which _must_ be an odd integer. * - * Max error (8th-order): 8.7e-9 - * Max error (6th-order): 2.82e-6 + * Max error (8th-order): 7.25e-9 + * Max error (6th-order): 2.24e-6 * Max error (4th-order): 7.93e-4 */ template @@ -306,13 +303,47 @@ namespace TrigApprox return cos_o3 * ((NumericType) -3 + (NumericType) 4 * cos_o3 * cos_o3); } - /** Full-range triple-angle sine approximation. */ + /** Full-range triple-angle cosine approximation. */ template T cos_3angle (T x) { return cos_3angle_mpi_pi (detail::fast_mod_mpi_pi (x)); } + /** + * Combined sine/cosine approximation, using the triple-angle + * approximations described above. + * + * Order should + */ + template + auto sin_cos_3angle_mpi_pi (T x) + { + using NumericType = SampleTypeHelpers::NumericType; + [[maybe_unused]] static constexpr auto pi = juce::MathConstants::pi; + jassert (SIMDUtils::all (x <= pi) + && SIMDUtils::all (x >= -pi)); + + const auto theta_o3 = x * NumericType (1.0 / 3.0); + const auto theta_o3_sq = theta_o3 * theta_o3; + const auto theta_o3_quad = theta_o3_sq * theta_o3_sq; + + const auto sin_o3 = detail::sin_o3 (theta_o3, theta_o3_sq, theta_o3_quad); + const auto s = sin_o3 * ((NumericType) 3 + (NumericType) -4 * sin_o3 * sin_o3); + + const auto cos_o3 = detail::cos_o3 (theta_o3, theta_o3_sq, theta_o3_quad); + const auto c = cos_o3 * ((NumericType) -3 + (NumericType) 4 * cos_o3 * cos_o3); + + return std::make_tuple (s, c); + } + + /** Full-range triple-angle sine approximation. */ + template + auto sin_cos_3angle (T x) + { + return sin_cos_3angle_mpi_pi (detail::fast_mod_mpi_pi (x)); + } + // @TODO: // - sine/cosine together // - combined sine function with enum template? diff --git a/tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp b/tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp index 3712ee85f..108208372 100644 --- a/tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp +++ b/tests/dsp_tests/chowdsp_math_test/TrigApproxTest.cpp @@ -52,8 +52,33 @@ TEMPLATE_TEST_CASE ("Trig Approx Test", "[dsp][math][simd]", float, double, xsim tester (&ta::cos_bhaskara, (NumericType) 1.65e-3); tester (&ta::cos_1st_order, (NumericType) 5.65e-2); - tester (&ta::cos_3angle<8, FloatType>, (NumericType) 8.7e-9); - tester (&ta::cos_3angle<6, FloatType>, (NumericType) 2.82e-6); + tester (&ta::cos_3angle<8, FloatType>, (NumericType) 7.25e-9); + tester (&ta::cos_3angle<6, FloatType>, (NumericType) 2.24e-6); tester (&ta::cos_3angle<4, FloatType>, (NumericType) 7.93e-4); } + + SECTION ("Sine/Cosine") + { + const auto tester = [] (std::tuple (*testFunc) (FloatType), NumericType margin) + { + if constexpr (std::is_same_v) + margin = std::sqrt (margin); + + static constexpr auto pi10 = (NumericType) 10 * juce::MathConstants::pi; + static constexpr auto inc = (NumericType) 0.001 * juce::MathConstants::pi; + for (auto x = -pi10; x < pi10; x += inc) + { + const auto ref_s = std::sin (x); + const auto ref_c = std::cos (x); + const auto input = (FloatType) x; + const auto [test_s, test_c] = testFunc (input); + REQUIRE (test_s == SIMDApprox { ref_s }.margin (margin)); + REQUIRE (test_c == SIMDApprox { ref_c }.margin (margin)); + } + }; + + tester (&ta::sin_cos_3angle<7, 8, FloatType>, (NumericType) 2.0e-7); + tester (&ta::sin_cos_3angle<5, 6, FloatType>, (NumericType) 5.0e-5); + tester (&ta::sin_cos_3angle<3, 4, FloatType>, (NumericType) 8.0e-3); + } } From c5d96001d834ce245afdfde31d7022f64dc50dbd Mon Sep 17 00:00:00 2001 From: jatin Date: Tue, 10 Oct 2023 17:46:12 -0700 Subject: [PATCH 07/10] Clean up comments --- modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h index d23e97986..afc588f3c 100644 --- a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h +++ b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h @@ -343,9 +343,5 @@ namespace TrigApprox { return sin_cos_3angle_mpi_pi (detail::fast_mod_mpi_pi (x)); } - - // @TODO: - // - sine/cosine together - // - combined sine function with enum template? } // namespace TrigApprox } // namespace chowdsp From 91f28265155e76b3404db4b87933c1e14e521b68 Mon Sep 17 00:00:00 2001 From: jatin Date: Tue, 10 Oct 2023 17:49:50 -0700 Subject: [PATCH 08/10] More cleanup --- bench/TrigBench.cpp | 30 +++++++++---------- .../chowdsp_math/Math/chowdsp_TrigApprox.h | 5 ++-- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/bench/TrigBench.cpp b/bench/TrigBench.cpp index d479b587e..5ea213fe7 100644 --- a/bench/TrigBench.cpp +++ b/bench/TrigBench.cpp @@ -43,14 +43,14 @@ static constexpr auto data_m10pi_10pi = [] const auto s = op_full_range (x); \ benchmark::DoNotOptimize (s); }) -//SIN_BENCH (std, std::sin, std::sin); -//SIN_BENCH (juce, juce::dsp::FastMathApproximations::sin, std::sin); // JUCE approximation is range-limited -//SIN_BENCH (bhaskara, chowdsp::TrigApprox::sin_bhaskara_mpi_pi, chowdsp::TrigApprox::sin_bhaskara); -//SIN_BENCH (order1, chowdsp::TrigApprox::sin_1st_order_mpi_pi, chowdsp::TrigApprox::sin_1st_order); -//SIN_BENCH (tri_angle_9, chowdsp::TrigApprox::sin_3angle_mpi_pi<9>, chowdsp::TrigApprox::sin_3angle<9>); -//SIN_BENCH (tri_angle_7, chowdsp::TrigApprox::sin_3angle_mpi_pi<7>, chowdsp::TrigApprox::sin_3angle<7>); -//SIN_BENCH (tri_angle_5, chowdsp::TrigApprox::sin_3angle_mpi_pi<5>, chowdsp::TrigApprox::sin_3angle<5>); -//SIN_BENCH (tri_angle_3, chowdsp::TrigApprox::sin_3angle_mpi_pi<3>, chowdsp::TrigApprox::sin_3angle<3>); +SIN_BENCH (std, std::sin, std::sin); +SIN_BENCH (juce, juce::dsp::FastMathApproximations::sin, std::sin); // JUCE approximation is range-limited +SIN_BENCH (bhaskara, chowdsp::TrigApprox::sin_bhaskara_mpi_pi, chowdsp::TrigApprox::sin_bhaskara); +SIN_BENCH (order1, chowdsp::TrigApprox::sin_1st_order_mpi_pi, chowdsp::TrigApprox::sin_1st_order); +SIN_BENCH (tri_angle_9, chowdsp::TrigApprox::sin_3angle_mpi_pi<9>, chowdsp::TrigApprox::sin_3angle<9>); +SIN_BENCH (tri_angle_7, chowdsp::TrigApprox::sin_3angle_mpi_pi<7>, chowdsp::TrigApprox::sin_3angle<7>); +SIN_BENCH (tri_angle_5, chowdsp::TrigApprox::sin_3angle_mpi_pi<5>, chowdsp::TrigApprox::sin_3angle<5>); +SIN_BENCH (tri_angle_3, chowdsp::TrigApprox::sin_3angle_mpi_pi<3>, chowdsp::TrigApprox::sin_3angle<3>); #define COS_BENCH(name, op_mpi_pi, op_full_range) \ TRIG_BENCH ( \ @@ -60,13 +60,13 @@ static constexpr auto data_m10pi_10pi = [] const auto c = op_full_range (x); \ benchmark::DoNotOptimize (c); }) -//COS_BENCH (std, std::cos, std::cos); -//COS_BENCH (juce, juce::dsp::FastMathApproximations::cos, std::cos); // JUCE approximation is range-limited -//COS_BENCH (bhaskara, chowdsp::TrigApprox::cos_bhaskara_mpi_pi, chowdsp::TrigApprox::cos_bhaskara); -//COS_BENCH (order1, chowdsp::TrigApprox::cos_1st_order_mpi_pi, chowdsp::TrigApprox::cos_1st_order); -//COS_BENCH (tri_angle_8, chowdsp::TrigApprox::cos_3angle_mpi_pi<8>, chowdsp::TrigApprox::cos_3angle<8>); -//COS_BENCH (tri_angle_6, chowdsp::TrigApprox::cos_3angle_mpi_pi<6>, chowdsp::TrigApprox::cos_3angle<6>); -//COS_BENCH (tri_angle_4, chowdsp::TrigApprox::cos_3angle_mpi_pi<4>, chowdsp::TrigApprox::cos_3angle<4>); +COS_BENCH (std, std::cos, std::cos); +COS_BENCH (juce, juce::dsp::FastMathApproximations::cos, std::cos); // JUCE approximation is range-limited +COS_BENCH (bhaskara, chowdsp::TrigApprox::cos_bhaskara_mpi_pi, chowdsp::TrigApprox::cos_bhaskara); +COS_BENCH (order1, chowdsp::TrigApprox::cos_1st_order_mpi_pi, chowdsp::TrigApprox::cos_1st_order); +COS_BENCH (tri_angle_8, chowdsp::TrigApprox::cos_3angle_mpi_pi<8>, chowdsp::TrigApprox::cos_3angle<8>); +COS_BENCH (tri_angle_6, chowdsp::TrigApprox::cos_3angle_mpi_pi<6>, chowdsp::TrigApprox::cos_3angle<6>); +COS_BENCH (tri_angle_4, chowdsp::TrigApprox::cos_3angle_mpi_pi<4>, chowdsp::TrigApprox::cos_3angle<4>); #define SIN_COS_BENCH(name, op_mpi_pi, op_full_range) \ TRIG_BENCH ( \ diff --git a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h index afc588f3c..f7b7ce9b8 100644 --- a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h +++ b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h @@ -7,6 +7,7 @@ namespace chowdsp * * References: * - Sine plots: https://www.desmos.com/calculator/rnsmcx6wb5 + * - Cosine plots: https://www.desmos.com/calculator/tgt3dejrgr */ namespace TrigApprox { @@ -313,8 +314,6 @@ namespace TrigApprox /** * Combined sine/cosine approximation, using the triple-angle * approximations described above. - * - * Order should */ template auto sin_cos_3angle_mpi_pi (T x) @@ -337,7 +336,7 @@ namespace TrigApprox return std::make_tuple (s, c); } - /** Full-range triple-angle sine approximation. */ + /** Full-range triple-angle sine/cosine approximation. */ template auto sin_cos_3angle (T x) { From 2062403a528171cf34a1d979442c475365c1731c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 11 Oct 2023 00:50:28 +0000 Subject: [PATCH 09/10] Apply clang-format --- bench/TrigBench.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bench/TrigBench.cpp b/bench/TrigBench.cpp index 5ea213fe7..f93c1b843 100644 --- a/bench/TrigBench.cpp +++ b/bench/TrigBench.cpp @@ -82,8 +82,8 @@ const auto std_sin_cos = [] (float x) }; SIN_COS_BENCH (std, std_sin_cos, std_sin_cos); -SIN_COS_BENCH (tri_angle_7_8, (chowdsp::TrigApprox::sin_cos_3angle_mpi_pi<7, 8>), (chowdsp::TrigApprox::sin_cos_3angle<7, 8>)); -SIN_COS_BENCH (tri_angle_5_6, (chowdsp::TrigApprox::sin_cos_3angle_mpi_pi<5, 6>), (chowdsp::TrigApprox::sin_cos_3angle<5, 6>)); -SIN_COS_BENCH (tri_angle_3_4, (chowdsp::TrigApprox::sin_cos_3angle_mpi_pi<3, 4>), (chowdsp::TrigApprox::sin_cos_3angle<3, 4>)); +SIN_COS_BENCH (tri_angle_7_8, (chowdsp::TrigApprox::sin_cos_3angle_mpi_pi<7, 8>), (chowdsp::TrigApprox::sin_cos_3angle<7, 8>) ); +SIN_COS_BENCH (tri_angle_5_6, (chowdsp::TrigApprox::sin_cos_3angle_mpi_pi<5, 6>), (chowdsp::TrigApprox::sin_cos_3angle<5, 6>) ); +SIN_COS_BENCH (tri_angle_3_4, (chowdsp::TrigApprox::sin_cos_3angle_mpi_pi<3, 4>), (chowdsp::TrigApprox::sin_cos_3angle<3, 4>) ); BENCHMARK_MAIN(); From 228e919ecb801591a4982460ee0f4e8d00cabc37 Mon Sep 17 00:00:00 2001 From: jatin Date: Tue, 10 Oct 2023 17:57:43 -0700 Subject: [PATCH 10/10] Fixing no SIMD failure --- modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h index f7b7ce9b8..5b2497e9f 100644 --- a/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h +++ b/modules/dsp/chowdsp_math/Math/chowdsp_TrigApprox.h @@ -23,11 +23,13 @@ namespace TrigApprox return T ((int) x); } +#if ! CHOWDSP_NO_XSIMD template xsimd::batch truncate (xsimd::batch x) { return xsimd::to_float (xsimd::to_int (x)); } +#endif /** Fast method to wrap a value into the range [-pi, pi] */ template