abs(-2147483648)的结果是-2147483648,不是吗?这似乎是不可接受的.
printf("abs(-2147483648): %d\n", abs(-2147483648));
Run Code Online (Sandbox Code Playgroud)
输出:
abs(-2147483648): -2147483648
Run Code Online (Sandbox Code Playgroud)
Ale*_*nze 22
标准说abs()
:
的
abs
,labs
和llabs
函数计算的整数的绝对值j
.如果无法表示结果,则行为未定义.
并且结果确实无法表示,因为有符号整数的2的补码表示不是对称的.想想看......如果你在32位int
,这给你2点32从不同的值INT_MIN
来INT_MAX
.这是偶数个值.因此,如果只有一个0,则大于0的值的数量不能与小于0的值的数量相同.因此,没有正值对应INT_MIN
的值为 - INT_MIN
.
所以,调用abs(INT_MIN)
你的平台是不可接受的.
Luk*_*hne 15
负数通常表示为二进制补码.
要将正转换为负数,则使用逻辑
x -> not(x)+1
Run Code Online (Sandbox Code Playgroud)
对于8位算术
01111111b是127,-127变为
10000000b + 1 = 10000001b
并向相反方向-127 10000001b变为
01111110b + 1 = 01111111b
-128怎么样?
-128是10000000b并且它没有正对应物,因为在8位有符号算术中没有128.
10000000 - > 01111111 + 1 = 10000000和-128
同样适用于原始问题
这是GNU glibc源代码中abs.c中的代码.
/* Return the absolute value of I. */
int
DEFUN(abs, (i), int i)
{
return(i < 0 ? -i : i);
}
Run Code Online (Sandbox Code Playgroud)
所以,abs(-2147483648)返回 - ( - 2147483648).在x86中,它是由这两条指令实现的
movl $-2147483648, %eax
negl %eax
Run Code Online (Sandbox Code Playgroud)
negl指令通过这种方式实现:num = 0-num; sbb通过这种方式实现:从目标中减去源,如果设置了进位标志,则减去1.所以abs(-2147483648)(十六进制是0x80000000) - > - ( - 2147483648) - > 0 - ( - 2147483648)最终成为(0x80000000).
有关negl指令的详细信息,请访问http://zsmith.co/intel_n.html#neg
有关sbb指令的详细信息,请访问http://web.itu.edu.tr/kesgin/mul06/intel/instr/sbb.html
归档时间: |
|
查看次数: |
16374 次 |
最近记录: |