Suppose I is some integer type and F some (real) floating point type.
I want to write two functions. The first function shall take a value i of type I and return a boolean indicating whether i converted to F falls into the representable range, i.e. whether (F)i will have defined behavior.
The second function shall take a value f of type F and return a boolean indicating whether f converted to I falls into the representable range, i.e. whether (I)f will have defined behavior.
Is it possible to write such a function that will be, on every implementation conforming to the standard, correct and not exhibit undefined behavior for any input? In particular I do not want to assume that the floating point types are IEEE 754 types.
I am asking about both C and C++ and their respective standard versions separately, in case that changes the answer.
Basically the intention of this question is to figure out whether (sensible) floating-point / integral conversions are possible without relying on IEEE 754 or other standards or hardware details at all. I ask out of curiosity.
Comparing against e.g. INT_MAX or FLT_MAX does not seem to be possible, because it is not clear which type to do the comparison in without already knowing which of the types has wider range.
some float to some int is fairly easy is we can assume FLT_RADIX != 10 (2N floating point) and the range of FP exceeds the integer range.
Form exact FP limits
Test if FP has a fraction part that is 0**. (also handles NaN, inf)
Test if too positive.
Test if too negative.
Test if converted to integer value rounds.
Pseudo code
// For now, assume 2's complement.
// With some extra macro magic, could handle all integer encodings.
// Use integer limits whose magnitudes are at or 1 away from a power-of-2
// and form FP power-of-2 limits
// The following will certainly not incur any rounding
#define FLT_INT_MAXP1 ((INT_MAX/2 + 1)*2.0f)
#define FLT_INT_MIN (INT_MIN*1.0f)
status float_to_int_test(float f) {
float ipart;
if (modff(f, &ipart) != 0.0) {
return not_a_whole_number;
}
if (f >= FLT_INT_MAXP1) return too_big;
if (f < FLT_INT_MIN) return too_negative;
if (f != (volatile float) f)) return rounding_occurred;
return success;
}
Armed with the above float_to_int test....
status int_to_float_test(int i) {
volatile float f = (float) i;
if (float_to_int_test(f) != success) return fail
volatile int j = (int) f;
if (i != j) return fail;
return success;
}
Simplifications possible, but something to get OP started.
Extreme cases which need additional code include int128_t or wider having more range than float and FLT_RADIX == 10.
** Hmmm - appears OP does not cares about fractional part. In that case conversion from double to int appears as a good duplicate for half the problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With