首页 > 解决方案 > 意外导致 C 的长整数除法

问题描述

我尝试在 C 中进行长整数除法,但我无法得到正确的结果。我很好奇我遇到崩溃的原因以及如何获得正确的结果。

#include <stdio.h>
#include <stdint.h>

int main() {
    int64_t a = 0x8000000000000000;
    int64_t b = 0xffffffffffffffff;
    printf("a: %ld; b: %ld\n", a, b);
    int64_t c = a/b;
    printf("a/b: %ld\n", 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

分割结果

标签: c

解决方案


正如您已经注意到的,打印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

二进制补码算术的一个可怕的伪影是“最负数”问题。拿这个代码:

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

此代码适用于除( )a之外的任何值。那是因为:-128INT8_MIN

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

但实际上,如果您查看最后一步:

0111 1111 (bit flip)

如果你加一个,我们已经溢出了,因为第一位被保留为符号位。


推荐阅读