主题:【原创】继续关于swap的讨论 -- 不锈钢破锣
- 共: 💬 22 🌺 5
不过,讲究速度的,一般都是下层的应用,CODE不大。。(虽然全系统全部CODE 可能很大)。。。如果用c++写的,SIZE恐怕不小,少几条指令也好不了多少。。。这个我是瞎猜的。。。如果你有例子反驳一下,最好。。。
也许速度从两秒减少到一秒,不算什么。
但是我的有些应用问题要用几十个CPU
并行计算几个月才有结果。这样,两个月
和四个月的区别还是很大的,所以在速度上
需要很“抠门儿”。呵呵。
具体例子太繁琐了,如果有时间我简化一下
贴上来。还是蛮有意思的。
那为什么现在比较常用的方法还是使用临时变量呢?两个原因,一个是赋值运算比逻辑运算的速度更快;另一个是在编程方面,使用临时变量可读性更高。
更重要的原因,如果a,b是一个复杂的object,后两种做法很可能就不work,因为一般class的design,通常都会实现operator=(),而不一定会实现operator+, operator-,几乎很少会实现XOR operator。
因此第一种做法是上面唯一一个能handle generic case的,同时您也提到了,可读性好,效率也不差(实际上如果a,b是object,效率应该比后两种更好)。
严格说来,后两种做法(不使用临时变量),是违反软件工程的基本原则,因为会使code reusability大幅度降低,也不容易维护。
除了在interview中刻意为难一下Interviewee,实际编程工作中,一般不会用后两种做法。
寄存器在CPU内部,这样就不需要完成内存送到reg和reg存回内存这个步骤了,运算速度提高的不是一点半点,特别是复杂的算术运算。直接内存读取当然可以,但是人家编译器多半不肯那,。
其次,编译器在生成中间代码的时候,会采用线性优化的方法来分配寄存器,是否会多分配出一个Reg取决于最后优化的结果。所以对于使用临时变量的那段代码,这里的temp是占有一个内存空间还是寄存器很难说。
可能的一个结果就是给a或者b一个reg,其余在内存中完成操作。
---------------
LOAD a R0;
MOV b a;
MOV R0 b;
---------------
不使用temp的情况下,编译器多半就照着代码翻,加法和赋值的开销基本是一样的,所以代码可能不变。同样的,分配寄存器按照上面说的来进行。
楼主的东东是在机器语言才可比较
机器语言里(说错了的只管扔鸡蛋上来,俺有篮子接)
temp=a;
a=b;
b=temp.
是这样做的
控制器控制寄存器a放a
控制器控制寄存器b放b
控制器控制寄存器a取a给寄存器c放a
控制器控制寄存器b取b给寄存器a放b
控制器控制寄存器c取a给寄存器b放a
a = a+b;
b = a-b;
a = a-b;
是这样走
控制器控制寄存器a放a
控制器控制寄存器b放b
控制器控制寄存器a取a 寄存器b取b 给计算器计算a+b
控制器控制 计算器把a+b=A送寄存器a放A
控制器控制 寄存器a取A 寄存器b取b 给计算器计算A-b a+b-b
控制器控制 计算器把A-b=a送寄存器b放a
控制器控制 寄存器a取A 寄存器b取a 给计算器计算A-a a+b-a
控制器控制 计算器把A-b=b送寄存器a放b
所以牺牲空间换时间,牺牲时间换空间
a和b可能是同一个地址的引用,例如在选择排序或是洗牌算法中调用swap(a[i], a[j])时可能i与j相等。
如果我没记错的话,TAOCP里的题目是有所不同的,所以我不是说K大的答案有问题。
如果是支持赋值表达式的语言,可以有如下的答案:
a = a + b - (b = a);
但这个方法和“经典答案”一样,如同楼下有人提到的,从编译器偷了临时变量。
这种题和IOCCC一样,作为趣味智力题就很好,但并不适合在实际中使用。
另外,我认为仅这个题目是上纲不到“计算机科学”的,对照自然科学的说法,说是属于“计算机工程”或“应用计算机学”比较合适。
应该在计算机结构(computer architecture)的范围内讨论比较有意义。否则编译软件的优化很可能把你的各种办法都优化成相同的代码了。
事实上如果我们假设a,b都是寄存器变量的话,不少处理器都可以直接提供交换指令。例如x86处理器的
"xchg ax,bx;"
就是交换两个16位寄存器的内容。
通常情况是,在使用临时变量作显式交换时,编译软件较容易判断出程序员的目的,从而直接使用交换指令。