zoukankan      html  css  js  c++  java
  • 两个变量交换的三种方法的反汇编比较

    先说结论:不开编译器优化的前提下,三变量交换法效率最高;开了优化后没区别。
    起因:
    学了点汇编的皮毛,想看看两变量交换的底层到底是怎么实现的。
    主体代码:

    //三变量交换法
    int t = a;
    a = b;
    b = t;
    //两减一加法
    a = a + b;
    b = a - b;
    a = a - b;
    //异或法
    a ^= b;
    b ^= a;
    a ^= b;
    

    用VS2017进行反汇编

    排版整理得

    //三变量交换法
    int t = a;a = b;b = t;
    mov		eax,a  
    mov		t,eax  
    mov		eax,b  
    mov		a,eax  
    mov		eax,t  
    mov		b,eax 
    
    //两减一加法
    a = a + b; b = a - b; a = a - b;
    mov		eax,a  
    add		eax,b  
    mov		a,eax  
    mov		eax,a  
    sub		eax,b  
    mov		b,eax  
    mov		eax,a  
    sub		eax,b  
    mov		a,eax
    
    //异或法
    a ^= b;b ^= a;a ^= b;
    mov		eax,a  
    xor		eax,b  
    mov		a,eax  
    mov		eax,b  
    xor		eax,a  
    mov		b,eax  
    mov		eax,a  
    xor		eax,b  
    mov		a,eax 
    

    观察可知,每种方法都用到了六条mov指令,但后两种方法却还用到了其他的指令。
    这打破了我的常规认知:用的变量越少,算法效率越高。
    不,也不是完全推翻,毕竟后两种方法确实是减少了内存开销,有着更低的空间复杂度,虽然只有一个变量那么大。。。。。。这算是哪门子节约啊。

    我原先觉得异或法最快,因为二进制操作快,因为计算机底层就是二进制运算。而且很多的初学者也是迷信二进制,这种对二进制效率的盲目认知使我写了的a ^= b ^= a ^= b,但我从来没有实验过。
    那么接下来就实地测量一下:

    #include <cstdio>
    #include <iostream>
    #include <windows.h>
    using namespace std;
    int a = 0,b=0;
    void fun1() {
    	for (int i = 0; i < 1000000000; i++) {
    		int t = a;
    		a = b;
    		b = t;
    	}
    }
    void fun2() {
    	for (int i = 0; i < 1000000000; i++) {
    		a = a + b;
    		b = a - b;
    		a = a - b;
    	}
    }
    void fun3(){
    	for (int i = 0; i < 1000000000; i++) {
    		a = a ^ b;
    		b = a ^ b;
    		a = a ^ b;
    	}
    }
    int main()
    {
    	a = 10;
    	b = 12;
    	long t1 = GetTickCount();
    	fun1();
    	long t2 = GetTickCount();
    	fun2();
    	long t3 = GetTickCount();
    	fun3();
    	long t4 = GetTickCount();
    	cout << t2 - t1 << '
    ' << t3 - t2<< '
    ' << t4 - t3;
    	return 0;
    }
    

    我的CPU是Core i5-6200U,windows系统,编译器是g++,跑出来的结果是

    fun1: 2937
    fun2: 5781
    fun3: 5594
    

    为了排除函数执行顺序的影响,我交换了三个函数的顺序又测试了两遍

    fun3: 5703
    fun1: 2875
    fun2: 5891
    
    fun2: 5937
    fun3: 5703
    fun1: 2844
    

    结果很明显了,三变量交换法速度是另外两种方法的近乎两倍。

    后记:
    翻了CSDN,发现前人也思考过这个问题。有很多人说异或快,也有人说异或慢。但说快的一般都是拿二进制来说事,没有深入分析,甚至连测个速都没有。反观说异或慢的,深入至汇编,给出了严谨详细的证明,有理有据,令人信服。
    譬如下面的二位前辈:
    两个变量交换的扩展思考
    用异或来交换两个变量是错误的

    感想颇多,想说的也很多,但还是老祖宗看的透彻,一言以蔽之:

    纸上学来终觉浅,绝知此事要躬行

    原写于2019年06月17日 23:41:45

  • 相关阅读:
    podium服务器端的微前端开发框架
    几个java proxy servlet 工具
    Presto Infrastructure at Lyft
    cube.js 通过presto-gateway 进行连接
    presto-gateway nodejs client
    presto-gateway 试用以及docker 镜像制作
    presto-gateway lyft 团队开源的prestodb 的负载均衡、代理、网关工具
    Singer 修改tap-s3-csv 支持minio 连接
    plotly-dash 简单使用(一)
    smashing 三方widgets 使用
  • 原文地址:https://www.cnblogs.com/kangyupl/p/13525246.html
Copyright © 2011-2022 走看看