zoukankan      html  css  js  c++  java
  • 异或交换真的比开一个tmp快吗?

      在以前学习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从内存载入寄存器eax
    movl        a, %ecx       ;将a从内存载入寄存器ecx
    movl        %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技术进步很快,我们的经验积累反而是最慢的。多反思,多总结。

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

  • 相关阅读:
    CentOs下Mongodb的下载与安装
    Mysql的sql_mode
    【Android】无限滚动的HorizontalScrollView
    Android 交错 GridView
    Android文档资源大放送 感兴趣的话可以网盘下载(个人收集)
    2014年最新720多套Android源码2.0GB免费一次性打包下载
    安卓开发之刮刮乐实例教程
    Android捕获崩溃异常
    Android -- Messager与Service
    Git的简单使用
  • 原文地址:https://www.cnblogs.com/zhangmingzhao/p/7854083.html
Copyright © 2011-2022 走看看