早上好,中午好,晚上好,地球O|

园龄:粉丝:关注:

2023-09-23 22:56阅读: 12评论: 0推荐: 0

数值系统

数值系统

知其然而知其所以然。

二进制整数表示方式

原、反、补码及其缺点和补码好处

原码
二进制的第一位表示符号位,剩下的位表示绝对值,例如:

2  ---> 0010
-2 ---> 1010

问题:做加法的时候需要额外判断两个数的正负,且存在+0和-0。

原码做计算要考虑额外考虑符号正负。

反码
反码解决了额外判断正负号的问题。在原码的基础上,对负数的非符号位取反(注意:正数三种码都和原码一样)

可以直接进行加法运算,如果算子中有负结果要加一,依然有点麻烦,例如

-2 ---> 1010  //原码
-2 ---> 1101  //反码

-2 + 5 = 3
 1101
+0101
+0001 //额外加一
=0011 ---> 3

-1 + -1 = -2
1110
1110
0001
1101 --->-2

问题:仍然存在+0和-0,且需要判断算子有没有负数

补码
反码基础上加一就是补码,补码码运算的时候不必加上最后的1,不用判断正负数。
补码还有好处是:没有+0 -0。
至于他为什么可以直接相加得到最后的答案,用数学知识可以证明,此处略。

-2 + 5 = 3
1110
0101
0011 ---> 3

补码特性

//2
0010
//-2 是 2取反加一 
1110 (1101 + 1 = 1110)
// 2 是 -2 取反加一
0010 (0001 + 1 = 0010)

范围和溢出

讨论范围要分有符号和无符号

无符号
这个比较简单 [0,2k1] ,如果发生溢出,会从头开始

//unsigned 4_bits
0000-1111
1111 + 0001 = 0000

有符号
正数,符号位占一位,所以范围只有: [0,2k11]
负数,计算方式为 2k+ 所以范围是 [1,2k]

//负数举例
1111 = -2^4 + 7 = -9
1000 = -2^4 + 0 = -16

有符号的溢出,会变成异号,很好理解,最高位发生改变。

0111 + 1 = 1000 ---> 7 + 1 = -16
1000 - 1 = 1000 + 1111 = 0111 ---> 7

他们的范围可以看作一个圆,从0到正最大,再迈出一步到负最小,再继续增加到-1,0.
相当于把数轴两端粘到一起。

注意
C++中无符号和有符号运算的时候会发生一些自动转换,容易出错。例如

vector<int> nums;
//size()返回的size_t是无符号的,所以若size() == 0,会变得很大
for (int i = 0; i < nums.size() - 1)

浮点数

格式

image-20231012121336284

第一位表示正负(sign, 0+, 1-),一些位数表示小数值(frac位),一些位数(exp)用于表示指数大小,bias是用于偏移指数的值

x=(1)sign(1+frac)2(expbias)

注意上述公式中f是小数部分的二进制位
exp - bias是指数的真实大小,bias的作用是将指数范围都转到正数,使得exp部分永远是正数,就不用补码表示了,举例:

假设我们有一个单精度浮点数:
0 10000010 11010000000000000000000
其中:
符号位:0,表示正数
指数位:10000010,偏移量为 127,所以真实指数值为 10000010 - 127 = -25
尾数位:11010000000000000000000

为什么exp 是8bits时bias是127?

假设exp有k位,IEEE规定,k位全0和全1要用于额外表示其他数据(后面讲),所以我们exp的范围就是[1,2k2]这意味着我们一共可指数一共有2k2个一半正数一半负数,那就是2k11,带入8就是127,并且用不了的两个数是0和255

三种浮点数类型

Normal

规格化数,exp非全0非全1,整数部分只有一个1,小数部分由frac表示,参考科学计数法。例如

// 2.5f的二进制位
0 10000000 01000000000000000000000
// 可以算出exp是1, frac是1.01

DeNormal

非规格化数,exp全0,若frac也全0,则是0,若frac非0,则被认为是非常接近0的数。

exp为0,frac非0的区域,浮点数是均匀分布的。因为指数恒定,frac的增减自然对浮点数大小的影响是线性的。

Special

特殊的数,exp全1,frac全0,被认为是INF,无穷。若frac非0,则被认为是NaN(Not a Number)

浮点数分布

DeNormal区域均匀分布,再往外就是越来越稀疏,如图

image-20231012123822614

浮点数舍入

默认四舍六入,五则向偶数舍入,例如1.5 -> 2 <- 2.5,原因:一部分向上一部分向下,减少舍入误差。

为什么说浮点数的精度和范围不可兼得

可以从计算公式看出来:总位数固定,小数位越多,指数越少,那么范围就越小,反之亦然。

浮点数运算

加法

规定:exp较小的向exp较大的对齐,并且相应地对frac移位,类似10进制科学计数法。

frac直接相加,最终exp取大的那个

最终符号如何确定:不知道

如何判断溢出:不知道

如何做减法:不知道

以上问题主要不知道的原因是浮点数的符号位是额外写出来的,并不像整数那样使用补码,也许底层进行运算的时候确实是会转成补码来算吧,但我没查到相关资料。

乘法

exp相加再减去bias,frac直接相乘,符号做异或运算。

如何判断溢出:我只知道如果exp变成全1或者全0可能溢出了,但如果exp的结果不是全0全一,但你确实知道他发生了溢出,那机器如何判断这种情况溢出呢?我不知道。

运算规则引发的常见问题和一些尚未解决的疑惑

主要是由exp对齐等引发的。

比如一个很大的数加很小的数,很小的数会被“忽略”。因为对阶的时候,frac右移太多的话,frac的有效位都被移没了,成了0.

而且实际计算乘法的时候,规则也许并不是我上面说的那样,举例

// 1e20
0 11000001 01011010111100011101100
// 1e20 * 1e20
0 11111111 00000000000000000000000

很明显exp不是直接相加再减去bias,frac也不是直接相乘

浮点数如何判断运算溢出

不知道。不要跟我说超出范围就算溢出,机器如何判断超出范围?

浮点和整形类型转换的底层原理

注意,这里不是说高级语言的强制类型转换截断之类的问题,是bit层面的。

整形和浮点对同一串bits的解读方式不一样,比如

// int 123
0 00000000 00000000000000001111011
// 对于浮点数来说,他表示: 1.723597e-43

转换规则

int转float

符号位直接看最高位

找到从最高位往下第一个1,之后的位数就是exp - bias的值,之后的bits就是frac

float转int

符号位同上

frac << (exp - bias) 之后的位舍去。

存在的问题

注意,有可能会溢出。还有精度损失。

如何存储

大小端

指的是二进制如何存储。假设一个存储单位是8bits

0x78_9a_bc
//假设左边低地址,右边高
//大端,高位存在地址低端
78 9a bc
//小端,低位存低端
bc 9a 78

本文作者:DL

本文链接:https://www.cnblogs.com/BayMax0-0/p/17725304.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _nullptr0xf  阅读(12)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起