16#if defined(__APPLE__) && defined(__clang__)
23#if defined(__clang__) && defined(__has_builtin)
24#if __has_builtin(__builtin_elementwise_maximum) && __has_builtin(__builtin_elementwise_minimum)
25#define PULP_FAST_MATH_HAS_IEEE_MINMAX 1
28#ifndef PULP_FAST_MATH_HAS_IEEE_MINMAX
29#define PULP_FAST_MATH_HAS_IEEE_MINMAX 0
101 template <FastTrigProfile Profile>
104 constexpr float two_pi = 6.28318530717958647692f;
105 return std::sin(two_pi * phase_cycles);
107 float x = phase_cycles;
114 const float x2 = x * x;
117 return x * (6.28250560008354834003487064338056964f +
118 x2 * (-41.1664423308903732524414077000881397f +
119 74.4524187069072428211419543641796188f * x2));
129 (precise_c3 + precise_c4 * x2))));
146#if defined(__APPLE__) && defined(__clang__)
151 static simd_float4 sin_cycles_precise(simd_float4 phase_cycles)
noexcept {
152 simd_float4 x = phase_cycles - ::simd::floor(phase_cycles + 0.5f);
153 const simd_float4 magnitude = ::simd::abs(x);
154 x = ::simd::copysign(::simd::min(magnitude, 0.5f - magnitude), x);
155 const simd_float4 x2 = x * x;
163 (precise_c3 + precise_c4 * x2))));
196 constexpr float kScale = 1.0f - 0x1p-21f;
197 constexpr float a0 = 0.9997622141279201f * kScale;
198 constexpr float a1 = 0.10092608875679396f * kScale;
199 constexpr float a2 = 0.0006321601824242231f * kScale;
200 constexpr float b1 = 0.4335808440239807f;
201 constexpr float b2 = 0.01240458813388444f;
202 const float t =
c *
c;
203 return c * (a0 + t * (a1 + t * a2)) / (1.0f + t * (b1 + t * b2));
212#if PULP_FAST_MATH_HAS_IEEE_MINMAX
213 return __builtin_elementwise_minimum(__builtin_elementwise_maximum(x, -
kTanhClamp),
245 const float u = std::fmin(x * x, 81.0f);
250 const float upper = r > 1.0f ? 1.0f : r;
251 return upper < -1.0f ? -1.0f : upper;
258 const float u2 =
u *
u;
261 const float p = (1.0f +
u * 0.133803148f) +
262 u2 * ((0.00349475497f +
u * 2.05960245e-05f) + u2 * 1.33379685e-08f);
263 const float q = (1.0f +
u * 0.467136322f) +
264 u2 * ((0.0258737793f +
u * 0.000328429886f) + u2 * 7.7694232e-07f);
317 static void tanh_minimax(
const float* input,
float* output, std::size_t count)
noexcept {
319#if defined(__clang__) || defined(__GNUC__)
320 using Lanes =
float __attribute__((vector_size(16)));
321 constexpr std::size_t kVectors = 4;
322 constexpr std::size_t kStep = kVectors * 4;
323 for (;
i + kStep <= count;
i += kStep) {
325 std::memcpy(v, input +
i,
sizeof v);
326 for (
auto& lane : v) {
327#if defined(__clang__)
328 const Lanes
c = __builtin_elementwise_min(
334 const Lanes floored = lane < lo ? lo : lane;
335 const Lanes
c = floored > hi ? hi : floored;
339 std::memcpy(output +
i, v,
sizeof v);
342 for (;
i < count; ++
i)
351 constexpr float kScale = 1.0f - 0x1p-21f;
353 const T num = x * (kScale + t * (1.2183626499918065e-01f * kScale +
354 t * (2.1714800492144003e-03f * kScale +
355 t * (3.4510574788349538e-06f * kScale))));
356 const T den = 1.0f + t * (4.5515217250939749e-01f +
357 t * (2.0577605545641264e-02f + t * 1.3105688057792639e-04f));
384 constexpr float kScale = 1.0f - 0x1p-21f;
385 constexpr float n1 = 1.2183626499918065e-01f * kScale;
386 constexpr float n2 = 2.1714800492144003e-03f * kScale;
387 constexpr float n3 = 3.4510574788349538e-06f * kScale;
388 constexpr float d1 = 4.5515217250939749e-01f;
389 constexpr float d2 = 2.0577605545641264e-02f;
390 constexpr float d3 = 1.3105688057792639e-04f;
391 const float t = x * x;
392 const float t2 = t * t;
393 const float num = x * ((kScale + t * n1) + t2 * (n2 + t * n3));
394 const float den = (1.0f + t * d1) + t2 * (d2 + t * d3);
402 static float sin(
float x) {
403 constexpr float pi = 3.14159265f;
404 constexpr float two_pi = 6.28318530f;
406 x = std::fmod(x, two_pi);
407 if (x < 0) x += two_pi;
409 if (x > pi) x -= two_pi;
411 constexpr float B = 4.0f / pi;
412 constexpr float C = -4.0f / (pi * pi);
413 float y = B * x + C * x * std::abs(x);
415 y = 0.225f * (y * std::abs(y) - y) + y;
420 static float cos(
float x) {
421 return sin(x + 1.5707963f);
443 std::memcpy(&bits, &x,
sizeof(bits));
444 int32_t exponent =
static_cast<int32_t
>((bits >> 23) & 0xFF) - 127;
445 bits = (bits & 0x007FFFFF) | 0x3F800000;
447 std::memcpy(&m, &bits,
sizeof(m));
449 float result =
static_cast<float>(exponent);
451 result += m * (1.4423904f + m * (-0.7210953f + m * 0.4778948f));
456 static float pow(
float base,
float exp) {
457 if (base <= 0)
return 0;
463 return exp2(db * 0.16609640f);
468 if (gain <= 0)
return -200.0f;
469 return log2(gain) * 6.0205999f;
489 constexpr std::uint32_t kSqrtHalfBits = 0x3f3504f3u;
490 const std::uint32_t offset = std::bit_cast<std::uint32_t>(x) - kSqrtHalfBits;
491 const float k =
static_cast<float>(
static_cast<std::int32_t
>(offset) >> 23);
492 const float m = std::bit_cast<float>((offset & 0x007fffffu) + kSqrtHalfBits);
493 const float f = m - 1.0f;
494 const float s = f / (2.0f + f);
495 const float z = s * s;
497 z * (1.0f / 3.0f + z * (1.0f / 5.0f + z * (1.0f / 7.0f + z * (1.0f / 9.0f))));
498 const float two_s = 2.0f * s;
499 const float ln_m = two_s * series + two_s;
502 constexpr float kLog10TwoHi = 0.30102539062f;
503 constexpr float kLog10TwoLo = 4.6050390e-06f;
504 constexpr float kInvLn10 = 0.43429448190f;
505 return k * kLog10TwoHi + (ln_m * kInvLn10 + k * kLog10TwoLo);
522 constexpr float kLog2Ten = 3.32192809489f;
523 constexpr float kLog10TwoHi = 0.30102539062f;
524 constexpr float kLog10TwoLo = 4.6050390e-06f;
525 constexpr float kLnTen = 2.30258509299f;
529 const float xc = std::fmin(std::fmax(x, -75.0f), 75.0f);
530 const float n = std::nearbyint(xc * kLog2Ten);
531 const float d = (xc - n * kLog10TwoHi) - n * kLog10TwoLo;
532 const float t = d * kLnTen;
535 t * (1.0f + t * (0.5f + t * (1.0f / 6.0f +
538 t * (1.0f / 720.0f + t * (1.0f / 5040.0f)))))));
539 const std::int32_t
e =
static_cast<std::int32_t
>(n);
540 const std::int32_t e_half =
e / 2;
541 const float scale_a = std::bit_cast<float>(
static_cast<std::uint32_t
>(e_half + 127) << 23);
542 const float scale_b =
543 std::bit_cast<float>(
static_cast<std::uint32_t
>(
e - e_half + 127) << 23);
544 const float result = (p * scale_a) * scale_b;
545 return x == x ? result : x;
560 static float rcp(
float x) {
562 float estimate = 1.0f / x;
570 std::memcpy(&
i, &x,
sizeof(
i));
571 i = 0x5f3759df - (
i >> 1);
573 std::memcpy(&y, &
i,
sizeof(y));
574 y = y * (1.5f - 0.5f * x * y * y);
579 static constexpr float precise_c0 =
580 6.28318527379078585274731929079414949f;
581 static constexpr float precise_c1 =
582 -41.3416774783915252855640244027643612f;
583 static constexpr float precise_c2 =
584 81.6022312427274226421465134076212909f;
585 static constexpr float precise_c3 =
586 -76.5749921819992128192000934020817094f;
587 static constexpr float precise_c4 =
588 39.7109181438058471453004860893416233f;
594 return std::max(-1.0f, std::min(1.0f, x));
599 if (x <= -1.5f)
return -1.0f;
600 if (x >= 1.5f)
return 1.0f;
601 return x - (x * x * x) / 6.75f;
644#if defined(PULP_SIGNAL_LADDER_SATURATION)
645static_assert(PULP_SIGNAL_LADDER_SATURATION == 0 || PULP_SIGNAL_LADDER_SATURATION == 1 ||
646 PULP_SIGNAL_LADDER_SATURATION == 2,
647 "PULP_SIGNAL_LADDER_SATURATION must be 0 (exact), 1 (accurate) or "
648 "2 (realtime_efficient)");
653#elif defined(PULP_SIGNAL_FAST_LADDER_TANH)
666template <auto Saturation>
679template <auto RealtimeEfficient>
680 requires std::is_same_v<
decltype(RealtimeEfficient),
bool>
681[[deprecated(
"use ladder_tanh_profiled<LadderSaturation>")]]
711 const double x = std::clamp(v, -3.0, 3.0);
712 const double x2 = x * x;
713 return x * (27.0 + x2) / (27.0 + 9.0 * x2);
724template <
typename T>
inline T
select_bits(
bool condition, T if_true, T if_false)
noexcept {
725 static_assert(
sizeof(T) == 4 ||
sizeof(T) == 8);
726 using U = std::conditional_t<
sizeof(T) == 4, std::uint32_t, std::uint64_t>;
727 const U mask = U{0} -
static_cast<U
>(condition);
728 return std::bit_cast<T>((std::bit_cast<U>(if_true) & mask) |
729 (std::bit_cast<U>(if_false) & ~mask));
734#if PULP_DSP_ENABLE_SNAP_TO_ZERO
744 const float u = std::fmin(x * x, 81.0f);
746 const float upper =
select_bits(r > 1.0f, 1.0f, r);
T select_bits(bool condition, T if_true, T if_false) noexcept
condition ?
Definition fast_math.hpp:724
float tanh_accurate_bits(float x) noexcept
FastMath::tanh_accurate() with its clamps as bit operations; the same value for every input.
Definition fast_math.hpp:743
T snap_to_zero_bits(T x) noexcept
snap_to_zero() as bit operations (see select_bits()).
Definition fast_math.hpp:733
Definition additive_bank.hpp:218
constexpr T snap_threshold()
Threshold in absolute value below which a sample is treated as zero.
Definition denormal.hpp:36
double lipschitz_tanh(double v) noexcept
A [3/2] Padé tanh that is 1-LIPSCHITZ and bounded — the saturator to reach for inside a feedback loop...
Definition fast_math.hpp:710
float ladder_tanh(float x)
The ladder's default float saturator.
Definition fast_math.hpp:688
@ c
Definition spectrum_trace.hpp:35
FastTrigProfile
Semantic accuracy choices for bounded-cycle real-time trigonometry.
Definition fast_math.hpp:38
@ realtime_efficient
Lower-cost float path with maximum absolute error at most 1.2e-4 over one bounded cycle.
Definition fast_math.hpp:43
@ reference
Platform sine; the compatibility default.
Definition fast_math.hpp:40
@ realtime_precise
Float-precision path with maximum absolute error at most 2.5e-7 over one bounded cycle.
Definition fast_math.hpp:46
@ u
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
@ e
Definition formant_filter_bank.hpp:20
LadderSaturation
Saturator choices for the Moog ladder's per-stage non-linearity.
Definition fast_math.hpp:630
@ exact
Definition fast_math.hpp:630
@ accurate
Definition fast_math.hpp:630
@ realtime_efficient
Definition fast_math.hpp:630
constexpr LadderSaturation kDefaultLadderSaturation
Selecting the default ladder saturator at build time:
Definition fast_math.hpp:657
float ladder_tanh_profiled(float x)
The ladder's float saturator for an explicit choice.
Definition fast_math.hpp:668
Math helpers optimized for audio DSP.
Definition fast_math.hpp:88
static float tanh_minimax(float x)
Constrained-minimax [7/6] rational tanh: two more coefficients per polynomial than tanh()'s [5/4],...
Definition fast_math.hpp:296
static float rsqrt(float x)
Fast inverse square root (1/sqrt(x)).
Definition fast_math.hpp:567
static constexpr float kTanhMinimaxClamp
Definition fast_math.hpp:398
static float gain_to_db(float gain)
Fast linear gain to dB: 20 * log10(gain) = 20 * log2(gain) / log2(10).
Definition fast_math.hpp:467
static float tanh_minimax_recursive(float x) noexcept
tanh_minimax() for a serial recursion: the same fit, clamp and numerator scale, with each cubic evalu...
Definition fast_math.hpp:379
static float log10_accurate(float x) noexcept
log10(x) for finite, positive, normal x, within 4 ulps of the correctly rounded result (3....
Definition fast_math.hpp:488
static float pow(float base, float exp)
Fast pow(base, exp) via exp2(exp * log2(base)).
Definition fast_math.hpp:456
static constexpr float kTanhClamp
tanh() clamps its argument to [-kTanhClamp, kTanhClamp], where its rational reaches 1.
Definition fast_math.hpp:208
static float rcp(float x)
Fast reciprocal (1/x) via Newton-Raphson with SSE hint.
Definition fast_math.hpp:560
static float tanh_accurate_rational(float x, float u)
The unsaturated rational inside tanh_accurate(): x * P(u) / Q(u) with u = min(x^2,...
Definition fast_math.hpp:257
static float soft_clip(float x)
Soft clipping (polynomial saturation, no discontinuity).
Definition fast_math.hpp:598
static float cos(float x)
Fast cos approximation. Input in radians.
Definition fast_math.hpp:420
static float sin_cycles(float phase_cycles) noexcept
Computes sine for a normalized phase in [0, 1).
Definition fast_math.hpp:102
static float clamp_unit(float x)
Clamp to [-1, 1] without branching (for saturation).
Definition fast_math.hpp:593
static float tanh_accurate(float x)
tanh within 3.0e-7 absolute of std::tanh when the compiler fuses multiply-adds, and within 3....
Definition fast_math.hpp:242
static float db_to_gain_accurate(float db) noexcept
10^(dB / 20), within exp10_accurate()'s bound.
Definition fast_math.hpp:555
static float log2(float x)
Fast log2 approximation (max error ~0.007 for x > 0).
Definition fast_math.hpp:440
static float tanh(float x)
Fast tanh: an odd [5/4] rational, within 5.7e-5 of std::tanh for every float input,...
Definition fast_math.hpp:194
static float sin_cycles(float phase_cycles, FastTrigProfile profile) noexcept
Runtime profile dispatch for setup, control, and non-inner-loop use.
Definition fast_math.hpp:135
static float tanh_clamp(float x) noexcept
tanh()'s argument clamp, propagating NaN.
Definition fast_math.hpp:211
static float db_to_gain(float db)
Fast dB to linear gain: 10^(dB/20) = 2^(dB * log2(10)/20).
Definition fast_math.hpp:462
static T tanh_minimax_rational(T x) noexcept
The rational inside tanh_minimax() for an argument already clamped to [-7, 7], generic over float and...
Definition fast_math.hpp:350
static void tanh_minimax(const float *input, float *output, std::size_t count) noexcept
Block form of tanh_minimax(); output may equal input.
Definition fast_math.hpp:317
static float sin(float x)
Fast sin approximation (Bhaskara-style, max error ~0.001 for any x).
Definition fast_math.hpp:402
static float exp10_accurate(float x) noexcept
10^x within 1.2e-7 relative of the correctly rounded result, with or without fused multiply-add.
Definition fast_math.hpp:521
static float gain_to_db_accurate(float gain) noexcept
20 log10(gain) for a finite, positive, normal gain (clamp to a floor first); within log10_accurate()'...
Definition fast_math.hpp:550
static float exp2(float x)
Computes 2^x with the platform's standard float exp2 semantics.
Definition fast_math.hpp:435