汇编 —— 尾数、负数加法、标准浮点数

网友投稿 1057 2022-08-27

汇编 —— 尾数、负数加法、标准浮点数

汇编 —— 尾数、负数加法、标准浮点数

大小尾数

小尾数:低位字节存储在低内存位置或寄存器的低位地址,高位字节存储在高内存位置或寄存器的高位地址。 大尾数:和小尾数的存储顺序是相反的,低位字节存储在高位地址。

intel采用的是小尾数存储格式: 检测:

.section .datavalue: .int 0x127.section .text.global mainmain: nop movl $0x127,%ebx int $0x80

查看内存情况:

(gdb) x/x &value0x8049664 : 0x27(gdb) x/4x &value0x8049664 : 0x27 0x01 0x00 0x00(gdb) p/x $ebx$1 = 0x127(gdb) p/x $bx$2 = 0x127(gdb) p/x $bl$3 = 0x27(gdb) p/x $bh$4 = 0x1

负数的数学计算

在计算机中,四则运算以加法为基础。理解负数在计算机中以补码表示,负数和非负数的加法计算,负数和负数的加法计算很重要。

使用gdb简单查看负数的加法操作: 汇编:

.section .text.global mainmain: nop movl $24,%edx movl $-35,%ecx addl %edx,%ecx movl $-24,%edx addl %edx,%ecx int $0x80

gdb调试:

Temporary breakpoint 1, main () at negtive.s:44 nopMissing separate debuginfos, use: debuginfo-install glibc-2.12-1.192.el6.i686(gdb) n5 movl $24,%edx(gdb) n6 movl $-35,%ecx(gdb) n7 addl %edx,%ecx(gdb) p/t $edx$1 = 11000(gdb) p/t $ecx$2 = 11111111111111111111111111011101(gdb) n8 movl $-24,%edx(gdb) p/t $ecx$3 = 11111111111111111111111111110101(gdb) p $ecx$4 = -11(gdb) n9 addl %edx,%ecx(gdb) p $edx$5 = -24(gdb) p/t $edx$6 = 11111111111111111111111111101000(gdb) n10 int $0x80(gdb) p $ecx$7 = -35(gdb) p/t $ecx$8 = 11111111111111111111111111011101

整个过程简单地说是这样的:

00000000000000000000000000011000 + 11111111111111111111111111011101 =11111111111111111111111111110101即是:24 + -35 = -1111111111111111111111111111101000 +11111111111111111111111111110101

标准浮点数据

标准浮点数据类型,IEEE标准754顶的浮点数

32位单精度浮点数

因为假设有效数字的整数值是1,并且不在有效数字值中使用它,所以精度就变成了23+1=24。

指数使用8位,那么它的范围应该是-128~127.

单精度浮点数最大绝对值是1.9˙×2127≈1.9˙×1.701×1038≈3.4×1038

64位双精度浮点数

指数的位数是11,2^11=2048,那么指数的范围是-1024~1023.

双精度的最大绝对值估计为:1.9˙∗21023≈1.79×10308

拓展双精度

IA-32平台,拓展双精度格式使用在80位FPU寄存器中。

指数位是15,2^15=32768,那么指数的范围是-16384~16383,拓展双精度的最大绝对值是:1.9˙×216383≈1.18×104932

由此我们得到下面这张表:

数据类型

长度

有效数字位

指数位

精度范围

单精度

32

23

8

1.18×10−38∼3.4∗1038

双精度

64

53

11

2.23×10−308∼1.79×10308

拓展双精度

80

64

15

3.37×10−4932∼1.18×104932

最小的精度值我没能想通它是怎么算出来的。望交流。

浮点数转化成二进制

