Skip to content

Commit

Permalink
util: add float classify functions
Browse files Browse the repository at this point in the history
  • Loading branch information
riptl authored and ripatel-fd committed Jun 23, 2024
1 parent f75cfa9 commit b000894
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 1 deletion.
79 changes: 78 additions & 1 deletion src/util/bits/fd_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ FD_PROTOTYPES_BEGIN
fd_fltbits_unbias return the exponent for a biased exponent
fd_fltbits_bias return the biased exponent for an exponent
As these don't do any interpretation of the bits, these in principle
As these don't do any interpretation of the bits, above in principle
are just linguistic operations as opposed to an actual operation
(e.g. in FPGA synthesis, these amount to reinterpretation of the
meaning of some voltages on some wires). But because of the way
Expand All @@ -57,6 +57,19 @@ FD_PROTOTYPES_BEGIN
require some operations on the target (generally fast O(1)
operations).
The functions below do classification of IEEE-754 bit patterns as
described in the table at the start of the file. These functions
return stable results regardless of compiler flags and hardware
behavior. This means they may not behave the same as ISO C
fpclassify(3) and friends. For example, when compiling on Clang 18
with -ffast-math, 0==isnan(NAN). Whereas 1==fd_fltbits_is_nan( fd_fltbits( NAN ) ).
fd_fltbits_is_zero returns 1 if fltbits is a (signed) zero, else 0
fd_fltbits_is_denorm returns 1 if fltbits is a denorm number, else 0
fd_fltbits_is_inf returns 1 if fltbits is -inf or +inf, else 0
fd_fltbits_is_nan returns 1 if fltbits is a nan, else 0
fd_fltbits_is_normal returns 0 if fltbits is a zero, a denorm, -inf, +inf, or nan; else 1
The APIs below use ulong for bit fields in general (even in cases
where 32-bit might be sufficient) to avoid unnecessary assembly ops
under the hood. */
Expand Down Expand Up @@ -91,6 +104,38 @@ fd_float( ulong u ) { /* 32-bit */
return tmp.f[0];
}

FD_FN_CONST static inline int
fd_fltbits_is_zero( ulong u ) {
return ( fd_fltbits_bexp( u )==0 ) &
( fd_fltbits_mant( u )==0 );
}

FD_FN_CONST static inline int
fd_fltbits_is_denorm( ulong u ) {
return ( fd_fltbits_bexp( u )==0 ) &
( fd_fltbits_mant( u )!=0 );
}

FD_FN_CONST static inline int
fd_fltbits_is_inf( ulong u ) {
return ( fd_fltbits_bexp( u )==255 ) &
( fd_fltbits_mant( u )== 0 );
}

FD_FN_CONST static inline int
fd_fltbits_is_nan( ulong u ) {
return ( fd_fltbits_bexp( u )==255 ) &
( fd_fltbits_mant( u )!= 0 );
}

FD_FN_CONST static inline int
fd_fltbits_is_normal( ulong u ) {
return ( !fd_fltbits_is_zero ( u ) ) &
( !fd_fltbits_is_denorm( u ) ) &
( !fd_fltbits_is_inf ( u ) ) &
( !fd_fltbits_is_nan ( u ) );
}

#if FD_HAS_DOUBLE /* These are 64-bit / double precision counterparts to the above */

FD_FN_CONST static inline ulong
Expand Down Expand Up @@ -121,6 +166,38 @@ fd_double( ulong u ) {
return tmp.d[0];
}

FD_FN_CONST static inline int
fd_dblbits_is_zero( ulong u ) {
return ( fd_dblbits_bexp( u )==0 ) &
( fd_dblbits_mant( u )==0 );
}

FD_FN_CONST static inline int
fd_dblbits_is_denorm( ulong u ) {
return ( fd_dblbits_bexp( u )==0 ) &
( fd_dblbits_mant( u )!=0 );
}

FD_FN_CONST static inline int
fd_dblbits_is_inf( ulong u ) {
return ( fd_dblbits_bexp( u )==2047 ) &
( fd_dblbits_mant( u )== 0 );
}

FD_FN_CONST static inline int
fd_dblbits_is_nan( ulong u ) {
return ( fd_dblbits_bexp( u )==2047 ) &
( fd_dblbits_mant( u )!= 0 );
}

