如何在不调用未定义的行为的情况下检查一个值适合类型?
我希望检查double
值是否可以表示为int
(或对于整数类型的任何一对浮点)。这是一种简单的方法:
double x = ...;
int i = x; // potentially undefined behaviour
if ((double) i != x) {
// not representable
}
但是,它在标记的线上调用了未定义的行为,并触发了瑞银(有些人会抱怨)。
问题:
- 这种方法一般认为可以接受吗?
- 在不调用未定义行为的情况下,是否有合理简单的方法可以做到这一点?
按要求进行澄清:
我现在面临的情况涉及从double
转换为各种整数类型(int
,long
,long>但是。整数和整数 - >浮点转换。
转换如何失败的示例:
- float->整数转换可能失败是值不是整数,例如
3.5
。 - 源值可以超出目标类型的范围(比最大和最小代表值更大或小)。例如
1.23E100
。 - 源值可能为 +-Inf或Nan,NAN很棘手,因为与其任何比较返回false。
- 整数 - >当浮点类型没有足够的精度时,浮点转换可能会失败。例如,典型的
double
具有52个二进制数字,而64位整数类型中有63位数字。例如,在典型的64位系统上,(long)(double)((1l<<< 53) + 1L)
。 - 我知道
1L<< 53
(而不是(1L<< 53) + 1
)在技术上完全可以表示为double
,并且我提出的代码会接受这种转换,即使可能不允许。 - 我没想到什么?
I am looking to check if a double
value can be represented as an int
(or the same for any pair of floating point an integer types). This is a simple way to do it:
double x = ...;
int i = x; // potentially undefined behaviour
if ((double) i != x) {
// not representable
}
However, it invokes undefined behaviour on the marked line, and triggers UBSan (which some will complain about).
Questions:
- Is this method considered acceptable in general?
- Is there a reasonably simple way to do it without invoking undefined behaviour?
Clarifications, as requested:
The situation I am facing right now involves conversion from double
to various integer types (int
, long
, long long
) in C. However, I have encountered similar situations before, thus I am interested in answers both for float -> integer and integer -> float conversions.
Examples of how the conversion may fail:
- Float -> integer conversion may fail is the value is not a whole number, e.g.
3.5
. - The source value may be out of the range of the target type (larger or small than max and min representable values). For example
1.23e100
. - The source values may be +-Inf or NaN, NaN being tricky as any comparison with it returns false.
- Integer -> float conversion may fail when the float type does not have enough precision. For example, typical
double
have 52 binary digits compared to 63 digits in a 64-bit integer type. For example, on a typical 64-bit system,(long) (double) ((1L << 53) + 1L)
. - I do understand that
1L << 53
(as opposed to(1L << 53) + 1
) is technically exactly representable as adouble
, and that the code I proposed would accept this conversion, even though it probably shouldn't be allowed. - Anything I didn't think of?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
创建范围限制与FP类型
“窍门”是在不失去精度的情况下形成限制。
让我们考虑
float
int
。float
转换为int
是有效的(例如,32位2的补语int
),以-2,147,483,648.9999 ...至2,147,483,647.99999 ...或几乎int_min
-1 toint_max
+ 1。我们可以利用
integer_max
始终是一种力量-2-1和integer_min
is-(2)(用于常见2的补语)。避免
fp_int_min_minus_1
的限制,因为它可能/可能无法完全编码为FP。更多的pedantic代码将使用
!isnan(f)
,并考虑Non-2的补充编码。Create range limits exactly as FP types
The "trick" is to form the limits without loosing precision.
Let us consider
float
toint
.Conversion of
float
toint
is valid (for example with 32-bit 2's complementint
) for -2,147,483,648.9999... to 2,147,483,647.9999... or nearlyINT_MIN
-1 toINT_MAX
+ 1.We can take advantage that
integer_MAX
is always a power-of-2 - 1 andinteger_MIN
is -(power-of-2) (for common 2's complement).Avoid the limit of
FP_INT_MIN_minus_1
as it may/may not be exactly encodable as a FP.More pedantic code would use
!isnan(f)
and consider non-2's complement encoding.使用已知限制和浮点数有效性。检查
limits.h
标头中的内容。您可以编写如下内容:
显然,代码依赖于惰性布尔求值。
Using known limits and floating-point number validity. Check what's inside
limits.h
header.You can write something like this:
Code relies on lazy boolean evaluation, obviously.
请参考 IEEE 754 内存中浮点数的表示
https://en.wikipedia.org/wiki/IEEE_754
以 double 为例:
这里需要指出三个特殊值:
这是64位上double转int的例子,仅供参考
Please refer to IEEE 754 representation of floating point numbers in Memory
https://en.wikipedia.org/wiki/IEEE_754
Take double as an example:
There are three special values to point out here:
This is an example of convert from double to int on 64-bit, just for reference