高級的數學方法

FPU環境

  • FPU 寄存器棧
    • 8個80位的數據寄存器(R0~R7)
      • 特點
        • 不能通過名字訪問
        • 寄存器是環形的
    • 16位的狀態寄存器
      • 狀態位
狀態位 描述
0 不合法的操作
1 不規範化的操作
2 除數爲0的異常
3 上溢出異常
4 下溢出異常
5 精度異常
6 棧錯誤
7 錯誤總體狀態
8 狀態碼C0
9 狀態碼C1
10 狀態碼C2
11~13 棧頂指針
14 狀態碼C3
15 FPU忙標誌
	* 示例
# getstatus.s - Get the FPU Status register contents
.section .bss
	.lcomm status, 2
.section .text
.globl _start
_start:
	nop
	fstsw %ax
	fstsw status

	movl $1, %eax
	movl $0, %ebx
	int $0x80
* 16位的控制寄存器
	* 狀態位
控制位 描述
0 不合法的操作異常掩碼
1 不合規範的操作異常掩碼
2 除於0異常掩碼
3 上溢出異常掩碼
4 下溢出異常掩碼
5 精度異常掩碼
6-7 保留
8-9 精度控制
10-11 湊整控制
12 無窮控制
13-15 保留
* 精度控制
描述
00 單精度(24位有效位)
01 沒有使用
10 雙精度(53位有效位)
11 雙擴展精度(64位有效位)default
* 湊整控制
描述
00 向最近值取整 default
01 向下取整
10 向上取整
11 向0取整
* 示例
# setprec.s - An example of setting the precision bits in the Control Register
.section .data
newvalue:
	.byte 0x7f, 0x00
.section .bss
	.lcomm control, 2
.section .text
.globl _start
_start:
	nop
	fstcw control
	fldcw newvalue
	fstcw control
	
	movl $1, %eax
	movl $0, %ebx
	int $0x80
* 16位的標籤寄存器
	* 格式
14-15 12-13 10-11 8-9 6-7 4-5 2-3 0-1
R7 R6 R5 R4 R3 R2 R1 R0
	* 值
		* 00 : 合法的雙擴展精度值
		* 01 : 零值
		* 10 : 一個特殊的單精度值
		* 11 : 空值
	
* 使用FPU棧
	* 示例
# stacktest.s - An example of working with the FPU stack
.section .data
value1:
	.int 40
value2:
	.float 92.4405
value3:
	.double 221.440321
.section .bss
	.lcomm int1, 4
	.lcomm control, 2
	.lcomm status, 2
	.lcomm result, 4
.section .text
.globl _start
_start:
	nop
	finit
	fstcw control
	fstsw status
	filds value1
	fists int1
	flds value2
	fld1 value3
	fst %st(4)
	fxch %st(1)
	fstps result
	movl $1, %eax
	movl $0, %ebx
	int $0x80
	* 說明
		FINIT : 初始化狀態和控制寄存器
		FILDS :  將一個雙字整數放入FPU寄存器
		FISTS : 檢索棧頂元素,並放入目的地址
		FLDS: 將一個單精度的浮點數放入寄存器
		FLDL:  將一個雙精度的浮點數放入寄存器
		FST: 將ST0寄存器的值存入另外一個寄存器,不取出棧頂元素
		FSTP: 取出棧頂值並放入另外一個寄存器
		FXCH: 用於和ST0寄存器交換元素

基本的浮點數運算

  • 運算
指令 描述
FADD 浮點數加法
FDIV 浮點數除法
FDIVR 逆向浮點數加法
FMUL 浮點數乘法
FSUB 浮點數減法
FSUBR 逆向浮點數減法
* 指令描述
	FADD source :  source + ST0 -> ST0
	FADD %st(x), %st(0)  : STX + ST0 -> ST0
	FADD %st(0) , %st(x) : ST0 + STX -> STX
	FADDP %st(0), %st(x) : ST0 + STX -> STX, pop ST0
	FADDP : ST0 + ST1 -> ST1, pop ST0
	FIADD source : source( 16 or 32 bits int) + ST0 -> ST0
  • 示例
