从汇编指令解决浮点数疑问

x87 FPU

:本文默认使用x87 FPU指令
注:x87 FPU特指与x86处理器配套的浮点协处理器架构

–浮点寄存器采用栈结构

  • 深度为8,宽度为80位,即8个80位寄存器
  • 名称为 ST(0) ~ ST(7),栈顶为ST(0),编号分别为 0~7

–所有浮点运算都按80位扩展精度进行

–浮点数在浮点寄存器和内存之间传送

  • float、double、long double型变量在内存分别用IEEE 754单精度、
    双精度和扩展精度表示,分别占32位(4B)、64位(8B)和96位(12B,其中高16位无意义)
  • float、double、long double类型变量在浮点寄存器中都用80位扩展精度表示
  • 从浮点寄存器到内存:80位扩展精度格式转换为32位或64位
  • 从内存到浮点寄存器:32位或64位格式转换为80位扩展精度格式

浮点处理指令

•数据传送类
(1) 装入(转换为80位扩展精度)
	FLD:将数据从存储单元装入浮点寄存器栈顶 ST(0)
	FILD:将数据从int型转换为浮点格式后,装入浮点寄存器栈顶
(2) 存储(转换为IEEE 754单精度或双精度)
	FSTx:x为s/l时,将栈顶ST(0)转换为单/双精度格式,然后存入存储单元
	FSTPx:弹出栈顶元素,并完成与FSTx相同的功能
	FISTx:将栈顶数据从int型转换为浮点格式后,存入存储单元
	FISTP:弹出栈顶元素,并完成与FISTx相同的功能
带P结尾指令表示操作数会出栈,也即ST(1)将变成ST(0)
(3) 交换
	FXCH:交换栈顶和次栈顶两元素
(4) 常数装载到栈顶
	FLD1:装入常数1.0
	FLDZ:装入常数0.0
	FLDPI:装入常数pi (=3.1415926...)
	FLDL2E :装入常数log(2)e
	FLDL2T:装入常数log(2)10
	FLDLG2 :装入常数log(10)2
	FLDLN2:装入常数Log(e)2
	
•算术运算类
(1)加法
	FADD/FADDP:相加/相加后弹出栈
	FIADD:按int型转换后相加
(2)减法
	FSUB/FSUBP:相减/相减后弹出栈
	FSUBR/FSUBRP:调换次序相减/相减后弹出栈
	FISUB:按int型转换后相减
	FISUBR:按int型转换并调换次序相减
若指令未带操作数,则默认操作数为ST(0)、ST(1)
带R后缀指令是指操作数顺序变反,例如:fsub执行的是x-y,fsubr执行的就是y-x
(3) 乘法
	FMUL/FMULP: 相乘/相乘后弹出栈
	FIMUL:按int型转换后相乘
(4) 除法
	FDIV/FDIVP : 相除/相除后弹出栈
	FIDIV:按int型转换后相除
	FDIVR/FDIVRP:调换次序相除/相减后弹

问题一

1
(右边多一条赋值语句)
问题:使用老版本gcc -O2 编译时,程序一输出0,程序二输出1,是什么原因造成的?

  • 先看函数的汇编
    2
    fld1:即将常数1.0压入栈顶ST(0)
    fidivl:将指定的操作数epb寄存器内容+8地址中的01序列(即int x 此时为10),中的int型转换为double型,再将ST(0) (1.0)除以该数,并将结果存入ST(0)中

  • f(10)
    f(10)=1.0(80位扩展精度)/10(转换为double)=0.1
    0.1=0.00011[0011]B无限循环小数无法精确表示

  • 程序一
    a=f(10);
    b=f(10);
    i=a==b;
    3
    a=f(10);
    把10作为参数调用函数,计算的结果赋给a,把f(10)存到0xfffffff8开始的64位单元中(即a的地址)
    即从80位->64位
    b=f(10);
    同样把10作为参数调用函数,此时fldl把64位的a重入栈顶,即64位->80位,此时b在ST(1),
    然后fucompp比较ST(0)和ST(1),b仍为80位
    所以此时a!=b

  • 程序二
    a=f(10);
    b=f(10);
    c=f(10;
    i=a==b;
    4
    可以发现,a,b都先存入内存,80位->64位,c一直在浮点寄存器中,然后比较前a,b都入栈,即c到ST(2),a到ST(1),b到ST(0),ab同时从64位->80位所以比较时相等。

问题二

5
不都是强制转换吗?怎么会不一样?
关键差别为fldl和fildl
6
相信大家看了汇编代码后已经有了答案


参考:南大计算机系统基础(一)

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值