整数与浮点数知识都在这里了

一 整数

首先我们来讲一讲背景,整数在不同的平台下可能会有不同的大小,一般来说都是4个字节,也就是32位,但是在一些老的平台上可能会占用两个字节,也就是16位。这里指定整数就是32位的整数,然后对32位的整数的表示范围进行分析。

1. 无符号整数

整数要分正数和负数,但是对于一个无符号整数来说,他只有正,标准中是用第一位标志正负,0代表正,1代表负。因为无符号整数不用一位去标识,所以对于无符号整数来说,所有位数为都为1即为最大,都为0为最小。

对于一个位数为w的二进制数:
向量 : x = [x_{w-1},\dots, x_0]
那么无符号整数计算方式为:
V_{unsigned}(x) = \sum_{i=0}^{w-1}x_i2^i
下面测验一下最大的无符号整数:

int main(void) {
    //cout << sizeof(unsigned int) << endl;
    unsigned int unMax = 0b11111111111111111111111111111111;
    cout << "位都为1的无符号整数为:" << unMax << endl;
    cout <<"最大无符号整数为:" << UINT32_MAX << endl;
    return 0;
}

结果:
位都为1的无符号整数为:4294967295
最大无符号整数为:4294967295

0b表示二进制。

2. 有符号整数

与一般人的直觉不同,有符号整数的表示并不是单独用一位来表示正负,而是采用补码的方式最大限度的利用了所有的位数。
对于一个位数为w的二进制数: 向量 : x = [x_{w-1},\dots, x_0]补码计算方式为:
V_{补码}=-x_{w-1}2^{w-1} + \sum_{i=0}^{w-2}x_i2^i
根据等比数列求和公式:补码最后一项的最大和 (所有x_i均为1时) 为:x_{w-1}2^{w-1} - 1 所以在第一位为1时,就决定了这一定是一个负数,相反的,在第一位为0时,说明一定为正数,那么其表示范围为多少?做实验:

int main(void) {
    int intMax = 0b01111111111111111111111111111111;
    int intMin = 0b10000000000000000000000000000000;
    cout << "首位为0其余都为1的32位整数为:" << intMax << endl;
    cout <<"最大整数为:" << INT_MAX << endl;
    cout << "首位为1其余都为0的32位整数为:" << intMin << endl;
    cout <<"最大整数为:" << INT_MIN << endl;
    return 0;
}

结果:
首位为0其余都为1的32位整数为:2147483647
最大整数为:2147483647
首位为1其余都为0的32位整数为:-2147483648
最大整数为:-2147483648

为什么要用补码的方式而不是像无符号整数那样计算,然后单独用一位表示正负呢?
如果我们用一位来表示正负,其他的按照无符号整数那么计算,那么0就会出现两次,浪费了一个数字的表示空间。

3 表示范围

正如之前计算的一样:

  • 最大无符号整数 = 11111111111111111111111111111111(二进制) = 4294967295 (十进制)
  • 最小无符号整数 = 0000000000000000000000000000(二进制) = 0 (十进制)
  • 最大正整数 = 01111111111111111111111111111111(二进制) = 2147483647(十进制)
  • 最小负整数 = 10000000000000000000000000000000(二进制) = -2147483648(十进制)
  • 全为1的有符号整数 = 11111111111111111111111111111111(二进制) = -1(十进制)
  • 全为0的有符号整数 = 00000000000000000000000000000000(二进制) = 0(十进制)

二 浮点数

1 标准浮点数形式

V = (-1)^s \times M \times 2^E \\s:符号位, M:尾数值, E:阶码值

  • 符号位:浮点数有单独的一位来表示正负:第1位为零的时候为正,第1位为一的时候为负。
  • 尾数值:表示小数点后面的值,比如0000011 = 0.00000011
  • 阶码值:就是2的多少次方。


    image.png

以下内容的M, E, s皆遵从上述定义。

2 单,双精度浮点数表示

名称 单精度长度 双精度长度
符号(sign) 1 1
尾数(frac) 23 52
阶码(exp) 8 11

也就是说对于一个32位的浮点数float来说,他有一位是符号位,23位是尾数位,8位为阶码位。对于一个64位的double浮点数来说他有一位是符号位,52位是尾数位,11位阶码位。

