第62部分- Linux x86 64位汇编 浮点数

第62部分- Linux x86 64位汇编 浮点数

单精度是这样的格式,1位符号,8位指数,23位小数。

https://pic4.zhimg.com/80/v2-749cc641eb4d5dafd085e8c23f8826aa_1440w.jpg

指数是从-128到127的8位有符号整数,或者是从0到255的8位无符号整数。指数部分采用的偏置码(biased)的形式来表示正负指数,若小于127则为负的指数,否则为非负的指数。所以0到126代表-127到-1,127代表零,128-255代表1-128。

另外补码,一个数字的补码就是将该数字作比特反相运算(即反码),再将结果加1。在补码系统中,一个负数就是用其对应正数的补码来表示。

补码系统的最大优点是可以在加法或减法处理中,不需数字的正负而使用不同的计算方式。只要一种加法电路就可以处理各种有号数加法,而且减法可以用一个数加上另一个数的补码来表示,因此只要有加法电路及补码电路即可完成各种有号数加法及减法,在电路设计上相当方便。

单精度公式:(-1)^S*(1.M)*2^(E-127)  

S是符号。

M是尾数。

E是指数。

双精度是1位符号,11位指数,52位小数。

https://pic2.zhimg.com/80/v2-48240f0e1e0dd33ec89100cbe2d30707_1440w.jpg

双精度公式: (-1)^S*(1.M)*2^(E-1023) 

扩展双精度是80位的,1位符号,15位指数,112位小数。

f、j、e 和 s 四个字段中的位模式值将决定整个位模式所表示的值。

计算模式相对复杂一点,大家可以忽略之。

双精度扩展位模式 (x86)

j = 0, 0 < e <32767

不支持

j = 1, 0 < e < 32767

(–1)s × 2e–16383 × 1.f(正规数)

j = 0, e = 0; f ≠ 0f 中至少有一位不为零)

(–1)s × 216382 × 0.f(次正规数)

j = 1, e = 0

(–1)s × 216382 × 1.f(伪非正规数)

j = 0, e = 0, f = 0f 中的所有位均为零)

(–1)s × 0.0(有符号的零)

j = 1; s = 0; e = 32767; f = 0f 中的所有位均为零)

+INF(正无穷大)

j = 1; s = 1; e = 32767; f = 0f 中的所有位均为零)

–INF(负无穷大)

j = 1; s = ue = 32767; f = .1uuu — uu

QNaNquiet NaN,静态 NaN

j = 1; s = ue = 32767; f = .0uuu — uu ≠ 0

f 中至少一个 u 不为零)

SNaNsignaling NaN,信号 NaN

SSE浮点数据类型

除了3种标准浮点数据类型之外,SSE技术的INTEL处理器还包含两种高级浮点数据类型。8个128位XMM寄存器可以保存打包浮点数。类似打包BCD概念。

数据移动如下:

         SSE2数据传送指令如下:

数据类型转换

PS是打包单精度FP

PD是打包双精度FP

PI是打包双字整数,使用MMX

DQ是打包双字整数

示例

转换数据类型如下:

.section .data
value1:
   .float 1.25, 124.79, 200.0, -312.5
value2:
   .int 1, -435, 0, -25
.section .bss
data:
   .lcomm datas, 16
.section .text
.globl _start
_start:
   nop
   cvtps2dq value1, %xmm0;//打包单精度到打包双字整型
   cvttps2dq value1, %xmm1;//打包单精度到打包双字整型,会截断
   cvtdq2ps value2, %xmm2;//打包双字整型到打包单精度,会截断
   movdqu %xmm0, datas;//保存到datas变量中。

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

在value1中定义了一个打包单精度浮点值。

value2中定义了打包双字整数值。

使用gdb进行调试,可以看到如下xmm寄存器。

(gdb) print $xmm0

$8 = {v4_float = {1.40129846e-45, 1.75162308e-43, 2.80259693e-43, -nan(0x7ffec8)}, v2_double = {2.6524947387115311e-312, -nan(0xffec8000000c8)}, v16_int8 = {1, 0, 0, 0, 125, 0,

    0, 0, -56, 0, 0, 0, -56, -2, -1, -1}, v8_int16 = {1, 0, 125, 0, 200, 0, -312, -1}, v4_int32 = {1, 125, 200, -312}, v2_int64 = {536870912001, -1340029796152},

  uint128 = 340282342201751762702250093524836941825}

(gdb) print $xmm1

$9 = {v4_float = {1.40129846e-45, 1.7376101e-43, 2.80259693e-43, -nan(0x7ffec8)}, v2_double = {2.6312747808018783e-312, -nan(0xffec8000000c8)}, v16_int8 = {1, 0, 0, 0, 124, 0,

    0, 0, -56, 0, 0, 0, -56, -2, -1, -1}, v8_int16 = {1, 0, 124, 0, 200, 0, -312, -1}, v4_int32 = {1, 124, 200, -312}, v2_int64 = {532575944705, -1340029796152},

  uint128 = 340282342201751762702250093520541974529}

(gdb) print $xmm2

$10 = {v4_float = {1, -435, 0, -25}, v2_double = {-7.3498756827903427e+18, -805306368}, v16_int8 = {0, 0, -128, 63, 0, -128, -39, -61, 0, 0, 0, 0, 0, 0, -56, -63}, v8_int16 = {

    0, 16256, -32768, -15399, 0, 0, 0, -15928}, v4_int32 = {1065353216, -1009156096, 0, -1043857408}, v2_int64 = {-4334292427813683200, -4483333429047328768},

  uint128 = 257579462558195729010253313545846390784}

可以看到cvttps2dq指令会进行截断。

而cvtps2dq指令会进行舍入。

另外,最后在调试的时候大家会发现,xmm寄存器已经被扩展了,已经变成了256位的zmm了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值