Is round-trip through floating point always defined behavior if floating point range is bigger?

时间:2015-04-29 00:33:52

标签: c++ language-lawyer c++14 floating-point-conversion

Let's say I have two arithmetic types, an integer one, I, and a floating point one, F. I also assume that std::numeric_limits<I>::max() is smaller than std::numeric_limits<F>::max().

Now, let's say I have a positive integer value i. Because the representable range of F is larger than I, F(i) should always be defined behavior.

However, if I have a floating point value f such that f == F(i), is I(f) well defined? In other words, is I(F(i)) always defined behavior?


Relevant section from the C++14 standard:

4.9 Floating-integral conversions [conv.fpint]

  1. A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type. [ Note: If the destination type is bool, see 4.12. — end note ]
  2. A prvalue of an integer type or of an unscoped enumeration type can be converted to a prvalue of a floating point type. The result is exact if possible. If the value being converted is in the range of values that can be represented but the value cannot be represented exactly, it is an implementation-defined choice of either the next lower or higher representable value. [ Note: Loss of precision occurs if the integral value cannot be represented exactly as a value of the floating type. — end note ] If the value being converted is outside the range of values that can be represented, the behavior is undefined. If the source type is bool, the value false is converted to zero and the value true is converted to one.

3 个答案:

答案 0 :(得分:4)

  

但是,如果我的浮点值为ff == F(i)I(f)是否已明确定义?换句话说,I(F(i))是否始终定义了行为?

没有

假设I是带符号的二进制补码32位整数类型,F是32位单精度浮点类型,i是最大正整数。这在浮点类型的范围内,但不能完全表示为浮点数。这些32位中的一些用于指数。

相反,从整数到浮点的转换是依赖于实现的,但通常通过舍入到最接近的可表示值来完成。该舍入值超出整数类型的范围。转换回整数失败(更好地说,它是未定义的行为)。

答案 1 :(得分:-1)

没有

可能是i == std::numeric_limits<I>::max(),但i中的F并不完全可以表示。

  

如果要转换的值在可以表示的值范围内,但该值无法准确表示,则它是实现定义的下一个较低或较高可表示值的选择。

由于可能会选择下一个较高的可表示值,因此结果F(i)可能不再适合I,因此转换回来将是未定义的行为。

答案 2 :(得分:-1)

没有。无论标准如何,您都不能指望通常此转换将返回原始整数。它在数学上没有任何意义。但是如果你读到你引用的内容,标准清楚地表明了从int转换为float时可能会失去精度。

假设您的类型I和F使用相同的位数。 I的所有位(可能保存一个存储符号的位)用于指定数字的绝对值。另一方面,在F中,一些比特用于指定指数,一些比特用于有效数。由于可能的指数,范围会更大。但是有效数字的精度会降低,因为它的规范所用的位数较少。

就像测试一样,我打印了

std::numeric_limits<int>::max();
std::numeric_limits<float>::max();

然后我将第一个数字转换为浮动并再次返回。 max float的指数为38,max int有10位数,所以显然float的范围更大。但是在将max int转换为float和back后,我从2147473647转到-2147473648。所以看起来这个数字增加了一个单位并且走向了负面。

我没有检查我的系统上浮动实际使用了多少位,但它至少证明了精度的损失,并且它表明gcc&#34;四舍五入&#34;。