(例子讲解12.23转化成01000001010000111010111000010100): 1. 提取小数部分0.23,乘以2,如果整数部分是1,那么十分位是1,否则是0 0.23×2=0.46decimals:0.0; 再取小数部分乘以2,判断是否在百分位上写1 0.46×2=0.92decimals:0.00; 继续刚才的步骤, 0.92×2=1.84decimals:0.0010.84×2=1.68decimals:0.00110.68×2=1.36decimals:0.001110.36×2=0.72decimals:0.0011100.72×2=1.44decimals:0.00111010.44×2=0.88decimals:0.001110100.88×2=1.76decimals:0.0011101010.76×2=1.52decimals:0.00111010110.52×2=1.04decimals:0.001110101110.04×2=0.08decimals:0.0011101011100.08×2=0.16decimals:0.00111010111000.16×2=0.32decimals:0.001110101110000.32×2=0.64decimals:0.0011101011100000.64×2=1.28decimals:0.00111010111000010.28×2=0.56decimals:0.001110101110000100.56×2=1.12decimals:0.0011101011100001010.12×2=0.24decimals:0.00111010111000010100.24×2=0.48decimals:0.00111010111000010100 (停,单精度已经装不下了) 2. 转化整数部分成二进制形式 11002,和小数部分写在一起: 1100.001110101110000101002如果是左移,第30位填1,左移位数n减去1再换成二进制形式填入指数位;若是右移或者n=0,第30位填0,第29位到第23位放n的二进制数,然后取反。 3. 转换成有效数字,左移3位,1100.001110101110000101002⟶1.100001110101110000101002 4. 将最左边的1去掉小数部分是23位,正是单精度的有效数字部分。 5. 因为是左移,那么第30位写1,左移位数3减去1等于2,填到指数位,​​​10000010​​​就是指数位的构成。 6. 因为12.23是正数,所以我们在第31位填0. 得到最终的结果:​​​01000001010000111010111000010100​​

当然这是有精度缺失的,gdb调试: float.s:

.section .datavalue1: .float 12.23 .section .text.global mainmain: nop int $0x80

gdb查看内存:

(gdb) x/t &value10x8049654 : 01000001010000111010111000010100(gdb) x/f &value10x8049654 : 12.2299995

在双精度存储的条件下,因为有效位数和指数位都明显增加,所以精度变高。

(gdb) x/gf &value10x8049654 : 12.23(gdb) x/t &value10x8049654 : 0100000000101000011101011100001010001111010111000010100011110110

对于小数点需要右移的情况: value = 0.23 1. 和左移的情况类似: 0.23×2=0.46decimals:0.00.46×2=0.92decimals:0.000.92×2=1.84decimals:0.0010.84×2=1.68decimals:0.00110.68×2=1.36decimals:0.001110.36×2=0.72decimals:0.0011100.72×2=1.44decimals:0.00111010.44×2=0.88decimals:0.001110100.88×2=1.76decimals:0.0011101010.76×2=1.52decimals:0.00111010110.52×2=1.04decimals:0.001110101110.04×2=0.08decimals:0.0011101011100.08×2=0.16decimals:0.00111010111000.16×2=0.32decimals:0.001110101110000.32×2=0.64decimals:0.0011101011100000.64×2=1.28decimals:0.00111010111000010.28×2=0.56decimals:0.001110101110000100.56×2=1.12decimals:0.0011101011100001010.12×2=0.24decimals:0.00111010111000010100.24×2=0.48decimals:0.00111010111000010100 more: 0.48×2=0.96decimals:0.0011101011100001010000.96×2=1.92decimals:0.00111010111000010100010.92×2=1.84decimals:0.001110101110000101000110.84×2=1.68decimals:0.0011101011100001010001110.68×2=1.36decimals:0.00111010111000010100011110.36×2=0.72decimals:0.00111010111000010100011110 2. 为了得到有效数字,右移3位,1.11010111000010100011110 有效数字位:11010111000010100011110 3. 第30位是0,指数位填000000112⟶011111002 4. 第31位填0。得到最终的结果即00111110011010111000010100011110 但是这和电脑上的结果最后一位不一样。

00111110011010111000010100011110(gdb) x/t &value10x8049654 : 00111110011010111000010100011111(gdb) x/f &value10x8049654 : 0.230000004

当我将其变成双精度存储后,用同样的方法计算,可以发结果是吻合的:

gdb: 0011111111001101011100001010001111010111000010100011110101110001man: 00111111110011010111000010100011110...

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:汇编 —— 起步
下一篇:杂记 (7) —— windows + code
相关文章

 发表评论

暂时没有评论,来抢沙发吧~