64 位整数的绝对值问题

Pra*_*ina 3 c gcc

此 C 代码试图找到负数的绝对值,但输出也是负数。谁能告诉我如何克服这个问题?

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

int main() {
    int64_t a = 0x8000000000000000;
    a = llabs(a);
    printf("%" PRId64 "\n", a);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出

-9223372036854775808
Run Code Online (Sandbox Code Playgroud)

更新:

感谢您的所有回答。我知道这是一个非标准值,这就是我无法对其执行绝对操作的原因。但是,我确实在遗传编程模拟的实际代码库中遇到过这种情况。这里的“有机体”不了解 C 标准并坚持生成此值:) 谁能告诉我解决此问题的有效方法?再次感谢。

caf*_*caf 6

如果 的结果llabs()无法在类型中表示long long,则行为未定义。我们可以推断这就是这里发生的事情 - 超出范围的值 0x8000000000000000 在转换为 时被转换为值 -9223372036854775808 int64_t,并且您的long long值是 64 位宽,因此值 9223372035680087 不可用。

为了让您的程序具有定义的行为,您必须确保传递给的值llabs()不小于-LLONG_MAX. 您如何做到这一点取决于您 - 要么修改“有机体”,使其无法生成此值(例如,过滤掉那些创建立即不适合的超出范围值的值),要么在将其传递给之前限制该值llabs().


Kei*_*son 5

基本上,你不能。

的可表示值的范围int64_t是-2 63到+2 63 -1。(并且标准要求int64_t具有纯 2 的补码表示;如果不支持,则实现将不会定义int64_t。)

该额外的负值没有相应的可表示的正值。

因此,除非您的系统具有大于 64 位的整数类型,否则您将无法将 的绝对值表示0x8000000000000000为整数。

事实上,根据 ISO C 标准,您的程序的行为是未定义的。引用2011 ISO C 标准N1570 草案的第 7.22.6.1 节:

ABS实验室,和llabs函数计算的整数的绝对值Ĵ。如果结果无法表示,则行为未定义。

就此而言,结果

int64_t a = 0x8000000000000000;
Run Code Online (Sandbox Code Playgroud)

是实现定义的。假设long long是 64 位,则该常量的类型为unsigned long long。它隐式转换为int64_t. 很可能,但不能保证,存储的值将是 -2 63-9223372036854775808. (甚至允许转换引发实现定义的信号,但这不太可能。)

(理论上,您的程序行为也可能只是实现定义的而不是未定义的。如果long long宽度大于 64 位,则 的评估llabs(a)不是未定义的,但结果的转换回int64_t是实现定义的。在实践中,我从未见过long long宽度超过 64 位的 C 编译器。)

如果您确实需要表示那么大的整数值,您可以考虑使用多精度算术包,例如GNU GMP