老生常谈的代码优化
在开发的过程中,最开始想的是如何完成任务,后来就总想着写一些 new bee 的代码,再往后我们可能就该注重性能优化了,因为迈出初级程序员的那道坎 已经让你不能再安逸下去了。其中优化的手段有很多,从资源的加载到程序的优化再到渲染的优化;诸如这些,咳咳,我们这里暂且都不谈,主要是根据最近的一些理解,聊一聊代码中的------位运算。
现在编程语言的更新和进步已经让很多的人都不再对内存的分配使用花太多的心思了,我们也很少使用汇编语言和VC来进行日常开发了,但是我们都知道,在程序中的所有的数 在计算机的内存中都是以二进制的形式存储的,而我们今天要谈的位运算就是直接对内存中的二进制位进行操作;废话不多说,上表:
注意首先操作对象都是整数类型
1、按位与 &
按位与 运算通常用于二进制的取位操作,例如 一个数 & 1 的结果就是取其二进制的最末位,有什么实际意义呢?对了,这可以用来判断一个整数的奇偶!二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数。相同位的两个数字都为1,则为1;若有一个不为1,则为0。我们在日常开发中经常会有需求来判断序列奇数位和偶数位的表现形式或者功能不一样,这样就好了 直接 &1 ,底层操作,代码简洁,是不是甩那些 ” %2 == 0 “的程序员十八条街?
2、 按位或 |
按位或 运算通常用于二进制特定位上的无条件赋值,例如一个数or 1的结果就是把二进制最末位强行变成1。如果需要把二进制最末位变成0,对这个数or 1之后再减一就可以了,其实际意义就是把这个数强行变成最接近的偶数。相同位上只要有一个1 即为1; 这个需求可以了解,日常使用的话 可能略显浮夸;容易被吐槽。
3、 异或 ^
异或的符号是 ^ 。按位异或运算, 对等长二进制模式按位或二进制数的每一位执行逻辑按位异或操作. 操作的结果是如果某位不同则该位为1, 否则该位为0.按位异或运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即(a ^ b) ^ b = a。按位异或运算可以用于简单的加密,举一个容易理解的例子:比如我想对一个后端MM说1314520,但怕别人知道,于是双方约定拿我的生日19941104作为密钥。1314520 ^ 19941104 = 19154984,我就把19154984告诉MM。MM再次计算19154984 ^ 19941104的值,得到1314520。这样 就可以提前祝你成功了!什么成功。呃呃 ,你们的数字就都可以加密了,这里涉及到具体的东西,比如传输金币的数值,体力的数值,等等,反正早晚会用到的吧。。。
再有一个常用的功能,我们经常用到的功能,是每一个程序员闭着眼都应该写出来的功能,swap.没错,在这里解释一下swap,知道的可以跳过,swap就是交换分区,上一段伪代码就知道了;
```
temp = a;
a = b;
b = temp;
```
是不是很眼熟?说到这里就再谈谈,有时候不想分配一个多余的变量,我们会这样操作;
```
a = a + b;
b = a - b;
a = a - b;
```
好吧,我承认你要是在学校,老师肯定会夸你,这位同学不错,理解的很快;仅限学校哈;那么接下来,看一点很厉害的东西。。。。
```
a = a ^ b;
b = a ^ b;
a = a ^ b;
```
是不是很诡异呢?是刚才你说的 ^ 逆运算是本身嘛,这么写完全没问题,所以,可以拿去装X 了。
4、按位取反运算 ~
敲黑板,这里不是析构函数,这里是位运算带你装X带你飞课堂,哈哈;按位取反运算的定义是把内存中的0和1全部取反。计算方法是这样的,
1、将待计算的数用2进制表示,位数最少为可以表示出当前数的绝对值的二进制位数加1(多1位符号位)。也就是将9表示为01001,其中最左面的0是符号位,0为正,1为负。
2、将每个二进制位取反,及如果是1,结果为0,反之结果为1。取反后结果为10110
3、将结果看做是有符号数,转为十进制即可。最左面的一位是符号位,1代表是负的。在计算机中负数是补码表示的,有符号数10110转为10进制即-10。
计算按位取反的简便算法: 用 -1 减去待取反的数即为按位取反的结果:-1-9=-10。而,这个在实际操作中有什么用呢()?看这里,举一个例子,有时我们会判断一个字符串中是否存在已有的字符串,(栗子要广义的理解,不要过分纠结伪代码的真假)
`return this.systemInfo['system'].indexOf('ios') != -1 ;` ,我们会通过它返回的值来判断是否是iOS设备,一般人会这么写 ,如果上面的代码返回 -1 即不是iOS,反之为是;那么看下面的代码;
`return !!( ~ this.systemInfo['system'].indexOf('ios')) ;`
是不是瞬间高大上了,而且注意,这种位运算更快,更节省性能;
( !! 的功能是把 null 、undefined 、0 都变成 false ,平时用的少的可能不知道)
5、左移运算; <<
a << b就表示把a转为二进制后左移b位(在后面添b个0)。例如100的二进制为1100100,而110010000转成十进制是400,那么100 << 2 = 400。可以看出,a << b的值实际上就是a乘以2的b次方,因为在二进制数后添一个0就相当于该数乘以2。
通常认为a << 1比 a * 2更快,因为前者是更底层一些的操作。因此程序中乘以2的操作请尽量用左移一位来代替。
6、右移运算; >>
和左移相似,a >> b表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整)。和上面一样的例子,那么400 >> 2 = 100。我们也经常用 >> 1来代替 / 2,比如二分查找、堆的插入操作等等。想办法用 >> 代替除法运算可以使程序效率大大提高。最大公约数的二进制算法用除以2操作来代替mod运算,效率可以提高60%。(这是百度百科上说的,不是我说的。)
这一点在日常代码中应用就更多了,比如我们设置图形的锚点的时候;
```
img.anchorOffsetX = img.width >> 1;
img.anchorOffsetY = img.height >> 1;
```
这样的代码简洁、规范、还高效,何乐而不为呢?
好了,都说完了,或许这些都是技术大牛不屑一顾的,但是对于我这种小学生来说,以后还是要掌握并且熟练使用的,最起码,不想吃天鹅肉的癞蛤蟆不是好癞蛤蟆,哈哈,做技术不能只为了完成需求,要多更多的理解,想别人想不到的东西,开始想的浅没关系,只要养成了思考的习惯,当你有一天回首的时候,你就会发现自己已经到达了一个很高的高度,至少会欣慰一些吧,前两天看到一个985硕士,13年工作经验,被一个公司的HR开价2800一个月.我不知道他怎么想的,或许这不是真的故事,但至少我们别在30岁还是个初级程序员的水平就好了;
以后面对如何进行优化的面试题,是不是又多了一条代码优化的回答呢?这个回答可能是雕虫小计,但是很能反应你的思考能力。希望能有所帮助。
来自一个矫情的程序员;