我想知道在C中从浮点类型转换为无符号整数类型时会发生什么情况,而这个值无法用相关的整数类型准确表示。举个例子
func (void)
{
float a = 1E10;
unsigned b = a;
}
我在我的系统上b
的值(我的系统上的unsigned
能够表示0到2 ^ 32-1之间的值)是1410065408
。这对我来说似乎是明智的,因为它只是演员结果的最低位。
我认为这些操作的行为未被标准定义。我错了吗?如果我做这样的事情,我在实践中可以期待什么?
此外,签名类型会发生什么?如果b
的类型为int
,我会收到-2147483648
,这对我来说并不合理。
答案 0 :(得分:2)
在这两种情况下,值都超出范围,因此它的行为未定义。
6.3.1.4实数浮点数和整数
- 当实际浮动类型的有限值转换为
醇>_Bool
以外的整数类型时, 丢弃小数部分(即,该值被截断为零)。如果值 整数部分不能用整数类型表示,行为是未定义的。 61)61)当整数类型的值转换为无符号类型时执行的剩余操作 当实际浮动类型的值转换为无符号类型时,不需要执行。就这样 便携式实数浮点值的范围是(-1,U 类型 _MAX + 1)。
要制作这个定义良好的代码,您应该在进行转换之前检查该值是否在可能的范围内。
答案 1 :(得分:2)
当值溢出(?)
时,将浮点类型转换为无符号整数类型时会发生什么
未定义的行为(UB)
另外@user694733很好的答案,为了防止超出范围float
到unsigned
代码导致未定义的行为,可以首先测试float
值。
然而,对于无符号类型,特别是对于签名类型,测试范围是棘手的。细节是整数转换之前的所有转换和常量必须 exact 。接近极限的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
数学,可能会起作用,但到目前为止,我认为它不会对上述解决方案产生负面影响。