sh-5.1$ ls
main.c main.s old
sh-5.1$ cat main.c
#include <stdio.h>
#include <math.h>
double get_n(void) {
size_t n; scanf("%zu", &n);
double s = 0;
for(size_t i = 1; i <= n; ++i) {
double x = pow(i, 0.5);
s += i % 2 == 0 ? -x : x;
}
return s;
}
int main(void) {
printf("%f\n", get_n());
return 0;
}
sh-5.1$ cat main.s
.section .text
.global _start
_start:
# 调用read系统调用
# 从标准输入读取一个数字,是字符串类型的
# 存储到buff中
movq $0, %rax # sys_read
movq $0, %rdi # stdin
leaq buff(%rip), %rsi # buff
movq $1024, %rdx # count
syscall
# 下面把buff中的字符串转换成数字
decq %rax # '\n'
movq %rax, %rcx
xorq %rax, %rax
movq $10, %rdi
1: mulq %rdi # rax *= 10
movzbq (%rsi), %rdx # dl = *(%rsi)
incq %rsi
subq $'0', %rdx
addq %rdx, %rax
decq %rcx
cmpq $0, %rcx
jg 1b
movq %rax, %r8
# 下面计算表达式的值
movq $1, %rcx
fldz
2: movq %rcx, temp(%rip)
fildq temp(%rip)
fsqrt # i的0.5次方就是对i开方
fst %st(2)
fchs
testq $1, %rcx
fcmovne %st(2), %st(0)
faddp
incq %rcx
cmpq %r8, %rcx
jng 2b
ffree %st(1)
# 下面把计算结果转换成字符串
# 首先判断浮点数是不是负数
# 如果是负数的话,要在字符串最前面加 '-'
leaq buff(%rip), %rsi
movb $'-', (%rsi)
leaq 1(%rsi), %rax
fldz
fcomip %st(1), %st(0)
cmovaq %rax, %rsi
# 然后把整数部分和小数部分分开
fld %st(0)
fisttpq temp(%rip)
fildq temp(%rip)
fsubrp
fabs
fildq temp(%rip)
fabs
# 接下来处理整数部分
3: fld %st(0)
movq $10, temp(%rip)
fildq temp(%rip)
fxch
fprem
fisttpq temp(%rip)
movb temp(%rip), %al
addb $'0', %al
movb %al, (%rsi)
incq %rsi
fdivrp
fisttpq temp(%rip)
fildq temp(%rip)
cmpq $0, temp(%rip)
ja 3b
fisttpq temp(%rip)
# 上面弄出来的整数部分顺序是反的
# 这里反序整数部分
leaq buff(%rip), %rbx
leaq 1(%rbx), %rax
cmpb $'-', (%rbx)
cmoveq %rax, %rbx
leaq -1(%rsi), %rdi
4: movb (%rbx), %al
movb (%rdi), %ah
movb %al, (%rdi)
movb %ah, (%rbx)
incq %rbx
decq %rdi
cmpq %rbx, %rdi
ja 4b
# 下面处理小数部分
# 保留小数点后15位
movb $'.', (%rsi)
incq %rsi
movq $15, %rcx
movq $10, temp(%rip)
fildq temp(%rip)
fxch
5: fmul %st(1), %st(0)
fld %st(0)
fisttpq temp(%rip)
movb temp(%rip), %al
addb $'0', %al
movb %al, (%rsi)
incq %rsi
fildq temp(%rip)
fsubrp
decq %rcx
cmpq $0, %rcx
ja 5b
# 字符串最后加一个 '\n'
movb $'\n', (%rsi)
incq %rsi
# 调用write系统调用输出字符串
movq $1, %rax # sys_write
movq $1, %rdi # stdout
movq %rsi, %rdx
leaq buff(%rip), %rsi # buff
subq %rsi, %rdx # count
syscall
# 调用exit系统调用退出程序
movq $60, %rax # sys_exit
movq $0, %rdi # status
syscall
retq
.section .bss
buff: .zero 1024
temp: .zero 8
sh-5.1$ gcc -O3 -g -Wall -o c main.c -lm
sh-5.1$ as -O3 -g -o asm.o main.s
sh-5.1$ ld -o asm asm.o
sh-5.1$ ls
asm asm.o c main.c main.s old
sh-5.1$ time ./c <<EOF
> 999999999
> EOF
15811.768402
real 0m20.280s
user 0m20.241s
sys 0m0.004s
sh-5.1$ time ./asm <<EOF
999999999
EOF
15811.768401701640368
real 0m2.343s
user 0m2.332s
sys 0m0.004s
sh-5.1$ time ./c <<EOF
999999999
EOF
15811.768402
real 0m21.210s
user 0m21.080s
sys 0m0.020s
sh-5.1$ time ./asm <<EOF
999999999
EOF
15811.768401701640368
real 0m2.476s
user 0m2.429s
sys 0m0.007s
sh-5.1$