28String getTemplatedMathsFunctionUnitTestName (
const String& functionName)
30 const auto getTypeName = []() -> String
32 if constexpr (std::is_same_v<int, T>)
35 if constexpr (std::is_same_v<float, T>)
38 if constexpr (std::is_same_v<double, T>)
41 if constexpr (std::is_same_v<long double, T>)
45 return functionName +
"<" + getTypeName() +
">";
49class ApproximatelyEqualTests final :
public UnitTest
52 ApproximatelyEqualTests()
53 :
UnitTest { getTemplatedMathsFunctionUnitTestName<T> (
"approximatelyEqual"), UnitTestCategories::maths }
58 using limits = std::numeric_limits<T>;
60 constexpr auto zero = T{};
61 constexpr auto one = T (1);
62 constexpr auto min = limits::min();
63 constexpr auto max = limits::max();
64 constexpr auto epsilon = limits::epsilon();
65 constexpr auto oneThird = one / (T) 3;
67 beginTest (
"Equal values are always equal");
69 expect (approximatelyEqual (zero, zero));
70 expect (approximatelyEqual (zero, -zero));
71 expect (approximatelyEqual (-zero, -zero));
73 expect (approximatelyEqual (min, min));
74 expect (approximatelyEqual (-min, -min));
76 expect (approximatelyEqual (one, one));
77 expect (approximatelyEqual (-one, -one));
79 expect (approximatelyEqual (max, max));
80 expect (approximatelyEqual (-max, -max));
82 const Tolerance<T> zeroTolerance{};
84 expect (approximatelyEqual (zero, zero, zeroTolerance));
85 expect (approximatelyEqual (zero, -zero, zeroTolerance));
86 expect (approximatelyEqual (-zero, -zero, zeroTolerance));
88 expect (approximatelyEqual (min, min, zeroTolerance));
89 expect (approximatelyEqual (-min, -min, zeroTolerance));
91 expect (approximatelyEqual (one, one, zeroTolerance));
92 expect (approximatelyEqual (-one, -one, zeroTolerance));
94 expect (approximatelyEqual (max, max, zeroTolerance));
95 expect (approximatelyEqual (-max, -max, zeroTolerance));
98 beginTest (
"Comparing subnormal values to zero, returns true");
100 expect (! exactlyEqual (zero, nextFloatUp (zero)));
101 expect (approximatelyEqual (zero, nextFloatUp (zero)));
103 expect (! exactlyEqual (zero, nextFloatDown (zero)));
104 expect (approximatelyEqual (zero, nextFloatDown (zero)));
106 expect (! exactlyEqual (zero, nextFloatDown (min)));
107 expect (approximatelyEqual (zero, nextFloatDown (min)));
109 expect (! exactlyEqual (zero, nextFloatUp (-min)));
110 expect (approximatelyEqual (zero, nextFloatUp (-min)));
113 beginTest (
"Comparing the minimum normal value to zero, returns true");
115 expect (approximatelyEqual (zero, min));
116 expect (approximatelyEqual (zero, -min));
119 beginTest (
"Comparing normal values greater than the minimum to zero, returns true");
121 expect (! approximatelyEqual (zero, one));
122 expect (! approximatelyEqual (zero, epsilon));
123 expect (! approximatelyEqual (zero, nextFloatUp (min)));
124 expect (! approximatelyEqual (zero, nextFloatDown (-min)));
127 beginTest (
"Values with large ranges can be compared");
129 expect (! approximatelyEqual (zero, max));
130 expect ( approximatelyEqual (zero, max, absoluteTolerance (max)));
131 expect ( approximatelyEqual (zero, max, relativeTolerance (one)));
132 expect (! approximatelyEqual (-one, max));
133 expect (! approximatelyEqual (-max, max));
136 beginTest (
"Larger values have a boundary that is a factor of the epsilon");
138 for (
auto exponent = 0; exponent < 127; ++exponent)
140 const auto value = std::pow ((T) 2, (T) exponent);
141 const auto boundaryValue = value * (one + epsilon);
143 expect (juce_isfinite (value));
144 expect (juce_isfinite (boundaryValue));
146 expect ( approximatelyEqual (value, boundaryValue));
147 expect (! approximatelyEqual (value, nextFloatUp (boundaryValue)));
149 expect ( approximatelyEqual (-value, -boundaryValue));
150 expect (! approximatelyEqual (-value, nextFloatDown (-boundaryValue)));
154 beginTest (
"Tolerances scale with the values being compared");
157 expect (approximatelyEqual ((T) 100'000'000'000'000.01,
158 (T) 100'000'000'000'000.011));
160 expect (! approximatelyEqual ((T) 100.01,
163 expect (! approximatelyEqual ((T) 123'000, (T) 121'000, relativeTolerance ((T) 1e-2)));
164 expect ( approximatelyEqual ((T) 123'000, (T) 122'000, relativeTolerance ((T) 1e-2)));
165 expect ( approximatelyEqual ((T) 123'000, (T) 123'000, relativeTolerance ((T) 1e-2)));
166 expect ( approximatelyEqual ((T) 123'000, (T) 124'000, relativeTolerance ((T) 1e-2)));
167 expect (! approximatelyEqual ((T) 123'000, (T) 125'000, relativeTolerance ((T) 1e-2)));
169 expect (! approximatelyEqual ((T) 123, (T) 121, relativeTolerance ((T) 1e-2)));
170 expect ( approximatelyEqual ((T) 123, (T) 122, relativeTolerance ((T) 1e-2)));
171 expect ( approximatelyEqual ((T) 123, (T) 123, relativeTolerance ((T) 1e-2)));
172 expect ( approximatelyEqual ((T) 123, (T) 124, relativeTolerance ((T) 1e-2)));
173 expect (! approximatelyEqual ((T) 123, (T) 125, relativeTolerance ((T) 1e-2)));
175 expect (! approximatelyEqual ((T) 12.3, (T) 12.1, relativeTolerance ((T) 1e-2)));
176 expect ( approximatelyEqual ((T) 12.3, (T) 12.2, relativeTolerance ((T) 1e-2)));
177 expect ( approximatelyEqual ((T) 12.3, (T) 12.3, relativeTolerance ((T) 1e-2)));
178 expect ( approximatelyEqual ((T) 12.3, (T) 12.4, relativeTolerance ((T) 1e-2)));
179 expect (! approximatelyEqual ((T) 12.3, (T) 12.5, relativeTolerance ((T) 1e-2)));
181 expect (! approximatelyEqual ((T) 1.23, (T) 1.21, relativeTolerance ((T) 1e-2)));
182 expect ( approximatelyEqual ((T) 1.23, (T) 1.22, relativeTolerance ((T) 1e-2)));
183 expect ( approximatelyEqual ((T) 1.23, (T) 1.23, relativeTolerance ((T) 1e-2)));
184 expect ( approximatelyEqual ((T) 1.23, (T) 1.24, relativeTolerance ((T) 1e-2)));
185 expect (! approximatelyEqual ((T) 1.23, (T) 1.25, relativeTolerance ((T) 1e-2)));
187 expect (! approximatelyEqual ((T) 0.123, (T) 0.121, relativeTolerance ((T) 1e-2)));
188 expect ( approximatelyEqual ((T) 0.123, (T) 0.122, relativeTolerance ((T) 1e-2)));
189 expect ( approximatelyEqual ((T) 0.123, (T) 0.123, relativeTolerance ((T) 1e-2)));
190 expect ( approximatelyEqual ((T) 0.123, (T) 0.124, relativeTolerance ((T) 1e-2)));
191 expect (! approximatelyEqual ((T) 0.123, (T) 0.125, relativeTolerance ((T) 1e-2)));
193 expect (! approximatelyEqual ((T) 0.000123, (T) 0.000121, relativeTolerance ((T) 1e-2)));
194 expect ( approximatelyEqual ((T) 0.000123, (T) 0.000122, relativeTolerance ((T) 1e-2)));
195 expect ( approximatelyEqual ((T) 0.000123, (T) 0.000123, relativeTolerance ((T) 1e-2)));
196 expect ( approximatelyEqual ((T) 0.000123, (T) 0.000124, relativeTolerance ((T) 1e-2)));
197 expect (! approximatelyEqual ((T) 0.000123, (T) 0.000125, relativeTolerance ((T) 1e-2)));
200 beginTest (
"The square of the square root of 2 is approximately 2");
202 constexpr auto two = (T) 2;
203 const auto sqrtOfTwo = std::sqrt (two);
205 expect (approximatelyEqual (sqrtOfTwo * sqrtOfTwo, two));
206 expect (approximatelyEqual (-sqrtOfTwo * sqrtOfTwo, -two));
207 expect (approximatelyEqual (two / sqrtOfTwo, sqrtOfTwo));
210 if constexpr (limits::has_quiet_NaN)
212 beginTest (
"Values are never equal to NaN");
214 const auto nan = limits::quiet_NaN();
216 expect (! approximatelyEqual (nan, nan));
218 const auto expectNotEqualTo = [&] (
auto value)
220 expect (! approximatelyEqual (value, nan));
221 expect (! approximatelyEqual (nan, value));
224 expectNotEqualTo (zero);
225 expectNotEqualTo (-zero);
226 expectNotEqualTo (min);
227 expectNotEqualTo (-min);
228 expectNotEqualTo (one);
229 expectNotEqualTo (-one);
230 expectNotEqualTo (max);
231 expectNotEqualTo (-max);
235 if constexpr (limits::has_infinity)
237 beginTest (
"Only infinity is equal to infinity");
239 const auto inf = limits::infinity();
240 expect (approximatelyEqual (inf, inf));
241 expect (approximatelyEqual (-inf, -inf));
242 expect (! approximatelyEqual (inf, -inf));
243 expect (! approximatelyEqual (-inf, inf));
245 const auto expectNotEqualTo = [&] (
auto value)
247 expect (! approximatelyEqual (value, inf));
248 expect (! approximatelyEqual (value, -inf));
249 expect (! approximatelyEqual (inf, value));
250 expect (! approximatelyEqual (-inf, value));
253 expectNotEqualTo (zero);
254 expectNotEqualTo (-zero);
255 expectNotEqualTo (min);
256 expectNotEqualTo (-min);
257 expectNotEqualTo (one);
258 expectNotEqualTo (-one);
259 expectNotEqualTo (max);
260 expectNotEqualTo (-max);
264 beginTest (
"Can set an absolute tolerance");
266 constexpr std::array<T, 7> negativePowersOfTwo
277 const auto testTolerance = [&] (
auto tolerance)
279 const auto t = Tolerance<T>{}.withAbsolute ((T) tolerance);
281 const auto testValue= [&] (
auto value)
283 const auto boundary = value + tolerance;
285 expect (approximatelyEqual (value, boundary, t));
286 expect (! approximatelyEqual (value, nextFloatUp (boundary), t));
288 expect (approximatelyEqual (-value, -boundary, t));
289 expect (! approximatelyEqual (-value, nextFloatDown (-boundary), t));
297 for (
const auto value : negativePowersOfTwo)
301 for (
const auto toleranceValue : negativePowersOfTwo)
302 testTolerance (toleranceValue);
305 beginTest (
"Can set a relative tolerance");
307 expect (! approximatelyEqual (oneThird, (T) 0.34, relativeTolerance ((T) 1e-2)));
308 expect ( approximatelyEqual (oneThird, (T) 0.334, relativeTolerance ((T) 1e-2)));
310 expect (! approximatelyEqual (oneThird, (T) 0.334, relativeTolerance ((T) 1e-3)));
311 expect ( approximatelyEqual (oneThird, (T) 0.3334, relativeTolerance ((T) 1e-3)));
313 expect (! approximatelyEqual (oneThird, (T) 0.3334, relativeTolerance ((T) 1e-4)));
314 expect ( approximatelyEqual (oneThird, (T) 0.33334, relativeTolerance ((T) 1e-4)));
316 expect (! approximatelyEqual (oneThird, (T) 0.33334, relativeTolerance ((T) 1e-5)));
317 expect ( approximatelyEqual (oneThird, (T) 0.333334, relativeTolerance ((T) 1e-5)));
319 expect (! approximatelyEqual (oneThird, (T) 0.333334, relativeTolerance ((T) 1e-6)));
320 expect ( approximatelyEqual (oneThird, (T) 0.3333334, relativeTolerance ((T) 1e-6)));
322 expect (! approximatelyEqual (oneThird, (T) 0.3333334, relativeTolerance ((T) 1e-7)));
323 expect ( approximatelyEqual (oneThird, (T) 0.33333334, relativeTolerance ((T) 1e-7)));
325 expect ( approximatelyEqual ((T) 1e6, (T) 1e6 + (T) 1, relativeTolerance ((T) 1e-6)));
326 expect (! approximatelyEqual ((T) 1e6, (T) 1e6 + (T) 1, relativeTolerance ((T) 1e-7)));
328 expect ( approximatelyEqual ((T) -1e-6, (T) -1.0000009e-6, relativeTolerance ((T) 1e-6)));
329 expect (! approximatelyEqual ((T) -1e-6, (T) -1.0000009e-6, relativeTolerance ((T) 1e-7)));
331 const auto a = (T) 1.234567;
332 const auto b = (T) 1.234568;
334 for (
auto exponent = 0; exponent < 39; ++exponent)
336 const auto m = std::pow ((T) 10, (T) exponent);
337 expect ( approximatelyEqual (a * m, b * m, relativeTolerance ((T) 1e-6)));
338 expect (! approximatelyEqual (a * m, b * m, relativeTolerance ((T) 1e-7)));
342 beginTest (
"A relative tolerance is always scaled by the maximum value");
344 expect ( approximatelyEqual ((T) 9, (T) 10, absoluteTolerance ((T) 10.0 * (T) 0.1)));
345 expect (! approximatelyEqual ((T) 9, (T) 10, absoluteTolerance ((T) 9.0 * (T) 0.1)));
347 expect (approximatelyEqual ((T) 9, (T) 10, relativeTolerance ((T) 0.1)));
348 expect (approximatelyEqual ((T) 10, (T) 9, relativeTolerance ((T) 0.1)));
355 expect (! approximatelyEqual (zero, std::sin (pi)));
356 expect ( approximatelyEqual (zero, std::sin (pi), absoluteTolerance (std::sin (pi))));
358 expect ( approximatelyEqual ((T) 100, (T) 95, relativeTolerance ((T) 0.05)));
359 expect (! approximatelyEqual ((T) 100, (T) 94, relativeTolerance ((T) 0.05)));
365class ApproximatelyEqualTests<int> final :
public UnitTest
368 ApproximatelyEqualTests()
369 :
UnitTest { getTemplatedMathsFunctionUnitTestName<int> (
"approximatelyEqual"), UnitTestCategories::maths }
374 beginTest (
"Identical integers are always equal");
376 expect (approximatelyEqual ( 0, 0));
377 expect (approximatelyEqual (-0, -0));
379 expect (approximatelyEqual ( 1, 1));
380 expect (approximatelyEqual (-1, -1));
382 using limits = std::numeric_limits<int>;
383 constexpr auto min = limits::min();
384 constexpr auto max = limits::max();
386 expect (approximatelyEqual (min, min));
387 expect (approximatelyEqual (max, max));
390 beginTest (
"Non-identical integers are never equal");
392 expect (! approximatelyEqual ( 0, 1));
393 expect (! approximatelyEqual ( 0, -1));
395 expect (! approximatelyEqual ( 1, 2));
396 expect (! approximatelyEqual (-1, -2));
398 using limits = std::numeric_limits<int>;
399 constexpr auto min = limits::min();
400 constexpr auto max = limits::max();
402 expect (! approximatelyEqual (min, min + 1));
403 expect (! approximatelyEqual (max, max - 1));
406 beginTest (
"Zero is equal regardless of the sign");
408 expect (approximatelyEqual ( 0, -0));
409 expect (approximatelyEqual (-0, 0));
415class IsFiniteTests final :
public UnitTest
419 :
UnitTest { getTemplatedMathsFunctionUnitTestName<T> (
"juce_isfinite"), UnitTestCategories::maths }
424 using limits = std::numeric_limits<T>;
426 constexpr auto zero = T{};
427 constexpr auto one = (T) 1;
428 constexpr auto max = limits::max();
429 constexpr auto inf = limits::infinity();
430 constexpr auto nan = limits::quiet_NaN();
434 expect (juce_isfinite (zero));
435 expect (juce_isfinite (-zero));
440 expect (juce_isfinite (nextFloatUp (zero)));
441 expect (juce_isfinite (nextFloatDown (zero)));
446 expect (juce_isfinite (one));
447 expect (juce_isfinite (-one));
452 expect (juce_isfinite (max));
453 expect (juce_isfinite (-max));
458 expect (! juce_isfinite (inf));
459 expect (! juce_isfinite (-inf));
464 expect (! juce_isfinite (nan));
465 expect (! juce_isfinite (-nan));
466 expect (! juce_isfinite (std::sqrt ((T) -1)));
467 expect (! juce_isfinite (inf * zero));
473class NextFloatTests final :
public UnitTest
477 :
UnitTest { getTemplatedMathsFunctionUnitTestName<T> (
"nextFloat"), UnitTestCategories::maths }
482 using limits = std::numeric_limits<T>;
484 constexpr auto zero = T{};
485 constexpr auto one = T (1);
486 constexpr auto min = limits::min();
487 constexpr auto epsilon = limits::epsilon();
489 beginTest (
"nextFloat from zero is subnormal");
491 expect (juce_isfinite (nextFloatUp (zero)));
492 expect (! exactlyEqual (zero, nextFloatUp (zero)));
493 expect (! std::isnormal (nextFloatUp (zero)));
495 expect (juce_isfinite (nextFloatDown (zero)));
496 expect (! exactlyEqual (zero, nextFloatDown (zero)));
497 expect (! std::isnormal (nextFloatDown (zero)));
500 beginTest (
"nextFloat from min, towards zero, is subnormal");
502 expect (std::isnormal (min));
503 expect (std::isnormal (-min));
504 expect (! std::isnormal (nextFloatDown (min)));
505 expect (! std::isnormal (nextFloatUp (-min)));
508 beginTest (
"nextFloat from one matches epsilon");
510 expect (! exactlyEqual (one, nextFloatUp (one)));
511 expect ( exactlyEqual (one + epsilon, nextFloatUp (one)));
513 expect (! exactlyEqual (-one, nextFloatDown (-one)));
514 expect ( exactlyEqual (-one - epsilon, nextFloatDown (-one)));
519template <
typename Type>
520struct MathsFloatingPointFunctionsTests
522 IsFiniteTests<Type> isFiniteTests;
523 NextFloatTests<Type> nextFloatTests;
524 ApproximatelyEqualTests<Type> approximatelyEqualTests;
528struct MathsFloatingPointFunctionsTests<int>
530 ApproximatelyEqualTests<int> approximatelyEqualTests;
533struct MathsFunctionsTests
535 MathsFloatingPointFunctionsTests<int> intFunctionTests;
536 MathsFloatingPointFunctionsTests<float> floatFunctionTests;
537 MathsFloatingPointFunctionsTests<double> doubleFunctionTests;
538 MathsFloatingPointFunctionsTests<long double> longDoubleFunctionTests;
541static MathsFunctionsTests mathsFunctionsTests;
UnitTest(const String &name, const String &category=String())
void beginTest(const String &testName)
void expect(bool testResult, const String &failureMessage=String())
static constexpr FloatType pi