C What happens when casting floating point types to unsigned integer types when the value would overflow

本秂侑毒 提交于 2019-12-20 03:18:17

问题


I'm wondering what happens when casting from a floating point type to an unsigned integer type in C when the value can't be accurately represented by the integer type in question. Take for instance

func (void)
{
float a = 1E10;
unsigned b = a;
}

The value of b I get on my system (with unsigned on my system being able to represent values from 0 to 2^32-1) is 1410065408. This seems sensible to me because it's simply the lowest order bits of the result of the cast.

I believe the behavior of operations such as these is undefined by the standard. Am I wrong? What can I expect in practice if I do things like this?

Also, what happens with signed types? If b is of type int, I get -2147483648, which doesn't really make sense to me.


回答1:


What happens when casting floating point types to unsigned integer types when the value would overflow (?)

undefined behavior (UB)


In addition @user694733 fine answer, to prevent undefined behavior caused by out of range float to unsigned code can first test the float value.

Yet testing for the range is tricky, for unsigned types and especially for signed types. The detail is that all conversions and constants prior to the integer conversion must be exact. FP math near the limits needs to be exact too.

Examples:

Conversion to a 32-bit unsigned is valid for the range -0.999... to 4294967295.999....

Conversion to a 32-bit 2's complement signed is valid for the range -2147483648.999... to 2147483647.999....


// code uses FP constants that are exact powers-of-2 to insure their exact encoding.

// Form a FP constant that is exactly UINT_MAX + 1
#define FLT_UINT_MAX_P1 ((UINT_MAX/2 + 1)*2.0f)

bool convert_float_to_unsigned(unsigned *u, float f) {
  if (f > -1.0f && f < FLT_UINT_MAX_P1) {
    *u = (unsigned) f;
    return true;
  }
  return false;  // out of range
}


#define FLT_INT_MAX_P1 ((INT_MAX/2 + 1)*2.0f)
bool convert_float_to_int(int *i, float f) {
  #if INT_MIN == -INT_MAX
  // Rare non 2's complement integer
  if (fabsf(f) < FLT_INT_MAX_P1) {
    *i = (int) f;
    return true;
  }
  #else
  // Do not use f + 1 > INT_MIN as it may incur rounding
  // Do not use f > INT_MIN - 1.0f as it may incur rounding
  // f - INT_MIN is expected to be exact for values near the limit
  if (f - INT_MIN > -1 && f < FLT_INT_MAX_P1) {
    *i = (int) f;
    return true;
  }
  #endif 
  return false;  // out of range
}

Pedantic code would take additional steps to cope with the rare FLT_RADIX 10.

FLT_EVAL_METHOD, which allows for float math be calculated at higher precision, may play a role, yet so far I do not see it negatively affecting the above solution.




回答2:


In both cases value is out of range, so it's undefined behaviour.

6.3.1.4 Real floating and integer

  1. When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined. 61)

61) The remaindering operation performed when a value of integer type is converted to unsigned type need not be performed when a value of real floating type is converted to unsigned type. Thus, the range of portable real floating values is (−1, Utype_MAX+1).

To make this well defined code, you should check that value is within possible range before doing the conversion.



来源:https://stackoverflow.com/questions/46928840/c-what-happens-when-casting-floating-point-types-to-unsigned-integer-types-when

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!