FD_FN_CONST static inline int
fd_dblbits_is_normal( ulong u ) {
return ( !fd_dblbits_is_zero ( u ) ) &
( !fd_dblbits_is_denorm( u ) ) &
( !fd_dblbits_is_inf ( u ) ) &
( !fd_dblbits_is_nan ( u ) );
}

#endif

FD_PROTOTYPES_END
Expand Down
42 changes: 42 additions & 0 deletions src/util/bits/test_float.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,48 @@ main( int argc,
# undef _
# endif

FD_TEST( fd_fltbits_is_zero( fd_fltbits_pack( 0UL, 0UL, 0UL ) )==1 );
FD_TEST( fd_fltbits_is_zero( fd_fltbits_pack( 1UL, 0UL, 0UL ) )==1 );
FD_TEST( fd_fltbits_is_inf ( fd_fltbits_pack( 0UL, 255UL, 0UL ) )==1 );
FD_TEST( fd_fltbits_is_inf ( fd_fltbits_pack( 1UL, 255UL, 0UL ) )==1 );
FD_TEST( fd_fltbits_is_nan ( fd_fltbits_pack( 0UL, 255UL, 1UL ) )==1 );
FD_TEST( fd_fltbits_is_nan ( fd_fltbits_pack( 1UL, 255UL, 1UL ) )==1 );

for( ulong mant=1UL; mant < (1UL<<23); mant+=(1UL<<10) ) {
for( ulong sign=0UL; sign < (1UL<<1); sign++ ) {
FD_TEST( fd_fltbits_is_denorm( fd_fltbits_pack( sign, 0UL, mant ) )==1 );
FD_TEST( fd_fltbits_is_nan ( fd_fltbits_pack( sign, 0UL, mant ) )==0 );
FD_TEST( fd_fltbits_is_denorm( fd_fltbits_pack( sign, 255UL, mant ) )==0 );
FD_TEST( fd_fltbits_is_nan ( fd_fltbits_pack( sign, 255UL, mant ) )==1 );
for( ulong bexp=0UL; bexp < (1UL<<8); bexp++ ) {
FD_TEST( fd_fltbits_is_zero( fd_fltbits_pack( sign, bexp, mant ) )==0 );
FD_TEST( fd_fltbits_is_inf ( fd_fltbits_pack( sign, bexp, mant ) )==0 );
}
}
}

# if FD_HAS_DOUBLE
FD_TEST( fd_dblbits_is_zero( fd_dblbits_pack( 0UL, 0UL, 0UL ) )==1 );
FD_TEST( fd_dblbits_is_zero( fd_dblbits_pack( 1UL, 0UL, 0UL ) )==1 );
FD_TEST( fd_dblbits_is_inf ( fd_dblbits_pack( 0UL, 2047UL, 0UL ) )==1 );
FD_TEST( fd_dblbits_is_inf ( fd_dblbits_pack( 1UL, 2047UL, 0UL ) )==1 );
FD_TEST( fd_dblbits_is_nan ( fd_dblbits_pack( 0UL, 2047UL, 1UL ) )==1 );
FD_TEST( fd_dblbits_is_nan ( fd_dblbits_pack( 1UL, 2047UL, 1UL ) )==1 );

for( ulong mant=1UL; mant < (1UL<<52); mant+=(1UL<<39) ) {
for( ulong sign=0UL; sign < (1UL<<1); sign++ ) {
FD_TEST( fd_dblbits_is_denorm( fd_dblbits_pack( sign, 0UL, mant ) )==1 );
FD_TEST( fd_dblbits_is_nan ( fd_dblbits_pack( sign, 0UL, mant ) )==0 );
FD_TEST( fd_dblbits_is_denorm( fd_dblbits_pack( sign, 2047UL, mant ) )==0 );
FD_TEST( fd_dblbits_is_nan ( fd_dblbits_pack( sign, 2047UL, mant ) )==1 );
for( ulong bexp=0UL; bexp < (1UL<<8); bexp++ ) {
FD_TEST( fd_dblbits_is_zero( fd_dblbits_pack( sign, bexp, mant ) )==0 );
FD_TEST( fd_dblbits_is_inf ( fd_dblbits_pack( sign, bexp, mant ) )==0 );
}
}
}
# endif

FD_LOG_NOTICE(( "pass" ));
fd_halt();
return 0;
Expand Down

0 comments on commit b000894

Please sign in to comment.