如果浮点范围更大,通过浮点的往返是否总是定义行为?
Is round-trip through floating point always defined behavior if floating point range is bigger?
假设我有两种算术类型,一种是整数,I
,另一种是浮点数,F
。我还假设 std::numeric_limits<I>::max()
小于 std::numeric_limits<F>::max()
.
现在,假设我有一个正整数值 i
。因为 F
的可表示范围大于 I
,所以 F(i)
应该始终是定义的行为。
但是,如果我有一个浮点值 f
使得 f == F(i)
,I(f)
是否定义明确?换句话说,I(F(i))
总是定义行为吗?
C++14 标准的相关部分:
4.9 Floating-integral conversions [conv.fpint]
- 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 ]
- 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.
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?
没有
假设I
是带符号的二进制补码32位整数类型,F
是32位单精度浮点数类型,i
是最大正整数。这在浮点类型的范围内,但不能准确表示为浮点数。这 32 位中的一些用于指数。
相反,从整数到浮点数的转换取决于实现,但通常是通过四舍五入到最接近的可表示值来完成的。该舍入值超出了整数类型的范围。转换回整数失败(更好的说法是,这是未定义的行为)。
没有
有可能 i == std::numeric_limits<I>::max()
,但 i
在 F
中不能完全表示。
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.
由于可能会选择下一个更高的可表示值,因此结果 F(i)
可能不再适合 I
,因此向后转换将是未定义的行为。
没有。无论标准如何,您都不能指望此转换通常会 return 您的原始整数。这在数学上没有意义。但是如果你仔细阅读你引用的内容,该标准清楚地表明在从 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 并返回时,我从 2147473647
变为 -2147473648
。所以看起来这个数字增加了一个单位并且绕到了负数。
我没有检查我的系统上实际使用了多少位浮点数,但它至少证明了精度的损失,并且它表明 gcc "rounded up".
假设我有两种算术类型,一种是整数,I
,另一种是浮点数,F
。我还假设 std::numeric_limits<I>::max()
小于 std::numeric_limits<F>::max()
.
现在,假设我有一个正整数值 i
。因为 F
的可表示范围大于 I
,所以 F(i)
应该始终是定义的行为。
但是,如果我有一个浮点值 f
使得 f == F(i)
,I(f)
是否定义明确?换句话说,I(F(i))
总是定义行为吗?
C++14 标准的相关部分:
4.9 Floating-integral conversions [conv.fpint]
- 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 ]- 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 valuefalse
is converted to zero and the valuetrue
is converted to one.
However, if I have a floating point value
f
such thatf == F(i)
, isI(f)
well defined? In other words, isI(F(i))
always defined behavior?
没有
假设I
是带符号的二进制补码32位整数类型,F
是32位单精度浮点数类型,i
是最大正整数。这在浮点类型的范围内,但不能准确表示为浮点数。这 32 位中的一些用于指数。
相反,从整数到浮点数的转换取决于实现,但通常是通过四舍五入到最接近的可表示值来完成的。该舍入值超出了整数类型的范围。转换回整数失败(更好的说法是,这是未定义的行为)。
没有
有可能 i == std::numeric_limits<I>::max()
,但 i
在 F
中不能完全表示。
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.
由于可能会选择下一个更高的可表示值,因此结果 F(i)
可能不再适合 I
,因此向后转换将是未定义的行为。
没有。无论标准如何,您都不能指望此转换通常会 return 您的原始整数。这在数学上没有意义。但是如果你仔细阅读你引用的内容,该标准清楚地表明在从 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 并返回时,我从 2147473647
变为 -2147473648
。所以看起来这个数字增加了一个单位并且绕到了负数。
我没有检查我的系统上实际使用了多少位浮点数,但它至少证明了精度的损失,并且它表明 gcc "rounded up".