为什么否定最小可能整数会产生自身?

时间:2017-07-13 19:40:12

标签: c integer storage min twos-complement

所以我写了一个小实验测试下溢&溢出,使用c和64位机器。对于int类型,最小/最大值为:

   int tmax = 2147483647;
   int tmin = -2147483648;

我知道两个补充是如何运作的,这不是我的问题。

所以我想,如果我做了一些消极的tmin会发生什么?那就是:

   int tmin = -2147483648;
   int negativeTmin = -tmin;

它最终仍然是tmin。 (即,negativeTmin将为-2147483648)

我的问题是为什么会这样?由于积极的2,147,483,648不能用int表示,我理解为什么它当然不是,但它似乎并不奇怪,它并没有改变所有这一点使它成为唯一的非零int,当 - 应用于它时,它不会发生变化。我并不是说我对它应该是什么有更好的了解,我只是好奇为什么-tmin == tmin。它是否与按位运算有关,或者在计算机中如何进行减法,或者它是否默认执行此操作,因为我尝试做的是未定义的,还是其他什么?

我的代码:

#include <stdio.h>
int main() {
   int tmax = 2147483647;
   printf("tmax Before: %d\n", tmax);
   tmax++;
   printf("tmax After: %d\n\n", tmax);

   int tmin = -2147483648;
   printf("tmin Before: %d\n", tmin);
   tmin--;
   printf("tmin After: %d\n\n", tmin);

   int tmin2 = -2147483648;
   int negativeTmin = -tmin2;
   printf("negative tmin: %d\n\n", negativeTmin);

   return 0;
}

输出:

  

tmax之前:2147483647   tmax之后:-2147483648

     

tmin之前:-2147483648   tmin之后:2147483647

     

负tmin:-2147483648

5 个答案:

答案 0 :(得分:3)

由于整数溢出,您的代码int tmin2 = -2147483648; int negativeTmin = -tmin2引入了未定义的行为,因此它可能会产生任何结果。所以考虑任何规则,为什么会发生这种情况,如果它与两个补码有关,那就毫无意义,实际上是错误的。

对于未定义的行为,整数溢出是 示例,因为它在标准的&#34;未定义的行为&#34;的定义中作为示例提及。 (3.4.3 - undefined behavior):

  

使用不可移植或错误时的1个未定义的行为行为   程序构造或错误数据,本国际   标准没有要求

     

2注意可能的未定义行为包括忽略这种情况   完全具有不可预测的结果,在翻译过程中表现出色   或者以文件化的方式执行程序   环境(有或没有发出诊断信息),到   终止翻译或执行(发布a   诊断信息)。

     

3示例未定义行为的示例是整数上的行为   溢出。

答案 1 :(得分:3)

正如其他人在这里发布的那样,从技术上讲,你所做的事情会导致未定义的行为,因为C中有符号整数的上溢或下溢会导致未定义的行为。

另一方面,在大多数英特尔系统上,整数上溢或下溢只是围绕整数值并设置一些处理器标志,以便将来的指令可以检测到溢出。在那些系统上,当你计算-T min 时,为什么你得到T min 是合理的?

在签名的双向补充系统中,值得注意的是表达式-x等同于~x + 1。所以,让我们想象你有T min ,看起来像这样:

10000000 00000000 00000000 00000000

如果你计算~T min ,你得到

01111111 11111111 11111111 11111111

这恰好是T max 。如果你向它添加一个,你会得到一个巨大的波纹携带传播一直到最后,产生

10000000 00000000 00000000 00000000

这是我们开始的。这就是为什么你可能会看到T min 回来。

另一种看待这种情况的方法:你知道签名的32位整数的T min 是-2 31 。 -T min 的值应该是一个值,使得T min + -T min = 0(mod 2 32 )。那么[-2 31 ,2 31 - 1]范围内的哪个值碰巧有这个属性?它是-2 31 ,这就是为什么T min = -T min

所以对你的问题的最佳答案可能是&#34;技术上你正在做的是未定义的行为,但是在合理的英特尔系统和没有设置进行积极优化的编译器上,它归结为有符号的32位整数运算如何工作以及如何定义否定的机制。&#34;

答案 2 :(得分:0)

-X是X的2s补码 这就是硬件对否定所做的事情https://c9x.me/x86/html/file_module_x86_id_216.html

INT_MIN = -2147483648 = 0x80000000
2的补充-2147483648 = 0x80000000

您可以将2的补码计算为翻转位并添加1个 请参阅https://en.wikipedia.org/wiki/Two%27s_complement。翻转位0x80000000给出0x7fffffff。
0x7fffffff + 1 = 0x80000000 = -2147483648

(gdb)p / x(int)( - 2147483648)
   $ 14 = 0x80000000
   (gdb)p / x(int) - ( - 2147483648)
   $ 15 = 0x80000000
   (gdb)p / x~(0x80000000)
   $ 16 = 0x7fffffff
   (gdb)p / x~(0x80000000)+ 1
   $ 17 = 0x80000000

答案 3 :(得分:0)

另一种思考方式。

类型为int的数据用32位表示。取tmin = -2147483648,然后当然是-tmin =2147483648。在二进制补码算法中, tmin 的二进制表示为

10000000 00000000 00000000 00000000

,对于 -tmin

0 10000000 00000000 00000000 00000000

但是只允许32位,因此截断消除了最高有效位(在这种情况下,是第一个零),我们得到了

10000000 00000000 00000000 00000000

这是 tmin

答案 4 :(得分:-2)

实际上我相信我刚刚意识到答案;因为我们知道2147483648不能用int表示,因此是-2147483648,所以当你做 - ( - 2147483648)以及那是2147483648时,但是不能表示如上所述那样变成-2147483648。因此为什么-tmin == tmin。