C++中的整数上溢和下溢
Integer overflow and underflow in C++
谁能解释一下为什么会这样?? :
int a = 2147483647;
cout <<"Product = " << a * a << endl; // output = 1 (why?)
int b = -2147483648;
cout <<"Product = " << b * b << endl; // output = 0 (why?)
另外,当我们为 'short' 编写类似的代码时,尽管变量被初始化为 short 类型,编译器仍将乘积视为整数类型,例如:
short x = 32767;
cout <<"Product = " << x * x << endl; // Product = 1073676289
short y = -32768;
cout <<"Product = " << y * y << endl;// Product = 1073741824
第 1 部分:直觉,无需参考资料
让我们尝试使用一些直觉或合理假设来解释为什么这些结果有意义。
基本上,这是关于物理整数变量可以表示的内容 - 这不是所有整数的整个无限集,而是范围 -2^31 ... 2^31 - 1(对于 32-位整数,这可能是你所拥有的;但请务必检查以确保,例如使用 sizeof()
.)
现在,如果
a = 2^31 - 1
然后
a*a = (2^31 - 1)^2 = 2^62 - 2*2^31 + 1 = 2^62 - 2^32 + 1
作为理想整数,忽略物理表示。当将结果放置为 32 位整数时,合理的猜测是 CPU 给你的任何结果都将等同于理想结果的模 2^31 或 2^32:
(2^62 - 2^32 + 1) mod 2^32
= (2^62 mod 2^32) - (2^32 mod 2^32) + (1 mod 2^32)
= 1 mod 2^32
这就是你得到的。
对于 b
,您有:
b = -2147483648 = -2^31
和
b*b = 2^62
等于 0,模 2^31 或 2^32。
第 2 部分:语言的要求
虽然我们的直觉确实对结果给出了合理的解释,但考虑“官方”答案通常也很有用。在我们的例子中,我引用了 cppreference.com(这不是官方语言标准,但足够接近):
When signed integer arithmetic operation overflows (the result does
not fit in the result type), the behavior is undefined: it may wrap
around according to the rules of the representation (typically 2's
complement), it may trap on some platforms or due to compiler options
(e.g. -ftrapv in GCC and Clang), or may be completely optimized out by
the compiler.
所以实际上,你不能保证在不同的编译器、不同的编译器版本、不同的机器甚至重复编译相同的代码时得到这些值!你实际上可以得到 1234 和 5678 作为结果,你不能抱怨。或者你的程序可能会崩溃。或者其他任何事情都可能发生!参见:
Undefined, unspecified and implementation-defined behavior
关于你问题的第二部分(关于 short
s)- 这是由于 integer promotion:
The arguments of the following arithmetic operators undergo implicit
conversions for the purpose of obtaining the common real type, which
is the type in which the calculation is performed:
- binary arithmetic *, /, %, +, -
...
Integer promotion is the implicit conversion of a value of any integer type with rank less or equal to rank of int or of a bit field of type ...short
[other types here] to the value of type int
or unsigned int
第 3 部分:实用底线
注意避免计算值超过 std::numeric_limits<T>::max()
:使用较大的类型开始,或检查过高的值(例如,确保两个值的绝对值都低于 2^16,否则应用一些特殊处理)。
Can anyone please explain why this happens ?? :
int a = 2147483647;
cout <<"Product = " << a * a << endl; // output = 1 (why?)
因为程序的行为是未定义的。
int b = -2147483648;
cout <<"Product = " << b * b << endl; // output = 0 (why?)
因为程序的行为是未定义的。
Also when we write the similar for 'short' , the compiler takes the product as integer type despite the variables being initialized as of short type, like:
整数算术运算中所有低于int
的操作数都隐式转换为int
(如果它可以表示源类型的所有值;否则转换为unsigned int
).这种转换称为整数提升。
谁能解释一下为什么会这样?? :
int a = 2147483647;
cout <<"Product = " << a * a << endl; // output = 1 (why?)
int b = -2147483648;
cout <<"Product = " << b * b << endl; // output = 0 (why?)
另外,当我们为 'short' 编写类似的代码时,尽管变量被初始化为 short 类型,编译器仍将乘积视为整数类型,例如:
short x = 32767;
cout <<"Product = " << x * x << endl; // Product = 1073676289
short y = -32768;
cout <<"Product = " << y * y << endl;// Product = 1073741824
第 1 部分:直觉,无需参考资料
让我们尝试使用一些直觉或合理假设来解释为什么这些结果有意义。
基本上,这是关于物理整数变量可以表示的内容 - 这不是所有整数的整个无限集,而是范围 -2^31 ... 2^31 - 1(对于 32-位整数,这可能是你所拥有的;但请务必检查以确保,例如使用 sizeof()
.)
现在,如果
a = 2^31 - 1
然后
a*a = (2^31 - 1)^2 = 2^62 - 2*2^31 + 1 = 2^62 - 2^32 + 1
作为理想整数,忽略物理表示。当将结果放置为 32 位整数时,合理的猜测是 CPU 给你的任何结果都将等同于理想结果的模 2^31 或 2^32:
(2^62 - 2^32 + 1) mod 2^32
= (2^62 mod 2^32) - (2^32 mod 2^32) + (1 mod 2^32)
= 1 mod 2^32
这就是你得到的。
对于 b
,您有:
b = -2147483648 = -2^31
和
b*b = 2^62
等于 0,模 2^31 或 2^32。
第 2 部分:语言的要求
虽然我们的直觉确实对结果给出了合理的解释,但考虑“官方”答案通常也很有用。在我们的例子中,我引用了 cppreference.com(这不是官方语言标准,但足够接近):
When signed integer arithmetic operation overflows (the result does not fit in the result type), the behavior is undefined: it may wrap around according to the rules of the representation (typically 2's complement), it may trap on some platforms or due to compiler options (e.g. -ftrapv in GCC and Clang), or may be completely optimized out by the compiler.
所以实际上,你不能保证在不同的编译器、不同的编译器版本、不同的机器甚至重复编译相同的代码时得到这些值!你实际上可以得到 1234 和 5678 作为结果,你不能抱怨。或者你的程序可能会崩溃。或者其他任何事情都可能发生!参见:
Undefined, unspecified and implementation-defined behavior
关于你问题的第二部分(关于 short
s)- 这是由于 integer promotion:
The arguments of the following arithmetic operators undergo implicit conversions for the purpose of obtaining the common real type, which is the type in which the calculation is performed:
- binary arithmetic *, /, %, +, -
...
Integer promotion is the implicit conversion of a value of any integer type with rank less or equal to rank of int or of a bit field of type ...
short
[other types here] to the value of typeint
orunsigned int
第 3 部分:实用底线
注意避免计算值超过 std::numeric_limits<T>::max()
:使用较大的类型开始,或检查过高的值(例如,确保两个值的绝对值都低于 2^16,否则应用一些特殊处理)。
Can anyone please explain why this happens ?? :
int a = 2147483647; cout <<"Product = " << a * a << endl; // output = 1 (why?)
因为程序的行为是未定义的。
int b = -2147483648; cout <<"Product = " << b * b << endl; // output = 0 (why?)
因为程序的行为是未定义的。
Also when we write the similar for 'short' , the compiler takes the product as integer type despite the variables being initialized as of short type, like:
整数算术运算中所有低于int
的操作数都隐式转换为int
(如果它可以表示源类型的所有值;否则转换为unsigned int
).这种转换称为整数提升。