博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
异或交换真的比开一个tmp快吗?
阅读量:7081 次
发布时间:2019-06-28

本文共 1955 字,大约阅读时间需要 6 分钟。

  在以前学习Java的时候,leetcode上有几道位运算的题目,利用位运算的特性很好的解决。

  之后有前辈老师在讲到异或^的时候,对我们说有不用开第三个变量tmp,来交换两个变量值的方法,说这种方法速度快,又节省了内存。受到之前leetcode题目和老师威信的影响下,我当然相信了,之后在写数据结构大作业的时候,又受到了学长异或交换两个值更快的提醒,然后特地把课程设计里面的算法涉及到交换的部分变成了位运算的写法,看起来逼格好像确实高了很多 =-=。

  然后在今天,几个大佬又在讨论这个问题。

  我们用代码证明了事实并非如此?!

  

 

结果证明tmp开第三个比异或时间上要快的多啊,喂。。。

现代机器的编译器其实在背后做了很多事啊。。

翻译成汇编的代码,跟我们想的有很多出入啊?!。。

两种写法:

{        int tmp;        tmp = a;        a = b;        b = tmp;}

按语言本身的特性来想,这些代码做以下这些工作:

  1. 在栈上分配为整型变量tmp分配空间;
  2. 将a的值放入tmp中;
  3. 将b的值放入a中;
  4. 将tmp的值放入b中;
  5. 释放为tmp分配的栈空间。

而实际上呢?我们来看看生成的汇编代码

 

movl        b, %eax    ;将b从内存载入到寄存器eax      movl        a, %edx    ;将a从内存载入到寄存器edx      movl        %eax, a    ;将eax的内容存入到内存a中      xorl        %eax, %eax ;将eax清零      movl        %edx, b    ;将edx的内容存入到内存b中

而另一种写法,

{        a ^= b;        b ^= a;        a ^= b;}

这个写法在-O2和-O3翻译成汇编:

movl        b, %eax       ;将b从内存载入寄存器eaxmovl        a, %ecx       ;将a从内存载入寄存器ecxmovl        %eax, %edx    ;将eax的值保存到edx中xorl        %ecx, %edx    ;ecx与edx异或xorl        %edx, %eax    ;edx与eax异或xorl        %eax, %edx    ;eax与edx异或movl        %eax, b       ;将eax的值存入到内存b中xorl        %eax, %eax    ;将eax置0:设置返回值,与上例中一样movl        %edx, a       ;将edx的值存入到内存a中

 

怎么样,结果跟你想的是否有出入呢,这样的话,第二种写法对内存的读写是肯定多于第一种的。

1.       这个所谓的“技巧”在现代的机器上只会更慢(我甚至怀疑它从来就不可能比原始办法快)。原始办法是两次内存读和写,这个"技巧"是六读三写加三次异或(或许编译器可以优化成两读三写加三次异或)。

2.       同样也不能节省内存,因为中间变量 tmp 通常会是寄存器(稍后有汇编代码供分析)。就算它在函数的局部堆栈(stack)上,反正栈已经开在那儿了,也没有进一步的函数调用,根本节约不了一丁点内存。

3.       相反,由于计算步骤较多,会使用更多的指令,编译后的机器码长度会增加。(这不是什么大问题,短的代码不一定快,后面有另外一个例子。)

 

详细可见:http://blog.csdn.net/do2jiang/article/details/4549679

      http://blog.csdn.net/solstice/article/details/5166912

 

关于优化,引用其他博主的观点:

http://www.php100.com/html/webkaifa/PHP/PHPyingyong/2012/1224/11834.html
“过早的优化是万恶之源”,当我们没有确定程序影响性能最重要的20%代码时,最好不要进行优化。同时,在优化时,不要过于相信经验,因为CPU技术,编译技术,操作系统等等,都会让看似可行的技术,失效。
在优化前,通过实际的运行确定影响性能的代码,然后进行优化。
编译器很强大,CPU技术进步很快,我们的经验积累反而是最慢的。多反思,多总结。

 

 

但是面试的时候可能会出这个无聊的题目,记住位运算交换之前一定要判断两个值是否相等,这是个小陷阱。

转载于:https://www.cnblogs.com/zhangmingzhao/p/7854083.html

你可能感兴趣的文章
kafka 主要内容介绍
查看>>
Linux获取网页源码的几种方法
查看>>
write a python http server & client
查看>>
并非全部的程序猿都适合做技术管理
查看>>
jQuery 效果 - 淡入淡出
查看>>
SSDB图形界面管理工具:phpssdbadmin安装部署
查看>>
how to backup and restore database of SQL Server
查看>>
Hibernate- QBC查询方式
查看>>
【Linux】linux查看日志文件内容命令tail、cat、tac、head、echo
查看>>
php中的或运算
查看>>
位图(BitMap)索引
查看>>
CSS3伪类和伪元素的特性和区别
查看>>
vue实现文章内容过长点击阅读全文功能
查看>>
记一次elementUI Icon 加载无效的问题。并且提示错误 Failed to decode downloaded font:
查看>>
OpenGL之位图的绘制和gluOrtho2D等函数详解
查看>>
Linux磁盘概念及其管理工具fdisk
查看>>
Linux epoll版定时器
查看>>
objective C中数据持久化方式1--对象归档
查看>>
Python面向对象编程 - 一个记事本程序范例(一)
查看>>
马桶餐厅
查看>>