Line data Source code
1 : #ifndef HEADER_fd_src_util_math_fd_float_h 2 : #define HEADER_fd_src_util_math_fd_float_h 3 : 4 : #include "fd_bits.h" 5 : 6 : /* IEEE-754 crash course: 7 : 8 : "float" / single precision: 9 : 10 : biased unbiased 11 : sign exponent exponent mantissa 12 : 0 0 -127 0 -> zero / +0.f 13 : 1 0 -127 0 -> signed zero / -0.f 14 : s 0 -127 non-zero -> denorm / (-1)^s 2^-126 m/2^23 15 : 0 255 128 0 -> positive infinity / +inf 16 : 1 255 128 0 -> negative infinity / -inf 17 : s 255 128 ( 0,2^22) -> signaling nan / snan (bits 0:21 theoretically encode diagnostic conditions, 0 not allowed for bits 0:21 here) 18 : s 255 128 [2^22,2^23) -> quiet nan / qnan (", 0 allowed for bits 0:21 here) 19 : s b e==b-127 m -> normal / (-1)^s 2^e (1 + m/2^23) 20 : 21 : "double" / double precision 22 : 23 : biased unbiased 24 : sign exponent exponent mantissa 25 : 0 0 -1023 0 -> zero / +0. 26 : 1 0 -1023 0 -> signed zero / -0. 27 : s 0 -1023 non-zero -> denorm / (-1)^s 2^-1022 m/2^52 28 : 0 2047 1024 0 -> positive infinity / +inf 29 : 1 2047 1024 0 -> negative infinity / -inf 30 : s 2047 1024 ( 0,2^51) -> signaling nan / snan (bits 0:50 theoretically encode diagnostic conditions, 0 not allowed for bits 0:50 here) 31 : s 2047 1024 [2^51,2^52) -> quiet nan / qnan (", 0 allowed for bits 0:50 here) 32 : s b e==b-1023 m -> normal / (-1)^s 2^e (1 + m/2^52) 33 : 34 : Some architectures have a notion of a "canonical nan" (such that nan 35 : producing operations will not have the sign bit set and will always 36 : have the same diagnostic condition). */ 37 : 38 : FD_PROTOTYPES_BEGIN 39 : 40 : /* fd_float treats a 32-bit unsigned int to a float 41 : fd_fltbits treats a float as a 32-bit unsigned ints ("fltbits") 42 : fd_fltbits_sign extracts the sign from a fltbits 43 : fd_fltbits_biasedexponent extracts the biased exponents of a fltbits 44 : fd_fltbits_mantissa extracts the mantissa 45 : fd_fltbits_pack packs a sign, biased exponent and mantissa 46 : into a fltbits 47 : fd_fltbits_unbias return the exponent for a biased exponent 48 : fd_fltbits_bias return the biased exponent for an exponent 49 : 50 : As these don't do any interpretation of the bits, above in principle 51 : are just linguistic operations as opposed to an actual operation 52 : (e.g. in FPGA synthesis, these amount to reinterpretation of the 53 : meaning of some voltages on some wires). But because of the way 54 : languages and hardware dubiously treat floating point as a somehow 55 : weirdly different realm from the rest of the world (e.g. separate CPU 56 : register files for integers and floats under the hood), this might 57 : require some operations on the target (generally fast O(1) 58 : operations). 59 : 60 : The functions below do classification of IEEE-754 bit patterns as 61 : described in the table at the start of the file. These functions 62 : return stable results regardless of compiler flags and hardware 63 : behavior. This means they may not behave the same as ISO C 64 : fpclassify(3) and friends. For example, when compiling on Clang 18 65 : with -ffast-math, 0==isnan(NAN). Whereas 1==fd_fltbits_is_nan( fd_fltbits( NAN ) ). 66 : 67 : fd_fltbits_is_zero returns 1 if fltbits is a (signed) zero, else 0 68 : fd_fltbits_is_denorm returns 1 if fltbits is a denorm number, else 0 69 : fd_fltbits_is_inf returns 1 if fltbits is -inf or +inf, else 0 70 : fd_fltbits_is_nan returns 1 if fltbits is a nan, else 0 71 : fd_fltbits_is_normal returns 0 if fltbits is a zero, a denorm, -inf, +inf, or nan; else 1 72 : 73 : The APIs below use ulong for bit fields in general (even in cases 74 : where 32-bit might be sufficient) to avoid unnecessary assembly ops 75 : under the hood. */ 76 : 77 : /* FIXME: CHECK X86 CODE QUALITY / USE SSE HACK */ 78 : 79 : FD_FN_CONST static inline ulong /* 32-bit */ 80 30 : fd_fltbits( float f ) { 81 30 : union { uint u[1]; float f[1]; } tmp; 82 30 : tmp.f[0] = f; 83 30 : return (ulong)tmp.u[0]; 84 30 : } 85 : 86 30 : FD_FN_CONST static inline ulong /* 1-bit */ fd_fltbits_sign( ulong u /* 32-bit */ ) { return u >> 31; } 87 25362480 : FD_FN_CONST static inline ulong /* 8-bit */ fd_fltbits_bexp( ulong u /* 32-bit */ ) { return (u >> 23) & 255UL; } 88 25362480 : FD_FN_CONST static inline ulong /* 23-bit */ fd_fltbits_mant( ulong u /* 32-bit */ ) { return u & 8388607UL; } 89 : 90 30 : FD_FN_CONST static inline long /* [-127,128] */ fd_fltbits_unbias( ulong b /* 8-bit */ ) { return ((long)b)-127L; } 91 30 : FD_FN_CONST static inline ulong /* 8-bit */ fd_fltbits_bias ( long e /* [-127,128] */ ) { return (ulong)(e+127L); } 92 : 93 : FD_FN_CONST static inline ulong /* 32-bit */ 94 : fd_fltbits_pack( ulong s, /* 1-bit */ 95 : ulong b, /* 8-bit */ 96 12681264 : ulong m ) { /* 23-bit */ 97 12681264 : return (s << 31) | (b << 23) | m; 98 12681264 : } 99 : 100 : FD_FN_CONST static inline float 101 30 : fd_float( ulong u ) { /* 32-bit */ 102 30 : union { uint u[1]; float f[1]; } tmp; 103 30 : tmp.u[0] = (uint)u; 104 30 : return tmp.f[0]; 105 30 : } 106 : 107 : FD_FN_CONST static inline int 108 12582918 : fd_fltbits_is_zero( ulong u ) { 109 12582918 : return ( fd_fltbits_bexp( u )==0 ) & 110 12582918 : ( fd_fltbits_mant( u )==0 ); 111 12582918 : } 112 : 113 : FD_FN_CONST static inline int 114 98304 : fd_fltbits_is_denorm( ulong u ) { 115 98304 : return ( fd_fltbits_bexp( u )==0 ) & 116 98304 : ( fd_fltbits_mant( u )!=0 ); 117 98304 : } 118 : 119 : FD_FN_CONST static inline int 120 12582918 : fd_fltbits_is_inf( ulong u ) { 121 12582918 : return ( fd_fltbits_bexp( u )==255 ) & 122 12582918 : ( fd_fltbits_mant( u )== 0 ); 123 12582918 : } 124 : 125 : FD_FN_CONST static inline int 126 98310 : fd_fltbits_is_nan( ulong u ) { 127 98310 : return ( fd_fltbits_bexp( u )==255 ) & 128 98310 : ( fd_fltbits_mant( u )!= 0 ); 129 98310 : } 130 : 131 : FD_FN_CONST static inline int 132 0 : fd_fltbits_is_normal( ulong u ) { 133 0 : return ( !fd_fltbits_is_zero ( u ) ) & 134 0 : ( !fd_fltbits_is_denorm( u ) ) & 135 0 : ( !fd_fltbits_is_inf ( u ) ) & 136 0 : ( !fd_fltbits_is_nan ( u ) ); 137 0 : } 138 : 139 : #if FD_HAS_DOUBLE /* These are 64-bit / double precision counterparts to the above */ 140 : 141 : FD_FN_CONST static inline ulong 142 1045002 : fd_dblbits( double f ) { 143 1045002 : union { ulong u[1]; double f[1]; } tmp; 144 1045002 : tmp.f[0] = f; 145 1045002 : return tmp.u[0]; 146 1045002 : } 147 : 148 936207 : FD_FN_CONST static inline ulong /* 1-bit */ fd_dblbits_sign( ulong u ) { return u >> 63; } 149 26407452 : FD_FN_CONST static inline ulong /* 11-bit */ fd_dblbits_bexp( ulong u ) { return (u >> 52) & 2047UL; } 150 25471275 : FD_FN_CONST static inline ulong /* 52-bit */ fd_dblbits_mant( ulong u ) { return u & 4503599627370495UL; } 151 : 152 30 : FD_FN_CONST static inline long /* [-1023,1024] */ fd_dblbits_unbias( ulong b /* 11-bit */ ) { return ((long)b)-1023L; } 153 30 : FD_FN_CONST static inline ulong /* 11-bit */ fd_dblbits_bias ( long e /* [-1023,1024] */ ) { return (ulong)(e+1023L); } 154 : 155 : FD_FN_CONST static inline ulong 156 : fd_dblbits_pack( ulong s, /* 1-bit */ 157 : ulong b, /* 11-bit */ 158 12681273 : ulong m ) { /* 52-bit */ 159 12681273 : return (s << 63) | (b << 52) | m; 160 12681273 : } 161 : 162 : FD_FN_CONST static inline double 163 39 : fd_double( ulong u ) { 164 39 : union { ulong u[1]; double d[1]; } tmp; 165 39 : tmp.u[0] = u; 166 39 : return tmp.d[0]; 167 39 : } 168 : 169 : FD_FN_CONST static inline int 170 12582918 : fd_dblbits_is_zero( ulong u ) { 171 12582918 : return ( fd_dblbits_bexp( u )==0 ) & 172 12582918 : ( fd_dblbits_mant( u )==0 ); 173 12582918 : } 174 : 175 : FD_FN_CONST static inline int 176 98304 : fd_dblbits_is_denorm( ulong u ) { 177 98304 : return ( fd_dblbits_bexp( u )==0 ) & 178 98304 : ( fd_dblbits_mant( u )!=0 ); 179 98304 : } 180 : 181 : FD_FN_CONST static inline int 182 12582918 : fd_dblbits_is_inf( ulong u ) { 183 12582918 : return ( fd_dblbits_bexp( u )==2047 ) & 184 12582918 : ( fd_dblbits_mant( u )== 0 ); 185 12582918 : } 186 : 187 : FD_FN_CONST static inline int 188 98310 : fd_dblbits_is_nan( ulong u ) { 189 98310 : return ( fd_dblbits_bexp( u )==2047 ) & 190 98310 : ( fd_dblbits_mant( u )!= 0 ); 191 98310 : } 192 : 193 : FD_FN_CONST static inline int 194 0 : fd_dblbits_is_normal( ulong u ) { 195 0 : return ( !fd_dblbits_is_zero ( u ) ) & 196 0 : ( !fd_dblbits_is_denorm( u ) ) & 197 0 : ( !fd_dblbits_is_inf ( u ) ) & 198 0 : ( !fd_dblbits_is_nan ( u ) ); 199 0 : } 200 : 201 : #endif 202 : 203 : FD_PROTOTYPES_END 204 : 205 : #endif /* HEADER_fd_src_util_math_fd_float_h */