第46部分-Linux x86 64位汇编 斐波那契

斐波那契数列

斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从 1963 年起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。

C语言版本
#include "stdio.h"
unsigned long Fibon1(int n)
{
	if (n == 1 || n == 2)
	{
		return 1;
	}
	else
	{
		return Fibon1(n - 1) + Fibon1(n - 2);
	}
}
int main()
{
	int n = 0;
	unsigned long ret = 0;
	//scanf("%d", &n);
	n=50;
	ret = Fibon1(n);
	printf("ret=%lu\n", ret);
	return 0;
}

可以直接编译运行。

#gcc -o fibo-c fibo.c

# time ./fibo-c

ret=12586269025

 

real   1m9.897s

user    1m9.931s

sys 0m0.020s

Nasm版本
extern printf ;//调用外部的printf函数
section .data
   fmt db "result is: %lu ", 0xa

global _start

fibo:

    push rbx
    push rdx
    cmp rax, 1
    je _get_out
    cmp rax, 2
    je _get_out;//相当于if(n == 1 || n == 2) return 1;

    mov rdx, rax;//相当于if(n!=1&&n!=2),先保存rax
    sub rax, 1
    call fibo;//相当于fibo(n-1)
    mov rbx, rax;//保存fibo(n-1)结果到rbx

    mov rax, rdx;//获取rax值。
    sub rax, 2
    call fibo;//相当于fibo(n-2)
    mov rcx, rax;//保存fibo(n-2)到rbx

    mov rax, rbx
    add rax, rcx;//fibo(n-1)+fibo(n-2)

    pop rdx
    pop rbx
    ret

_get_out:
    pop rdx
    pop rbx
    mov rax, 1
    ret;//直接返回fibo函数

_start:
    mov rax, 50 ;//求数列中第七个数
    call fibo
    mov rdi,fmt
    mov rsi,rax
    call printf
	
    mov rax,60
    syscall

nasm  -f elf64 -o fibo.o fibo.asm

ld -o fibo fibo.o -lc -I /lib64/ld-linux-x86-64.so.2

 

# time ./fibo

result is: 12586269025

real    0m41.641s

user    0m41.639s

sys 0m0.000s

 

Gas版本
.extern printf ;//调用外部的printf函数
.section .data
   fmt: .ascii  "result is: %lu \n"

.global _start

fibo:

    push %rbx
    push %rdx
    cmp $1,%rax
    je _get_out
    cmp $2,%rax
    je _get_out;//相当于if(n == 1 || n == 2) return 1;

    mov %rax, %rdx;//相当于if(n!=1&&n!=2),先保存rax
    sub $1,%rax
    call fibo;//相当于fibo(n-1)
    mov %rax, %rbx;//保存fibo(n-1)结果到rbx

    mov %rdx, %rax;//获取rax值。
    sub $2,%rax
    call fibo;//相当于fibo(n-2)
    mov %rax, %rcx;//保存fibo(n-2)到rbx

    mov %rbx, %rax
    add %rcx, %rax;//fibo(n-1)+fibo(n-2)

    pop %rdx
    pop %rbx
    ret

_get_out:
    pop %rdx
    pop %rbx
    mov $1,%rax
    ret;//直接返回fibo函数

_start:
    mov $50,%rax ;//求数列中第七个数
    call fibo
    mov $fmt,%rdi
    mov %rax,%rsi
    call printf
	
    mov $60,%rax
    syscall

编译连接:

as -g -o fibo_att.o fibo_att.s

ld -o fibo_att fibo_att.o -lc -I /lib64/ld-linux-x86-64.so.2

# time ./fibo_att

result is: 12586269025

 

real    0m41.625s

user    0m41.623s

sys 0m0.000s

 

性能差异

 

Nasm汇编

Gas汇编

C语言

C语言-O1

编译优化

C语言-O2

编译优化

执行时间

41.6s

41.6s

1m0.876s

NA,异常

NA,异常

可以看到汇编程序编译后的明显性能优势。性能提升31.5%。

使用GCC的-O参数优化后会影响程序本身的功能。