绝对值为64位整数的问题

时间:2013-07-30 00:57:44

标签: 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;
}

输出

-9223372036854775808

更新:

感谢您的所有答案。我知道这是一个非标准值,这就是为什么我无法对它执行绝对操作。但是,我确实在实际的代码库中遇到了这个问题,这是一个遗传编程模拟。这里的“生物”不知道C标准,并坚持产生这个价值:)有谁能告诉我一个有效的解决方法?再次感谢。

5 个答案:

答案 0 :(得分:4)

基本上,你不能。

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

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

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

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

  

abs labs llabs 函数计算绝对值   整数 j 的值。如果结果无法表示,则   行为未定义。

就此而言,

的结果
int64_t a = 0x8000000000000000;

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

(从理论上讲,程序的行为也可能只是实现定义而不是未定义。如果long long宽于64位,那么llabs(a)的评估不是未定义的,而是转换返回int64_t的结果是实现定义的。实际上,我从未见过long long宽于64位的C编译器。)

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

答案 1 :(得分:4)

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

为了让您的程序具有已定义的行为,您必须确保传递给llabs()的值不小于-LLONG_MAX。你是如何做到这一点取决于你 - 要么修改“有机体”,以便它们不能生成这个值(例如,过滤掉那些创建超出范围的值,因为它立即不合适)或者在将值传递给llabs()

答案 2 :(得分:2)

0x8000000000000000是可以由带符号的64位整数表示的最小数字。由于two's complement中的怪癖,这是唯一的64位整数,其绝对值不能表示为64位有符号整数。

这是因为0x8000000000000000 = -2^63,而最大可表示的64位整数是0x7FFFFFFFFFFFFFFF = 2^63-1

因此,取绝对值是未定义的行为,通常会产生相同的值。

答案 3 :(得分:1)

带符号的64位整数范围为−(2^63)2^63 − 10x8000000000000000−(2^63)的绝对值为2^63,大于最大64位整数。

答案 4 :(得分:1)

没有有符号整数,其最高位设置为高,所有其他位为低,可以表示为与该整数的绝对值相同的类型。

观察8位整数

int8_t x = 0x80; //二进制1000_0000,十进制-128

8位有符号整数可以保存介于-128和+127之间的值,因此值+128超出范围。 对于16位整数,这也是完整的

int16_t = 0x8000; //二进制1000_0000_0000_0000,十进制-32,768

16位整数可以保存介于-32,768和+32,767之间的值。

此模式适用于任何大小的整数,只要它以二进制补码表示,就像计算机中整数的事实表示一样。当所有位为低时,二进制补码保持为0,所有位为高时为-1。

因此,N位有符号整数可以保存2 ^(N-1)和2 ^(N-1)-1之间的值,无符号整数可以保存0到2 ^ N-1之间的值。 / p>