LCOV - code coverage report
Current view: top level - flamenco/types - fd_cast.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 20 25 80.0 %
Date: 2026-05-19 08:05:42 Functions: 3 382 0.8 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_types_fd_cast_h
       2             : #define HEADER_fd_src_flamenco_types_fd_cast_h
       3             : 
       4             : #include "../../util/bits/fd_float.h"
       5             : 
       6             : /* From https://doc.rust-lang.org/rust-by-example/types/cast.html
       7             : 
       8             :    Since Rust 1.45, the `as` keyword performs a *saturating cast*
       9             :    when casting from float to int. If the floating point value exceeds
      10             :    the upper bound or is less than the lower bound, the returned value
      11             :    will be equal to the bound crossed. */
      12             : 
      13             : FD_PROTOTYPES_BEGIN
      14             : 
      15             : #if FD_HAS_DOUBLE
      16             : 
      17             : /* Cast a double to unsigned long with identical behaviour to Rust's
      18             :    saturating "as" case.
      19             :    Saturate to 0 if the value is negative or NaN.
      20             :    Saturate to ULONG_MAX if the value is greater than ULONG_MAX. */
      21             : FD_FN_CONST static inline ulong
      22       39711 : fd_rust_cast_double_to_ulong( double f ) {
      23       39711 :   ulong u = fd_dblbits( f );
      24             : 
      25             :   /* NaN saturates to 0. */
      26       39711 :   if( FD_UNLIKELY( fd_dblbits_bexp( u )==0x7FFUL && fd_dblbits_mant( u )!=0 ) ) {
      27           3 :     return 0;
      28           3 :   }
      29             : 
      30             :   /* Negative values (including -Inf and -0.0) saturate to 0. */
      31       39708 :   if( FD_UNLIKELY( fd_dblbits_sign( u )==1 ) ) {
      32           6 :     return 0;
      33           6 :   }
      34             : 
      35             :   /* +Inf or values >= 2^64 saturate to ULONG_MAX.
      36             :       A positive double has value 1.mant * 2^(bexp-1023).
      37             :       When bexp >= 1087 (exponent >= 64), the value is >= 2^64
      38             :       and cannot fit in a ulong. bexp=0x7FF (+Inf) also caught here
      39             :       but NaN was already handled above. */
      40       39702 :   ulong bexp = fd_dblbits_bexp( u );
      41       39702 :   if( FD_UNLIKELY( bexp>=1087UL ) ) {
      42           9 :     return ULONG_MAX;
      43           9 :   }
      44             : 
      45             :   /* Subnormals (bexp==0) have value < 1.0 and truncate to 0. */
      46       39693 :   if( FD_UNLIKELY( bexp==0UL ) ) {
      47           0 :     return 0;
      48           0 :   }
      49             : 
      50             :   /* Normal value in [0, 2^64), is safe to convert.
      51             : 
      52             :      value = (1 << 52 | mantissa) >> (52 - (bexp - 1023))
      53             :      when bexp-1023 > 52, shift left instead
      54             :      bexp is within [1, 1086], so exponent = bexp-1023 is within [-1022, 63]
      55             :      shift = 52 - exponent is within [-11, 1074]
      56             :      For shift >= 64, result is 0 (very small positive numbers). */
      57       39693 :   ulong mant = fd_dblbits_mant( u ) | (1UL << 52);
      58       39693 :   int  shift = 52 - (int)( bexp-1023UL );
      59             : 
      60       39693 :   if( shift >= 64 ) {
      61           0 :     return 0;
      62       39693 :   } else if( shift>=0 ) {
      63       39693 :     return mant >> shift;
      64       39693 :   } else {
      65           0 :     return mant << (-shift);
      66           0 :   }
      67       39693 : }
      68             : 
      69             : #endif /* FD_HAS_DOUBLE */
      70             : 
      71             : FD_PROTOTYPES_END
      72             : 
      73             : #endif /* HEADER_fd_src_flamenco_types_fd_cast_h */

Generated by: LCOV version 1.14