曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 4643|回复: 0
打印 上一主题 下一主题

基本浮点运算

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
跳转到指定楼层
楼主
发表于 2010-3-6 00:52:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
FPU 提供对浮点值执行基本数学功能的指令:
指令
描述
FADD
浮点加法
FDIV
浮点除法
FDIVR
反向浮点除法
FMUL
浮点乘法
FSUB
反向减法
FSUBR
反向浮点减法
实际上,这些功能的每一个都具有单独的指令和格式,可以生成 6 个可能的功能,这取决于希望执行的确切操作是什么。例如,FADD 指令可以如下使用:
      FADD source : 内存中的 32 位或者 64 位值和 ST0 寄存器相加
      FADD %st(x), %st(0) : st(x) 和 st(0) 相加,结果存储到 st(0) 中
      FADD %st(0), %st(x) : st(0) 和 st(x) 相加,结果存储到 st(x) 中
      FADDP %st(0), %st(x) : st(0) 和 st(x) 相加,结果存储到 st(x) 中,并且弹出 st(0)
      FADDP : st(0) 和 st(1) 相加,结果存储到 st(1) 中,并且弹出 st(0)
      FIADD source : 16 位或者 32 位整数值和 st(0) 相加,结果存储到 st(0) 中
注意,GNU 的源和目标操作数的顺序是和 Intel 语法中的顺序相反的。

下面用程序计算 ((43.65 / 32) + (74.34 + 3.1)) / ((12.43 * 6) - (140.2 / 94.21)) ,程序代码如下:
.section .data
value1:
    .float 43.65
value2:
    .int 22
value3:
    .float 76.34
value4:
    .float 3.1
value5:
    .float 12.43
value6:
    .int 6
value7:
    .float 140.2
value8:
    .float 94.21
output:
    .asciz "The result is %f\n"

.section .text
.global _start
_start:
    nop
    finit
    flds value1
    fidiv value2
    flds value3
    flds value4
    fmul %st(1), %st(0)
    fadd %st(2), %st(0)
    flds value5
    fimul value6
    flds value7
    flds value8
    fdivrp
    fsubr %st(1), %st(0)
    fdivr %st(2), %st(0)
    subl $8, %esp
    fstpl (%esp)
    pushl $output
    call printf
    add $12, %esp
    pushl $0
    call exit
编译连接运行及输出
$ as -gstabs -o fpmath.o fpmath.s
$ ld -dynamic-linker /lib/ld-linux.so.2 -lc -o fpmath fpmath.o
$ ./fpmath
The result is 73.091837
程序说明
finit : 初始化 FPU 寄存器

flds value1 : 将 43.65 加载到 st0 中

fidiv value2 : 43.65/22 ,结果(1.98409)保存在 st0 中

flds value3 : 76.34 入栈并保存在 st0 ,1.98409 移到 st1 中

flds value4 : 3.1 入栈保存到 st0 中,76.34 移动到 st1,1.98409 移动到 st2

fmul %st(1), %st(0) : 76.34 * 3.1 = 236.654 ,这个结果保存到 st0

fadd %st(2), %st(0) : 236.654 + 1.98409 = 238.63809,这个结果保存到 st0

flds value5 : 12.43 压入 st0, 238.63809 被移动到 st1

fimul value6 : 12.43 * 6 = 74.58,结果保存在 st0

flds value7 : 140.2 入栈,存入到 st0 中, 74.58 被移到 st1,238.63809 被移到 st2

flds value8 : 94.21 入栈,存入到 st0,st1 中为 140.2, st2 中为 74.58,st3 中为 238.63809

fdivrp : 这是个反向除法指令(指令中的 r 表示反向 reverse)。 fdiv 指令(fdivp 也一样)如果不解操作数,那么它的执行过程是,先弹出 st0 和 st1,然后运算 st0/st1,然后将结果(商)再压回堆栈中。fdivrp 的运算过程是,先弹出 st0 和 st1,然后执行反向运算,即运算 st1/st0 ,最后将结果(商)压回堆栈。所以,执行这个指令后,堆栈中的值为 st0=1.48816(st1/st0=140.2/94.21=1.48816); st1=74.58;st2=238.63809。

fsubr %st(1), %st(0) : 执行反向运算,即 st1-st0,结果存入目标操作数即 st0。堆栈中的顺序变为:st0=73.09184, st1=74.58, st2=238.63809。

fdivr %st(2), %st(1) : 执行反向运算,即 st2/st1,结果存入到 st0 中,到此整个式子计算结束,st0 中的值为 3.264907 。

subl $8, %esp
fstpl (%esp)    : 因为 fstpl 存入的是双精度值(8字节),所以这里堆栈指针要先减去8

pushl $output : 压入输出字符串的地址

add $12, %esp : 上面压入的地址是 4 个字节,再加上压入结果的 8 个字节,共 12 个字节,当 printf 输出后,恢复堆栈。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-5-14 10:26 , Processed in 0.074777 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表