LCOV - code coverage report
Current view: top level - util/bits - fd_float.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 68 80 85.0 %
Date: 2024-11-13 11:58:15 Functions: 45 4368 1.0 %

          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 */

Generated by: LCOV version 1.14