可以看到,尾数位越多,那么这个浮点数能表示的数字就越精确,如果阶码位越多,那么浮点数能表示的范围就越大,但是同样的,它能表示的这个不连续区间的间隔就越大,说白了计算机是用一系列固定数量的离散点描述浮点数,离散点个数是确定的,如果想表示更大的浮点数,就得接受离散点之间的相对举例增大,也就是说浮点数不够精确。

3 单精度浮点数细节(标准情况)

下面以单精度浮点数为例,解释一下具体的浮点数计算,双精度浮点数和单精度浮点数大同小异。

先来说一说阶码,如果不用符号位或者补码的方式,那就是没有正负的,对于指数来说,负指数代表的是除法,只有这样才会出现浮点数,IEEE754标准人为的规定了一个偏移值,阶码的计算值减去这个偏移值才是真实的阶码值。

这里有一个小工具:IIEEE754计算器

阶码的实际值计算:

Bias = 2^{k-1} - 1
对于32位浮点数:Bias = 2^{8-1} - 1 = 127,
阶码全为0和全为1是两种特殊情况,会走不同的逻辑:所以阶码本身的范围为:[1, 254]
阶码的实际表示范围为:[-126, 127]([1-127, 254-127])

尾数值:

假设尾数值的二进制转十进制值为f,那么实际值M = 1+f.,例如:
若f = 00011111,则 M = 1 + f = 1.00011111

3 单精度浮点数细节(非规格化情况)

或许你注意到了,按照之前的表示方式,0是没有办法精确表示的,对于一个32位的正浮点数,最接近0的数为:
0(符号) 00000000000000000000000(尾数) 00000001(阶码) = 2^{-126},问题很大。

image.png

所以指定了,当阶码位全为0时,走入非规格化逻辑:

  • 阶码实际值为:E = 1- Bias = -126
  • 尾数实际值: M = f(尾数计算值)
    所以:
    0 = 0(符号)00000000000000000000000(尾数)00000000(阶码)

4 特殊情况

阶码位全为1时为特殊情况:

  • (1) 当小数位都为0时表示无穷,s为0表示正无穷,s为-1表示负无穷。


    image.png

    image.png
  • (2) 当小数位不全为0时表示溢出(NaN)。


    image.png

5 一些特殊浮点数

  • (1) 大于0的最小浮点数: V = 00000000000000000000000000000001 = 0.00000000000000000000001(二进制) \times 2^{-126}\approx1.4 \times 10^{-45}
    手动计算器算的值:
    image.png

    现成工具计算的值:
    image.png
  • (2) 标准规格下最接近于0的值:
    V = 00000000100000000000000000000000 \approx 1.175\times 10^{-38}
  • (3) 最大存在的浮点数:
    0-11111110-11111111111111111111111 \approx 3.4\times10^{38}
  • (4) 1的准确表示:
    V = 0-01111111-00000000000000000000000 = 1
  • (5) 负数与整数完全对称,就不赘述了。

6 总结

最后以一个小例子结尾:
f = 0.023 + 0.1
如果以较高精度输出f,f会是准确值吗?

int main(void) {
    float f = 0.023 + 0.1;
    cout << "f = " << setprecision(12) << f << endl;
    return 0;
}
结果:
f = 0.123000003397

浮点数并不像整数那样可靠,所以在计算浮点数的时候,你的加减乘除的顺序可能就会得到不同的计算结果,所以对待浮点数一定要谨慎,在对浮点数精度要求比较高的情况下,可以考虑使用BigDecimal。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容

  • 网站乱码问题我们会经常碰到,大多见于非英文的中文字符或其他字符乱码,而且,这类问题常常是因为编码方式问题,主要原因...
    波段顶底阅读 2,864评论 1 9
  • 精确定义如何编码和操作整数的数学术语: 1.1 整数数据类型 唯一一个与机器相关的类型是long,其他类型的取值范...
    月月月月_bd25阅读 562评论 0 0
  • 0.目录 浮点数的表示 加减 存储格式 特殊的数 1.浮点数的表示 1.1 表示格式 浮点数,顾名思义,是小数点不...
    lllnan阅读 1,817评论 0 1
  • 刚才刘小澈睡梦中突然大哭起来,怎么都哄不下来,哭的快背过气去,给奶也不吃。奶奶抱着,我和爸爸急得不知怎么办,刘小潼...
    燕子不飞么阅读 116评论 0 0
  • 钢琴闹钟,你们见了吗?下面,我就来讲一讲我的钢琴闹钟吧! 钢琴闹钟,是从我上钢琴课那里拿的,转发三天,...
    迷路的小星星阅读 711评论 0 4