FastLED 3.10.6
Loading...
Searching...
No Matches
AutoResearchMathExp.cpp
Go to the documentation of this file.
1
4#if FL_PLATFORM_HAS_LARGE_MEMORY
5
7#include "fl/math/math.h"
8#include "fl/stl/bit_cast.h"
9#include "fl/stl/int.h"
10#include <Arduino.h> // micros()
11#include <math.h> // ok include - libm is the reference this bench measures against
12
13namespace autoresearch {
14namespace math_exp {
15namespace {
16
17float ulp_of(float v) {
18 const fl::u32 bits = fl::bit_cast<fl::u32>(v < 0 ? -v : v);
19 return fl::bit_cast<float>(bits + 1u) - fl::bit_cast<float>(bits);
20}
21
22double ulp_of(double v) {
23 const fl::u64 bits = fl::bit_cast<fl::u64>(v < 0 ? -v : v);
24 return fl::bit_cast<double>(bits + 1ull) - fl::bit_cast<double>(bits);
25}
26
27typedef float (*ExpFn)(float);
28
29fl::u32 time_us(ExpFn fn, const float* in, fl::u32 iterations, float* sink) {
30 float acc = 0.0f;
31 const fl::u32 t0 = micros();
32 for (fl::u32 i = 0; i < iterations; ++i) {
33 acc += fn(in[i & 255u]);
34 }
35 const fl::u32 t1 = micros();
36 *sink += acc;
37 return t1 - t0;
38}
39
40float call_fl_expf(float x) { return fl::expf(x); }
41float call_libm_expf(float x) { return ::expf(x); }
42float call_fl_exp(float x) { return static_cast<float>(fl::exp(static_cast<double>(x))); }
43float call_libm_exp(float x) { return static_cast<float>(::exp(static_cast<double>(x))); }
44
45} // namespace
46
47Result run(fl::u32 iterations) {
48 Result r = {};
49 r.iterations = iterations;
50 r.large_memory = FL_PLATFORM_HAS_LARGE_MEMORY ? 1 : 0;
51
52 // Accuracy: the finite float range in 0.05 steps and the double range in
53 // 0.5 steps, against libm.
54 fl::u32 points = 0;
55 for (float x = -103.9f; x < 88.7f; x += 0.05f) {
56 const float want = ::expf(x);
57 const float got = fl::expf(x);
58 if (want <= 0.0f || want != want || want > 3.0e38f) {
59 continue;
60 }
61 const float d = (got > want ? got - want : want - got) / ulp_of(want);
62 if (d > r.worst_ulp_float) {
63 r.worst_ulp_float = d;
64 r.worst_x_float = x;
65 }
66 ++points;
67 }
68 for (double x = -745.0; x < 709.7; x += 0.5) {
69 const double want = ::exp(x);
70 const double got = fl::exp(x);
71 if (want <= 0.0 || want != want) {
72 continue;
73 }
74 const double d = (got > want ? got - want : want - got) / ulp_of(want);
75 if (d > r.worst_ulp_double) {
76 r.worst_ulp_double = d;
77 r.worst_x_double = x;
78 }
79 ++points;
80 }
81 r.accuracy_points = points;
82
83 // Speed: inputs over |x| <= 10, the constant-Q / Gaussian-window range.
84 static float inputs[256];
85 for (int i = 0; i < 256; ++i) {
86 inputs[i] = -10.0f + 20.0f * static_cast<float>(i) / 255.0f;
87 }
88 float sink = 0.0f;
89 r.fl_expf_us = time_us(&call_fl_expf, inputs, iterations, &sink);
90 r.libm_expf_us = time_us(&call_libm_expf, inputs, iterations, &sink);
91 r.fl_exp_us = time_us(&call_fl_exp, inputs, iterations, &sink);
92 r.libm_exp_us = time_us(&call_libm_exp, inputs, iterations, &sink);
93 r.sink = sink;
94
95 r.success = r.worst_ulp_float <= 2.0f && r.worst_ulp_double <= 2.0 && points > 0;
96 return r;
97}
98
99} // namespace math_exp
100} // namespace autoresearch
101
102#endif // FL_PLATFORM_HAS_LARGE_MEMORY
int x
Definition simple.h:92
On-device accuracy and speed of fl::exp against the toolchain libm (#4288).
Result run(fl::u32 iterations)
Runs the accuracy sweep and the timed loops. iterations = calls per loop.
fl::u32 micros()
Universal microsecond timer - returns microseconds since system startup.
To bit_cast(const From &from) FL_NO_EXCEPT
Definition bit_cast.h:48
enable_if< is_fixed_point< T >::value, T >::type exp(T x) FL_NO_EXCEPT
float expf(float value) FL_NO_EXCEPT
Definition math.h:398
#define FL_PLATFORM_HAS_LARGE_MEMORY