1
  • code
#include <iostream>

int main() {
    int  num = 2147483647;
    std::cout << (int)(float)num << std::endl; 

    return 0;
}
  • output
./main
-2147483648
-2147483648

I know that a float to int conversion is safe, but an int to float conversion is not. I also know that real floating point cannot be expressed accurately. It seems very dangerous to see overflows even though the maximum value(except inf) of int is not exceeded.

I want to be safe when converting int to float or float to int no matter what arbitrary number comes in.

Which way is best to handle it? Also, what other exceptions should I consider?


The above question isn't clear and doesn't fit the stackoverflow question, so I'll fix it specifically.

Numbers in normal categories like 2147483647 also overflow. What range should I handle?

hochan
  • 220
  • 3
  • 10
  • There are several different ways this is typically done, from explicitly doing bounds checking to doing exactly this: converting both ways and seeing if what you get back is what you started with. However it's a matter of opinion as "which way is best to handle it", so this wouldn't be an appropriate question for Stackoverflow. – Sam Varshavchik Jan 22 '21 at 13:31
  • Let's change the question to be a little specific. – hochan Jan 22 '21 at 13:32
  • Numbers in normal categories like 2147483647 also overflow. What range should I handle? – hochan Jan 22 '21 at 13:32
  • If I put the following it should work fine. ```int num = 1000;``` The main reason I asked here is that the actual 2147483647 is in the range of int. – hochan Jan 22 '21 at 13:34
  • 3
    "What range should I handle?" whatever is needed to get the correct answer in the computation you are performing. –  Jan 22 '21 at 13:35
  • Interestingly, if you turn on optimizations (`-O3` for example), you are likely getting the original value back. [Demo](https://godbolt.org/z/sj7Ydq) – Ted Lyngmo Jan 22 '21 at 13:35
  • cant reproduce https://ideone.com/zbDfJy – ΦXocę 웃 Пepeúpa ツ Jan 22 '21 at 13:39
  • Of course, the larger the computer bit system, the more accurate it will be. But what I'm asking is within the usual 32-bit or 64-bit we currently use. As many people are still using it, I think the setting of this range is inevitable. Additionally, I would like to leave some specific code rather than an option. – hochan Jan 22 '21 at 13:41
  • @ΦXocę웃Пepeúpaツ Look at my demo. It's entirely reproducible. – Ted Lyngmo Jan 22 '21 at 13:41
  • ```cant reproduce ideone.com/zbDfJy``` The reason is that it is an undefined behavior. Different actual compilers may behave differently. – hochan Jan 22 '21 at 13:42
  • @hochan Yes, that's the reason indeed. – Ted Lyngmo Jan 22 '21 at 13:43
  • 3
    An IEEE 754 `float` has 24-bits of precision (23 actual bits plus 1 implied most significant bit). Have a routine that ensures the `int` is equal-to-or-between `-16777216 .. +16777216` and you're golden. (A `float` on your system may have different characteristics.) – Eljay Jan 22 '21 at 14:00
  • I understood it correctly. Thank you. Come to think of it, I don't seem to realize the main point because I think the int range is less than the float. Actually, I have to consider the precision of float, but I think my thoughts were short. It seems to be a very bad question to see after gaining understanding now. I also understood exactly why @dratenik said it (+@Eljay ```(A float on your system may have different characteristics.)``` ). I fully agree with your opinion. It seems that it is correct to do a larger unit or individual treatment than the way I think it is. – hochan Jan 22 '21 at 14:50
  • Thank you all for thinking about it together. (How do I handle the completion of question resolution?) – hochan Jan 22 '21 at 14:50
  • "I know that a float to int conversion is safe, but an int to float conversion is not." Do you mean this the other way around? Also, for converting `float` to `int` what behavior do you want? Just saturate everything outside the range of `int` to its min/max value? What about infinities or NaNs? – chtz Jan 22 '21 at 14:56
  • First, The reason I mentioned "I know that~" earlier is that even if a float stores an actual int, there is a slight difference due to the error from the floating point. So I don't think it's safe to convert from int to float in the opposite sense. Second, Also, my consideration ranges were between x ~ 2147483647 in actual positive numbers. As chtz said, 2147483648 and above have INF treatment. So is the negative number. – hochan Jan 22 '21 at 15:20
  • The numbers in the following ranges are not guaranteed to be the original number by converting from int to float and then to int. – hochan Jan 22 '21 at 15:26
  • Your title asks about C, but the question is tagged C++ and shows C++ code. Did you mean for the title to ask about C++? – Eric Postpischil Jan 22 '21 at 15:32
  • @ Eric Postpischil I fully agree with your opinion. This question seems to be more suitable for c than c++. I fixed the tag to c. Additionally, the same result is produced even if cast with ```std::cout << static_cast(static_cast(num)) << std::endl;```. – hochan Jan 22 '21 at 15:41
  • 1
    @hochan: I did not express an opinion; I asked a question. We need to know the language you are asking about. Answers sometimes differ based on the language, and, if the answer includes code to demonstrate, it depends on the language. – Eric Postpischil Jan 22 '21 at 15:43
  • Detecting whether a floating-point value may be converted to an integer type safely is addressed [here](https://stackoverflow.com/questions/51304323/reliable-overflow-detection-of-floating-point-integer-type-conversion) for C++ and [here](https://stackoverflow.com/questions/51104995/can-a-conversion-from-double-to-int-be-written-in-portable-c/51107035#51107035) for C. – Eric Postpischil Jan 22 '21 at 15:44
  • 1
    For conversion of some positive integer x to floating-point, if the floating-point radix is 2, then x fits in the significand of the floating-point format iff `x/(x & - (uintmax_t) x) >> D` is zero, where `D` is the number of bits in the significand (`std::numeric_limits::digits` in C++, `FLT_MANT_DIG` and similar in C). Then there are only exponent range issues to consider, as well as generalization to negative and zero values. – Eric Postpischil Jan 22 '21 at 15:50
  • Sorry for being late reading the text you gave. I haven't read it all, but this is the answer I want. I wanted c++ and generalization. It seems to be a good way to consider. Thank you for the reply. – hochan Jan 22 '21 at 16:03

1 Answers1

3

I know that a float to int conversion is safe, but an int to float conversion is not.

Each conversion has issues.

(Assume 32-bit int and 32-bit float for discussion.)

Large int to float risks lost of precision as float does not exactly encode all int. With OP's int num = 2147483647; (float)num, the 2147483647 was converted to 1 of 2 nearby float. With round to the nearest rounding mode, float: result was certainly 2147483648.0.

float to int truncates any fraction. Conversion from infinity and Not-a-number pose addition concerns.

float to int risks implementation-defined behavior when the the floating point value is not inside the -2,147,483,648.9999... 2,147,483,647.9999... range. This is the case with OP's int num = 2147483647; (int)(float)num attempting to convert an out of range 2147483648.0 to int. In OP's case, the value was apparently wrapped around (232 subtracted) to end with -2147483648.


Which way is best to handle it? Also, what other exceptions should I consider?

With conversion int to float, expect rounding for large int.

With conversion float to int, expect truncation and perhaps test if value is in range.

With 2's complement integer encoding: a test to prevent out of range conversion.

#define FLT_INT_MAX_PLUS1 ((INT_MAX/2 + 1)*2.0f)

// return true when OK to convert 
bool float_to_int_test(float x) {
  return (x < FLT_INT_MAX_PLUS1) && (x - INT_MIN > -1.0f);
}

Other tests could be had to determine rounding or truncation.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • That's a good point. Thank you for telling me. Obviously, converting from int to float also has percision issues. I think my example wasn't good. In fact, the first time I asked the question, discussed in the comments: I was trying to ask that a problem can occur even within the range of an int. For example, in the case of positive numbers, there is always a potential for problems with 16777216 – hochan Jan 23 '21 at 10:16
  • 1
    @hochan "there is always a potential for problems with 16777216 No. The non-precision issue occurs when `x` is very near `INT_MAX`. When `x > 0x7fffff80 (2147483520)`, depending on rounding mode, the resulting `float` may be 2147483648.0f, which is one beyond `INT_MAX`. The precision issues can occur when x > 0x0100_0000 (16777216). – chux - Reinstate Monica Jan 23 '21 at 21:06
  • I thought it was the same reason, but the two were completely different problems. I'll do more personal experiments to gain understanding. Thanks for the additional explanation. – hochan Jan 24 '21 at 06:23