前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从编译器除以2的幂说起

从编译器除以2的幂说起

作者头像
超级大猪
发布2023-08-10 14:41:33
1690
发布2023-08-10 14:41:33
举报
文章被收录于专栏:大猪的笔记大猪的笔记

执行除法,是一种比较耗费性能的操作。但有一种类型除外。那就是除以2的幂。编译器会将除以

2^n

使用移位进行优化。

我们在编码时可以善于利用

2^n

,比如数组/队列的长度、取余、相除的除数等最好都使用

2^n

。说不定有意外的惊喜。在各类语言的标准库中,广泛的使用了这一优化。

原码除以 2^n

当一个整数以原码表示时,除以2的幂也可以用移位运算来实现。

执行逻辑右移(前位补0)移位总是舍入到零的结果。

公式为:

x/2^k = x>>k

<img src="https://share.superpig.win/img_share/edit-55f902ead4294db5a9b857197b5748ff/image-20230117155131336.png" alt="image-20230117155131336" style="zoom:50%;" />

> 图源:《深入理解计算机系统-第二章:信息的表示和处理

也就是说计算

6170/2^3

等同于6170的原码 0001100000011010,右移3位,得到000 0001100000011

其结果等于 771,而实际结果是 6170/8 = 771.25

结果向0进行了舍入。

补码除以 2^n

同理,补码有类似的性质。但需要进行算术右移,也就是前位补1。

<img src="https://share.superpig.win/img_share/edit-55f902ead4294db5a9b857197b5748ff/image-20230117155401056.png" alt="image-20230117155401056" style="zoom:50%;" />

> 图源:《深入理解计算机系统-第二章:信息的表示和处理》

-6170使用补码表示是:1110011111100110

对其除以

2^3

。等同右移3位,得到结果为:-772。但结果变成了 向下舍入。

回到前面的原码场景,6170进行除以8的结果是 771

为了运算一致,可以在移位前,增加一个&#x504F;&#x7F6E;(biasing),使其也向0舍入,这也是go的默认处理方式。

偏置为:

(2^k-1)

此时,运算公式变为:

x/2^k = (x+(2^k-1))>>k

重新计算

-6170/2^3

-6170使用补码表示是:1110011111100110

偏置

2^3-1

使用补码表示是 111

相加:1110011111101101

算术右移得:1111110011111101=-771,此时就是向0舍入的结果。

为什么偏置是 2^n-1

2^n-1

用二进制表示是,n个1。

比如

2^3-1=b111

1、假设最右边的n位是000...000,则加上n个1,再进行右移n位,这n个1不会有任何影响。因为正好能除尽。

例如计算

-8/2^2=-2

解:

-8=b11000
2^2 - 1=b11
-8+2^2-1=b11011

算术右移2位:

b11110 = -2

这说明,正好能除尽,也就没有向0舍入的问题。

2、假设最右边的n位是 111...111,加上n个1,再进行右移n位。

例如计算:

-25/2^3=-3.125

解:

-25 = b100111
-25+2^k-1=b100111+111=b101110

算术移位得:

b111101 = -3

这说明,增加偏置后,进行了一次进位。这个进位即是多出来的小数部分。如果不加偏置,直接算术右移,则结果为:

b111100 = -4

这就是-3.125向下舍入的结果。

最后,看看汇编代码会变成什么样

代码语言:javascript
复制
long arith(long x){
  return x/8
}

<img src="https://share.superpig.win/img_share/20230807/image-20230807212816533.png" alt="image-20230807212816533" style="zoom:50%;" />

这段代码计算了两个结果,

当x<0的时候,第二行汇编就是对 x 增加偏置 7。

当x>=0的时候,直接将x放在 %rax,这使得之前的带偏置的计算结果被丢弃,然后sarq,对 x 进行移位。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-08-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 原码除以 2^n
  • 补码除以 2^n
  • 为什么偏置是 2^n-1
  • 最后,看看汇编代码会变成什么样
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档