Branch data Line data Source code
1 : : // Copyright 2019-2024 David Robillard <d@drobilla.net> 2 : : // SPDX-License-Identifier: ISC 3 : : 4 : : #ifndef EXESS_TEST_FLOAT_TEST_UTILS_H 5 : : #define EXESS_TEST_FLOAT_TEST_UTILS_H 6 : : 7 : : #include "../src/ieee_float.h" 8 : : #include "../src/warnings.h" 9 : : 10 : : #include <assert.h> 11 : : #include <math.h> 12 : : #include <stdbool.h> 13 : : #include <stdint.h> 14 : : #include <string.h> 15 : : 16 : : /// Return the float with representation `rep` 17 : : static inline float 18 : 513 : float_from_rep(const uint32_t rep) 19 : : { 20 : 513 : float f = 0.0f; 21 : 513 : memcpy(&f, &rep, sizeof(f)); 22 : 513 : return f; 23 : : } 24 : : 25 : : /// Return a somewhat evenly distributed float from a random integer 26 : : static inline float 27 : 4096 : random_float(const uint32_t state) 28 : : { 29 : 4096 : return ldexpf((float)(state & 0xFFFF0000U), (int)(state % 256U) - 128); 30 : : } 31 : : 32 : : /// Return the distance between two floats in ULPs 33 : : static uint32_t 34 : 12856 : float_ulp_distance(const float a, const float b) 35 : : { 36 : : EXESS_DISABLE_CONVERSION_WARNINGS 37 [ - + ]: 12856 : assert(!isnan(a)); 38 [ - + ]: 12856 : assert(!isnan(b)); 39 : : EXESS_RESTORE_WARNINGS 40 : : 41 [ - + ]: 12856 : assert(a >= 0.0f); 42 [ - + ]: 12856 : assert(b >= 0.0f); 43 : : 44 : 12856 : const uint32_t ia = float_to_rep(a); 45 : 12856 : const uint32_t ib = float_to_rep(b); 46 : : 47 [ + - ]: 12856 : return ia >= ib ? ia - ib : ib - ia; 48 : : } 49 : : 50 : : static bool 51 : 12870 : float_matches(const float a, const float b) 52 : : { 53 : : EXESS_DISABLE_CONVERSION_WARNINGS 54 : 12870 : const bool a_is_nan = isnan(a); 55 : 12870 : const bool a_is_negative = signbit(a); 56 : 12870 : const bool b_is_nan = isnan(b); 57 : 12870 : const bool b_is_negative = signbit(b); 58 : : EXESS_RESTORE_WARNINGS 59 : : 60 [ + + - + : 38582 : return (a_is_nan && b_is_nan) || + + ] 61 [ + - + - : 25712 : (!a_is_nan && !b_is_nan && a_is_negative == b_is_negative && + - + - + - ] 62 : 16 : (a_is_negative ? float_ulp_distance(-a, -b) == 0 63 : 12840 : : float_ulp_distance(a, b) == 0)); 64 : : } 65 : : 66 : : #endif // EXESS_TEST_FLOAT_TEST_UTILS_H