# ((43.65 / 22) + (76.34 * 3.1)) / ((12.43 * 6) - (140.2 / 94.21))
# fpmath.s - An example of basic FPU math
.section .data
value1:
	.float 43.65
value2:
	.int 22
value3:
	.float 76.34
value4:
	.float 3.1
value5:
	.float 12.43
value6:
	.float 6
value7:
	.float 140.2
value8:
	.float 94.21
output:
	.asciz "The result is %f\n"
.section .text
.globl _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

高級的浮點數運算

指令 描述
F2XM1 計算ST0的2次方,然後減一
FABS 計算ST0的絕對值
FCHS 對ST0的值取反
FCOS 計算ST0的餘弦值
FPATAN 計算ST0的局部飯正切
FPREM 計算ST0/ST1的餘數
FPREM1 計算ST0/ST1的IEEE格式餘數
FPTAN 計算ST0的正切
FRNDINT 四捨五入ST0到整數
FSCAL 計算ST0的ST1次方
FSIN 計算ST0的正弦
FSINCOS 計算ST0的正弦和餘弦
FSQRT 計算ST0的平方根
FYL2X 計算ST1*logST0(base 2)
FYL2XP1 計算ST1*log(ST0+1)(base 2)
  • 示例
# fpmath2.s - An example of the FABS, FCHS, and PSQRT instructions
.section .data
value1:
	.float 395.21
value2:
	.float -9145.290
value3:
	.float 64.0
.section .text
.globl _start
_start:
	nop
	finit
	flds value1
	fchs
	flds vlaue2
	fabs
	flds value3
	fsqrt

	mov $1, %eax
	mov $0, %ebx
	int $0x80

(gdb) info all

# roundtest.s - An example of the FRNDINT instruction
.section .data
value1:
	.float 3.65
rdown:
	.byte 0x7f, 0x07
rup:
	.byte 0x7f, 0x0b
.section .bss
	.lcomm result1, 4
	.lcomm result2, 4
	.lcomm result3, 4
.section .text
.globl _start
_start:
	nop
	finit
	flds value1
	frndint
	fists result1

	fldcw rdown
	flds value1
	frndint
	fists result2

	fldcw rup
	flds value1
	frndint
	fists result3

	movl $1, %eax
	movl $0, %ebx
	int $0x80
  • 局部餘數
# premtest.s - An example of using the FPREM1 instruction
.section .data
value1:
	.float 20.65
value2:
	.float 3.97
.section .bss
	.lcomm result, 4
.section .text
.globl _start
_start:
	nop
	finit
	flds value2
	flds value1
loop:
	fprem1
	fstsw %ax
	testb $4, %ah
	jnz loop
	
	fsts result
	movl $1, %eax
	movl $0, %ebx
	int $0x80
  • FSIN 和 FCOS 指令
# trigtest.s - An example of using the FSIN and FCOS instructions
.section .data
degree1:
	.float 90.0
val180:
	.int 180
.section .bss
	.lcomm radian1, 4
	.lcomm result1, 4
	.lcomm result2, 4
.section .text
.globl _start
_start:
	nop
	finit
	flds degree1
	fidivs val180
	fldpi
	fmul %st(1), %st(0)
	fsts randian1
	fsin
	fsts result1
	flds randian1
	flds randian1
	fcos
	fsts result2

	movl $1, %eax
	movl $0, %ebx
	int $0x80

浮點數的條件分支

  • FCOM指令
指令 描述
FCOM 比較ST0與ST1
FCOM ST(x) 比較ST0與STX
FCOM source 比較ST0與source
FCOMP 比較ST0與ST1,popST0
FCOMP ST(X) 比較後出棧
FCOMP source 比較後出棧
FCOMPP 比較後出棧2次
FTST 比較ST0與0
條件 C3 C2 C0
ST0 > source 0 0 0
ST0 < source 0 0 1
ST0 == source 1 0 0
# fcomtest.s - An example of the FCOM instruction
.section .data
value1:
	.float 10.923
value2:
	.float 4.5532
