微前端架构如何改变企业的开发模式与效率提升
1152
2022-08-27
汇编 —— 尾数、负数加法、标准浮点数
大小尾数
小尾数:低位字节存储在低内存位置或寄存器的低位地址,高位字节存储在高内存位置或寄存器的高位地址。 大尾数:和小尾数的存储顺序是相反的,低位字节存储在高位地址。
intel采用的是小尾数存储格式: 检测:
.section .datavalue: .int 0x127.section .text.global mainmain: nop movl $0x127,%ebx int $0x80
查看内存情况:
(gdb) x/x &value0x8049664
负数的数学计算
在计算机中,四则运算以加法为基础。理解负数在计算机中以补码表示,负数和非负数的加法计算,负数和负数的加法计算很重要。
使用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
在双精度存储的条件下,因为有效位数和指数位都明显增加,所以精度变高。
(gdb) x/gf &value10x8049654
对于小数点需要右移的情况: 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
当我将其变成双精度存储后,用同样的方法计算,可以发结果是吻合的:
gdb: 0011111111001101011100001010001111010111000010100011110101110001man: 00111111110011010111000010100011110...
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~