c的long int除法出现意外结果

  • 本文关键字:意外 结果 除法 long int c
  • 更新时间 :
  • 英文 :


我尝试在C中进行长int除法,但我无法得到正确的结果。我很好奇为什么我崩溃了,我怎么才能得到正确的结果。

#include <stdio.h>
#include <stdint.h>
int main() {
int64_t a = 0x8000000000000000;
int64_t b = 0xffffffffffffffff;
printf("a: %ld; b: %ldn", a, b);
int64_t c = a/b;
printf("a/b: %ldn", c);
return 0;
}

结果如下:

(base) ➜  ~ gcc test.c -O2
(base) ➜  ~ ./a.out
a: -9223372036854775808; b: -1
a/b = : -9223372036854775808
(base) ➜  ~ gcc test.c
(base) ➜  ~ ./a.out
a: -9223372036854775808; b: -1
[1]    39193 floating point exception (core dumped)  ./a.out

除法结果

首先,尝试使用正确的格式说明符。包括inttypes.h,使用printf(PRId64 "n", x);打印int64_t x;%ld不可携带。它可能有效,也可能不有效。

然后注意,如果整数没有大小限制,除法int64_t c = a/b;的答案将是2^63。但实际上,没有64位补码来表示这个数字。范围从-2^632^63 - 1。这就是导致异常的原因。您已经溢出了正在进行除法运算的算术单元。

打开课本学习二进制整数表示。

正如您已经注意到的,打印ab:

int64_t a = 0x8000000000000000;
int64_t b = 0xffffffffffffffff;
printf("a:%" PRId64 ", b:%" PRId64 "n", a, b);

产生以下内容:

a:-9223372036854775808, b:-1

然而,在64位机器上,用64位有符号整数INT64_MIN除以-1是一个未定义的行为。

2的补数算法的一个可怕的产物是"最负数"问题。代码如下:

int8_t a = -127; //-127 to 127 OK
int8_t b = -1;
printf("a/b: %hhdn", a/b);

此代码将适用于a的任何值,除了-128(INT8_MIN)的。这是因为:

1000 0000 (-128)
0111 1111 (bit flip)
1000 0000 (add one, back at -128!!)

但是如果你看最后第二步:

0111 1111 (bit flip)

如果再加1,就已经溢出了,因为第一个位被保留为符号位。

最新更新