Check if float can be represented as an integral type

How to check whether it can floatbe represented as an integer type without causing undefined behavior by a simple cast? This is prohibited in § 4.9.1:

A floating point type value can be converted to a prvalue integer type. The conversion truncates; that is, the fractional part is discarded. Undefined behavior, if the truncated value cannot be represented in the destination type,

Here, the question for C, but the accepted answer clearly is undefined behavior (at first a simple injection, and later - with the help of breaking union, which makes it all very doubtful to me).

I see how difficult it would be to have a fully compatible solution, but one that is an implementation (assuming IEEE-754 floats) would also be acceptable.

+4
source share
3 answers

Check it out truncf(x) == x. (Function is in <math.h>). This will compare true if and only if x has no fractional part. Then compare x with the type range.

Sample code (untested)

#include <cfenv>
#include <cmath>
#pragma STDC FENV_ACCESS on

template<class F, class N> // F is a float type, N integral.
  bool is_representable(const F x)
{
  const int orig_rounding = std::fegetround();

  std::fesetround(FE_TOWARDZERO);
  const bool to_return = std::trunc(x) == x &&
                         x >= std::numeric_limits<N>.min() &&
                         x <= std::numeric_limits<N>.max();
  std::fesetround(orig_rounding);
  return to_return;
}

When rounding to zero, the implicit conversion of the minimum and maximum values ​​of an integral type to a floating-point type should not overflow. On many architectures, including the i386, casting to will long doublealso provide sufficient precision to accurately represent a 64-bit int.

0
source

%a snprintf(), , , , . .

0

1 MAX_FLOAT. IEEE 754 2 ( ). IEE-754 1 , 8 23 . . - 1/2, 1/4, 1/8...

1 1.999... . (1) 1

2 3.999... . (2,3) 2 . 3 , -. . 2 3 .

4 7.999... . (4, 6, 7) 4 , 2 . , .

8 15.999... . 8 (8,9,10,11,12,13,14,15) 3 . , .

Hopefully you will see a picture when the exponent increases, the number of possible integers doubles. Therefore, ignore the n bits of the highest mantissa and check if the least significant bits are set. If they are then this number is not an integer.

These tables indicate the value of the constant 0x40 plus the next most significant bit, and that only integer bits of the high order mantissa are given for integers

Float    Hex
4        0x40800000
5        0x40a00000
6        0x40c00000
7        0x40e00000

To convert float to UInt32

float x  = 7.0;
UInt32 * px = (UInt32*)&x;
UInt32    i = *px;
0
source

Source: https://habr.com/ru/post/1609206/


All Articles