在大多数机器上,整数 的除法很慢,需要30多个时钟周期,除以2的幂也可以用移位运算来实现
先码上代码
#include "stdio.h"
int main()
{
int x=-128;
int y=x/4;
printf("y=%d",y);
}
再附上汇编代码
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
movl $-128, 24(%esp)
movl 24(%esp), %eax
leal 3(%eax), %edx
testl %eax, %eax //这一步是测试%eax寄存器的值是否为0.并将标志位ZF和SF置为0或者1.
cmovs %edx, %eax //cmovs代表,sign为1的时候,也就是有符号数的时候,就执行mov指令。这是一个条件指令。
sarl $2, %eax //因为比如像c语言中就规定,右移是进行算术右移。那么就相当于c表达式(x<0 ? (x+(1<<k)-1) : x)>>k,因为c代码是除以4,那么就是右移2位。
movl %eax, 28(%esp)
movl 28(%esp), %eax
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
写这个笔记,主要目的有两点。
第一,在大多数机器上,进行除法指令比整数乘法指令更慢,需要30几个时钟周期。而移位只需要1个或几个时钟周期。这节省了很多时间。
所以一些编译器会把除法,编译为右移指令。
第二,进行算术右移的时候,是要分类讨论的。因为在大多数编程语言中,右移就是算术右移。
x/(2^k),若x为正数,那么右移,高位补0,这个没问题;
当x为负数的时候,右移,高位补1,那么由于得到的数是向下取整的(例如,得到的理论上的值为-2.1,那么结果为--3)
所以要在低位加1,也即在第k位置1.换成c语言为
(x<0 ? (x+(1<<k)-1) : x)>>k,