假设我有两个算术类型,一个整数类型 I 和一个浮点类型 F。我还假设 std::numeric_limits::max() 小于 std::numeric_limits::max()。
现在,假设我有一个正整数值 i。由于 F 的可表示范围大于 I,F(i) 应该总是有定义的行为。
然而,如果我有一个浮点值 f,使得 f == F(i),那么 I(f) 是否被良好定义?换句话说,I(F(i)) 是否总是有定义的行为?
相关部分摘自 C++14 标准:
4.9 浮点-整数转换 [conv.fpint] 1. 浮点类型的 prvalue 可以转换为整数类型的 prvalue。转换将截断;也就是说,小数部分被丢弃。如果截断后的值无法在目标类型中表示,则行为未定义。[注:如果目标类型是 bool,请参见 4.12。--end note] 2. 整数类型或未作用域枚举类型的 prvalue 可以转换为浮点类型的 prvalue。如果可能,结果是精确的。如果要转换的值在可以表示的值范围内,但不能准确地表示该值,则实现可以选择下一个更低或更高的可表示值。[注:如果整数值不能准确地表示为浮点类型的值,则会发生精度损失。--end note]如果要转换的值超出了可以表示的值范围,则行为未定义。如果源类型是 bool,则将值 false 转换为零,将值 true 转换为一。
现在,假设我有一个正整数值 i。由于 F 的可表示范围大于 I,F(i) 应该总是有定义的行为。
然而,如果我有一个浮点值 f,使得 f == F(i),那么 I(f) 是否被良好定义?换句话说,I(F(i)) 是否总是有定义的行为?
相关部分摘自 C++14 标准:
4.9 浮点-整数转换 [conv.fpint] 1. 浮点类型的 prvalue 可以转换为整数类型的 prvalue。转换将截断;也就是说,小数部分被丢弃。如果截断后的值无法在目标类型中表示,则行为未定义。[注:如果目标类型是 bool,请参见 4.12。--end note] 2. 整数类型或未作用域枚举类型的 prvalue 可以转换为浮点类型的 prvalue。如果可能,结果是精确的。如果要转换的值在可以表示的值范围内,但不能准确地表示该值,则实现可以选择下一个更低或更高的可表示值。[注:如果整数值不能准确地表示为浮点类型的值,则会发生精度损失。--end note]如果要转换的值超出了可以表示的值范围,则行为未定义。如果源类型是 bool,则将值 false 转换为零,将值 true 转换为一。
I
和F
具有相同的大小,比如32位。然后取最大的整数。它必然会转换成类型为F
的值,但会有损失。如果所选的可表示值大于下一个整数,则转换回来会导致未定义行为。 - Kerrek SBfloat
的范围与整数的范围相比巨大,但它只有23位的尾数,这意味着在指数高于23时,它将无法表示所有整数(甚至近似)。第一个这样的值将是2^24 + 1
,它位于(1 + 0/2^23) * 2^24
和(1 + 1/2^23) * 2^24
之间。double
可以正确舍入到任何32位整数(但不能舍入到任何64位整数)。 - Wug