当值溢出时将浮点类型转换为无符号整数类型会发生什么?
What happens when casting floating point types to unsigned integer types when the value would overflow?
我想知道在 C 中从浮点类型转换为无符号整数类型时会发生什么情况,因为所讨论的整数类型无法准确表示值。以
为例
func (void)
{
float a = 1E10;
unsigned b = a;
}
我得到的b
的值在我的系统上(unsigned
在我的系统上能够表示从0到232-1的值) 是 1410065408
。这对我来说似乎很明智,因为它只是转换结果的最低位。
我相信标准未定义此类操作的行为。我错了吗?如果我这样做,在实践中我能期待什么?
此外,签名类型会怎样?如果 b
是 int
类型,我会得到 -2147483648
,这对我来说没有意义。
在这两种情况下,值都超出范围,因此是未定义的行为。
6.3.1.4 Real floating and integer
- 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).
为了制作这个定义明确的代码,您应该在进行转换之前检查该值是否在可能的范围内。
What happens when casting floating point types to unsigned integer types when the value would overflow (?)
未定义的行为 (UB)
另外很好回答,防止未定义行为超出范围float
到unsigned
代码可以先测试一下float
值。
然而,对于无符号类型,尤其是有符号类型,范围测试很棘手。细节是整数转换之前的所有转换和常量必须精确。接近极限的 FP 数学也需要精确。
示例:
转换为 32 位无符号有效范围为 -0.999... 到 4294967295.999....
转换为带符号的 32 位 2 的补码的有效范围为 -2147483648.999... 到 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
}
迂腐的代码将采取额外的步骤来应对罕见的 FLT_RADIX 10
。
FLT_EVAL_METHOD
,允许以更高的精度计算 float
数学,可能会发挥作用,但到目前为止我没有看到它对上述解决方案产生负面影响。
我想知道在 C 中从浮点类型转换为无符号整数类型时会发生什么情况,因为所讨论的整数类型无法准确表示值。以
为例func (void)
{
float a = 1E10;
unsigned b = a;
}
我得到的b
的值在我的系统上(unsigned
在我的系统上能够表示从0到232-1的值) 是 1410065408
。这对我来说似乎很明智,因为它只是转换结果的最低位。
我相信标准未定义此类操作的行为。我错了吗?如果我这样做,在实践中我能期待什么?
此外,签名类型会怎样?如果 b
是 int
类型,我会得到 -2147483648
,这对我来说没有意义。
在这两种情况下,值都超出范围,因此是未定义的行为。
6.3.1.4 Real floating and integer
- 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).
为了制作这个定义明确的代码,您应该在进行转换之前检查该值是否在可能的范围内。
What happens when casting floating point types to unsigned integer types when the value would overflow (?)
未定义的行为 (UB)
另外float
到unsigned
代码可以先测试一下float
值。
然而,对于无符号类型,尤其是有符号类型,范围测试很棘手。细节是整数转换之前的所有转换和常量必须精确。接近极限的 FP 数学也需要精确。
示例:
转换为 32 位无符号有效范围为 -0.999... 到 4294967295.999....
转换为带符号的 32 位 2 的补码的有效范围为 -2147483648.999... 到 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
}
迂腐的代码将采取额外的步骤来应对罕见的 FLT_RADIX 10
。
FLT_EVAL_METHOD
,允许以更高的精度计算 float
数学,可能会发挥作用,但到目前为止我没有看到它对上述解决方案产生负面影响。