.section .text
.globl _start
_start:
	nop
	flds value1
	fcoms value2
	fstsw
	sahf
	ja greater
	jb lessthan
	movl $1, %eax
	movl $0, %eax
	int $0x80
greater:
	movl $1, %eax
	movl $2, %eax
	int $0x80
lessthan:
	movl $1, %eax
	movl $1, %eax
	int $0x80
  • FCOMI 指令
指令 描述
FCOMI 比較ST0與ST1
FCOMIP 比較ST0與ST(X), 然後出棧
FUCOMI 比較前檢查無序值
FUCOMIP 比較前檢查無序值並出棧
條件 ZF PF CF
ST0 > ST(x) 0 0 0
ST0 < ST(x) 0 0 1
ST0 = ST(x) 1 0 0
# fcomitest.s - An example of the FCOMI instruction
.section .data
value1:
	.float 10.923
value2:
	.float 4.5532
.section .text
.globl _start
_start:
	nop
	flds value2
	flds value1
	fcomi %st(1), %st(0)
	ja greater
	jb lessthan
	movl $1, %eax
	movl $0, %eax
	int $0x80
greater:
	movl $1, %eax
	movl $2, %eax
	int $0x80
lessthan:
	movl $1, %eax
	movl $1, %eax
	int $0x80
  • FCMOV 指令
指令 描述
FCMOVB 如果ST0 < ST(x) 移動
FCMOVE 如果ST0 = ST(x) 移動
FCMOVBE 如果ST0 <= ST(x) 移動
FCMOVU 如果ST0無序 移動
FCMOVNB 如果!ST0 < ST(x) 移動
FCMOVNE 如果 !ST0 = ST(x) 移動
FCMOVNBE 如果! ST0 <= ST(x) 移動
FCMOVNU 如果!ST0無序 移動
# fcmovtest.s - An example of the FCMOVxx instruction
.section .data
value1:
	.float 20.5
value2:
	.float 10.90
.section .text
.globl _start
_start:
	nop
	finit
	flds value1
	flds value2
	fcomi %st(1), %st(0)
	fcmovb %st(1), %st(0)

	movl $1, %eax
	movl $0, %ebx
	int $0x80

保存和設置FPU狀態

  • 保存和重載FPU環境
    • 命令
      FSEENV
    • 保存內容
      • 控制寄存器
      • 狀態寄存器
      • 標籤寄存器
      • FPU指令指針偏移
      • FPU數據指針
      • FPU上次操作碼執行結果
    • 示例
# fpuenv.s - An example of the FSTENV and FLDENV instructions
.section .data
value1:
	.float 12.34
value2:
	.float 56.789
rup:
	.byte 0x7f, 0x0b
.section .bss
	.lcomm buffer, 28
.section .text
.globl _start
_start:
	nop
	finit
	flds value1
	flds value2
	fldcw rup
	fstenv buffer

	finit
	flds value2
	flds value1
	fldenv buffer

	movl $1, %eax
	movl $0, %ebx
	int $0x80
  • 保存和重載FPU狀態
    • 指令
      FSAVE
    • 示例
#fpusave.s - An example of the FSAVE and FRSTOR instructions
.section .data
value1:
	.float 12.34
value2:
	.float 56.789
rup:
	.byte 0x7f, 0x0b
.section .bss
	.lcomm buffer, 108
.section .text
.globl _start
_start:
	nop
	finit
	flds value1
	flds value2
	fldcw rup
	fsave buffer

	flds value2
	flds value1

	frstor buffer

	movl $1, %eax
	movl $0, %ebx
	int $0x80
  • 非等待指令
指令 描述
FNCLEX 清除浮點數異常標識
FNSAVE 保存FPU狀態
FNSTCW 保存FPU控制寄存器
FNSTENV 保存FPU環境
FNSTSW 保存FPU狀態寄存器
  • 優化浮點數運算
    • 確保浮點數沒有溢出
    • 設置單精度浮點數的精度控制標識
    • 對簡單的三角函數運算使用查找表
    • 將鏈式運算拆解
    • 儘量長的保存方程式的值
    • 儘量將INT轉換成浮點數,再運算
    • 使用FCOMI 代替FCOM
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章