浮点数

定点数

计算机有两种小数,定点数和浮点数。

定点数指的是小数点后面的位数是固定的。小数点固定在数据的最高位就是定点小数,固定在小数点最低位的称为定点整数。

定点小数是纯小数,所以它的范围是[2-n,1-2-n]
在这里插入图片描述
定点小数是纯整数,所以它的范围是[1,2n-1]
在这里插入图片描述

定点数类型的值其实就是个整数,需要额外比例进位,进多少位需要根据具体的定点数类型决定。例如1.23使用1/1000比例的定点数表示是 1230;1,230,000 使用 1000 比例的定点数表示也是 1230。与浮点数不同,相同类型的定点数中所有值的缩放系数都是一致的,在计算过程中也保持不变。

缩放系数通常是 10 或 2 的幂,前者方便人类读写,后者易于高效计算。不过有时也会使用其它比例,例如可以用 1/3600 的比例的定点数来表示以小时为单位的时间值,可以精确到秒。

定点数的最大值,可以通过将其内部所使用的整数的最大值乘以缩放系数求得,最小值同理。

浮点数

应用更广、更加复杂。浮点数之所以存储字节相对来说比定点数少,是因为它不是硬生生的去表达小数,使用了科学计数法一些约定来表达小数。

浮点数由符号位、有效数字、指数来表示,有效数字在[1,9]区间内,可以看出表示不了0,但是可以通过规定产生。

浮点数标准是IEEE754,规定了4种浮点数类型:单精度、双精度、延伸单精度、延伸双精度。最长用的是单精度、双精度,下面将介绍单精度。

计算机世界由二进制来表示十进制,指数称为阶码、有效数称为尾数。

单精度分配了4个字节,一共32位,1位符号位,8位指数位,23位有效数字位。

符号位

最高1位表示,0正数,1负数。

阶码位

在符号位的右侧8位用来存储指数,IEEE754标准规定这8位是指数正向偏移到正域,8位二进制能表示[-128,127]偏移到正域就需加128变成[0,255],用0表示机器0,全1代表无穷大,所以得去头去尾,所以偏移量为2n-1 -1而不是2n-1,所以E=e+2n-1 -1,得到的指数范围为[-127,126]

尾数位

IEEE754规定尾数用源码表示

规范化

最终格式是± 1.bbb…*2p
±用符号位表示
p是加上偏移量对应的阶码
b是尾数由于最左边规定总是1所以用23位全部表示b。

举个例子

3.14
尾数3用11表示,0.14最近的是2-3=0.125 还差0.015,2-7=0.0078125还差0.0071875,2-8=0.00390625,依次类推最终表示为0.0010001111010111000010[10001111…]
这样3.14的二进制代码就是:11.0010001111010111000010[10001111…]规则化后1.10010001111010111000010[10001111…]*21这边先舍入后面再讲为啥,尾数为10010001111010111000011,阶码是1加上偏移量127就是128为1000 0000,符号位为0,那么结果就是0100-0000-0100-1000-1111-0101-1100-0011转为十进制是:3.1400001049041748046875,和3.14是有误差的。

舍入

舍入的目的主要是可能尾数过长,然后舍入的原则是保证一定的精度。所以规定相对误差不能超过一般机器ε的一半,3.14的相对舍入误差0.0000001049041748046875/3.14≈0.00000003340897286773,单精度的机器ε为2-23≈1.1920928955078125e-7,它的一半是0.00000005960464477539,显然上面舍入是符合要求的。

浮点数加减运算

零值检测

浮点数运算比较复杂,检测0值(规定阶码和尾数全为0)直接能得出结果。

对阶操作

如果阶码不一样就做不了求和操作,所以需要对齐,对阶可以将尾数左移右移,由于左移会移出高位这样会造成误差更大,所以IEEE754规定移动方向为右移动,即选择阶码小的数进行移动。

尾数求和

对阶完后,直接按位相加即可完成求和(如果是负数则需要进行转补码),和十进制类似如9.8103与0.6103结果为10.4*103

结果规整化

尾数向右移动称为右规,向左称为左规,比如上面结果需要右规1.04*104

现在把单精度1-0.9来推演下,为啥是0.100000024呢?

1用浮点数表示是
符号位0
阶码位是0加上移码127是0111-1111
尾数1.000-0000-0000-0000-0000-0000
结果是0011-1111-1000-0000-0000-0000-0000-0000
-0.9用浮点数表示是
结果是1011-1111-0110-0110-0110-0110-0110-0110

由于1的阶码还原后是0,-0.9还原后是-1,所以需要将-0.9尾数的补码
移动一位,尾数位最左端存在一个隐藏位,1110-0110-0110-0110-0110,
由于需要相加需要转补码0001-1001-1001-1001-1001-1010向右移动
一位之后0000-1100-1100-1100-1100-1101,最左位补1是
1000-1100-1100-1100-1100-1101,结果是0011-1111-1000-1100-1100-1100-1100-1101

对齐阶码位后尾数相加,会影响符号位
符号位 尾数位
0 1000-0000-0000-0000-0000-0000
1 1000-1100-1100-1100-1100-1101
0 0000-1100-1100-1100-1100-1101

符号位为0 尾数为0000-1100-1100-1100-1100-1101
规格化
向左移动4位,阶码减4为123(1111011) 结果为
0011-1101-1100-1100-1100-1100-1101-0000,对应十进制为0.100000024。

总结

上面一直讨论的是单精度,其实不管是单精度还是双精度,肯定都会出现误差,所以在不改变原来存储和表达方式的话可以改变单位来减少误差,比如用分替代元。 平时设计金额或者精度要求高的话最好用bigdecimal因为精度更高,具体我不知道是怎么存储和表达的,可能牺牲了物理存储来实现逻辑精度。

  • 7
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值