《深入理解计算机系统》第二章

 

一、布尔代数和环

利用^(异或)的环属性实现变量的交换。

void inplace_swap(int *x, int *y){
      *x = *x ^ *y;
      *y = *x ^ *y;
      *x = *x ^ *y;
}

 正如上面这段程序,看上去是来来回回的同样一种运算甚至连运算数都一样。但是就是这样三行代码达到了交换x和y指向的数据值的效果。

让我们来简单分析一下这个程序的具体过程吧:

步骤 *x *y
初始 a b
第一步 a^b b
第二步 a^b a^b^b=a^0=a
第三步 a^b^a=a^a^b=0^b=b a

 

 

 

 

 

 

 

 

 

不错这样看来,这个程序从表象三看好像是省去了一个空间,但是从汇编码等底层实现上看没有任何性能上的优势。下面我们看看这段代码的汇编码:

 

汇编代码 写道
.file "inplace_swap.c"
.text
.globl inplace_swap
.type inplace_swap, @function
inplace_swap:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movl (%eax), %edx
movl 12(%ebp), %eax
movl (%eax), %eax
xorl %eax, %edx
movl 8(%ebp), %eax
movl %edx, (%eax)
movl 8(%ebp), %eax
movl (%eax), %edx
movl 12(%ebp), %eax
movl (%eax), %eax
xorl %eax, %edx
movl 12(%ebp), %eax
movl %edx, (%eax)
movl 8(%ebp), %eax
movl (%eax), %edx
movl 12(%ebp), %eax
movl (%eax), %eax
xorl %eax, %edx
movl 8(%ebp), %eax
movl %edx, (%eax)
popl %ebp
ret


.size inplace_swap, .-inplace_swap
.globl swap
.type swap, @function
swap:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl 8(%ebp), %eax
movl (%eax), %edx
movl -4(%ebp), %eax
movl %edx, (%eax)
movl 12(%ebp), %eax
movl (%eax), %edx
movl 8(%ebp), %eax
movl %edx, (%eax)
movl -4(%ebp), %eax
movl (%eax), %edx
movl 12(%ebp), %eax
movl %edx, (%eax)
leave
ret


.size swap, .-swap
.section .rodata
.LC0:
.string "Old: x=%d,y=%d\n"
.LC1:
.string "New: x=%d,y=%d\n"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $36, %esp
movl $1, -8(%ebp)
movl $2, -12(%ebp)
movl -12(%ebp), %eax
movl %eax, 8(%esp)
movl -8(%ebp), %eax
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
movl -12(%ebp), %eax
movl -8(%ebp), %edx
movl %eax, 4(%esp)
movl %edx, (%esp)
call inplace_swap
movl -12(%ebp), %eax
movl %eax, 8(%esp)
movl -8(%ebp), %eax
movl %eax, 4(%esp)
movl $.LC1, (%esp)
call printf
movl $0, %eax
addl $36, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.2.4 (Ubuntu 4.2.4-1ubuntu1)"
.section .note.GNU-stack,"",@progbits
 

从这个问题上,我们获得启发:

  1. 分析程序的性能不能简单通过源程序判断,需要深入底层看看汇编码甚至于和OS硬件有关的指令执行状况
  2. 数学之美无处不在,一种根本无法想像的东西通过数学上代数环的性质迎刃而解
  3. 对于程序的分析如果发现逻辑不清,应当借助表格等工具静心一步一步的分析
  4. 配置Gedit让汇编码高亮 http://qianjigui.iteye.com/blog/248085

二、浮点运算的不精确性

   需要非常小心地使用浮点运算,因为浮点运算的范围和精度有限,而且浮点运算不遵守普通的算术性质,比如结合性。

 

未完待续

 

 

你可能感兴趣的:(ubuntu,Blog,gcc,OS)