计算机组成.运动中的小数点.浮点数

  • 我又来复习了
  • 上篇二进制那么多阅读量,,,小心脏怦怦跳,,,
  • 后来发现我最后的复习计划也被列到目录中了,,,大概是这个原因吧

浮点数与科学记数法

  • 之前讲过的定点整数,只是对整数的一种存储,诸如3.14这种只能存成314,之后那就要想办法存下“小数点在最高位3和次高位1之间”这个信息
  • 放心吧,计算机怎么也不会真正的保存小数点
  • 科学记数法就发挥了很大的作用
  • 十进制下科学记数法,就是将一个数表示成
  • number=a?10n
  • 这种形式,并且对a做限定
  • 1<=|a|<10
  • 比如
  • 3.14=3.14?100

    314=3.14?102

  • 如此一来,相当于默认了小数点位于a的最高位和次高位之间,那么只要存下了a*10^n也就不需要存小数点了
  • 问题?为什么要乘10?
  • 比如一个数字3.14,

    3.14?10=31.4

    31.4?10=314

    314?10?1=31.4

  • 看看看,小数点在运动哦~就酱
  • 二进制下有点不同
  • number=b?2n

    0<=|b|<1

  • 比如(除了2之外都是用二进制表示)

    10.01=0.1001?22
  • 还可以乘别的数来表示,比如

    10.01=0.1001?41

    只不过4的指数每变化1小数点就要移动2格

  • 这种对b的规范,默认了小数点的位置
  • 进一步,如果默认了乘的数就是2的话,那么需要存储的只有小数b和指数n了,我们叫这个乘数2为基值

浮点数的格式

  • 对于一个有小数部分的二进制数number,我们写出规范化的科学记数法的形式

    number=b?2n

    0<=|b|<1

  • 那么number就可以用b和n两个数来存储,同时默认了两个条件
    • n是需要乘的2的指数
    • b在0到1之间,也就是说b只能是0.XXX的形式
  • 对于n来说,n就是一个整数
  • b是0.XXX的形式,那么我们就只需要存储“0.XXX”的“XXX”部分就可以了,这也是一个整数的形式
  • 起个规范化的名字,我们称 n 为阶码,称 b 为尾数
  • 看图

  • 考虑到正负的问题,分别留出一位Es和Ms作为符号位,同样是0代表正数,1代表负数

规范化格式

  • 问题又来了?依旧用10.01来举例

    10.01=0.1001?22

    10.01=0.01001?23

  • 也就是说,尽管尾数已经在0到1之间了,我依旧可以移动小数点,再顺势改变一下阶码的值,同一个数存起来就有多种存法
  • 于是对于计算机内存储的时候,还需要进一步规格化
  • 很简单,你想移动小数点,规格化了之后就让你无法移动小数点
  • 即规定:M1必须为1
  • 那么10.01就只能存成

    0.1001?22

    的形式了

浮点数表示的问题

  • 但是,这种规格化也带来了另一个问题,那就是在实现规格化的过程中,我们总是想让M1为1,就需要移动小数点,也就需要改变阶码的值
  • 问题是,你移动了多少多少位来使得M1为1,但是要改变的阶码的值却超出了阶码的表示范围!!就是说阶码的表示范围是有限的!!
  • 这个问题就是浮点数不得不直接面对的问题了,另外尾数的位数限制也是浮点数表示法所固有的精度问题
  • 举例,取E1-E3共3位来记录阶值,Es一位记录阶符,M1-M3共3位来记录尾数的绝对值,Ms一位来记录尾符
    • 最大值:M1-M3均为1,Ms为0表示正,E1-E3均为1,Es为0表示正,即

      MaxValue=0.111?27=1110000
    • 最小值,即最大值的Ms取1表示负,即

      MinValue=?0.111?27=?1110000
    • 规范化表示下最接近零的正数M1取1,M2取0,M3取0,Ms取0,Es取1,E1E2E3均为1,即

      ClosestToZero=0.100?2?7=0.00000001
    • 规范化表示下最接近零的负数自然就是

      ClosestToZero=?0.100?2?7=?0.00000001
  • 问题就是:
    • 超过了最大值最小值,无法表示,称为上溢。这个可以理解,毕竟就算整数也有上限下限。一般运算超过了上限下限会出错,而不像整型那样截断。
    • 比较独特的地方在于,比“最接近零的数”更接近零的数无法表示。原因在于阶码范围的限制。在这个靠近零的狭小范围内,用浮点数来表示都是0,也就是机器中为全0来记录,尽管真实的数值可能很接近零但不是零,然而计算机表示的能力有限,太小的数无法表示,成为“机器零”,称为下溢
    • 最后就是精度的限制与损失。精度限制的原因是尾数的位数有限,而精度的损失一方面来源于“规格化”时小数点的移动,这使得某些数位可能移到了尾数表示范围之外,如

      101.01=0.10101?23=0.101?23

      后两位01没有了,因为尾数总够3位只能保存前面的3位;另一方面来源于十进制转换成二进制所固有的限制,比如

      (0.25)10=(0.01)2

      这样是没有损失的,但

      (0.2)10=(0.0011001...)2

      你会发现十进制的 0.2 根本无法用二进制来完美的表示。其实固然如此,就好比十进制无法完美表示三进制的0.1一样。

      (0.1)3=1/3=(0.3333333...)10

IEEE标准

  • 通常

    • float为 4 Byte = 32 bit , 即float中Es,Ms各占一位外,E1-Em和M1-Mn共占 32 - 2 = 30 位。
    • double为 8 Byte = 64 bit ,即double中Es,Ms各占一位外,E1-Em和M1-Mn共占 64 - 2 = 62位。
    • 那么如何分配 n 和 m 的值,这就需要一个统一的标准
  • 美国电气与电子工程师协会IEEE(Institute of Electrical and Electronic Engineers)为了便于软件的移植,为采用软件对浮点数运算时发生特殊情况进行处理提供支持,并鼓励开发出面向数值计算的优秀程序,于1985年推出了“浮点数表示及运算标准”,即IEEE标准754。
  • 其设计者Kahan因此荣获了1989年的图灵奖。
  • IEEE标准如下
    • 最高位为尾数符号位S
    • 次高位段为 用移码表示的 阶码E
    • 低位字段为 尾数F
    • 基值为2
    • 基本单精度格式:E占8位,F占23位,共32位
    • 基本双精度格式:E占11位,F占52位,共64位
    • 扩充单精度格式:E>=11位,F>=31位
    • 扩充双精度格式:E>=15位,F>=63位
  • 还有一些很奇怪的地方,我尽可能按我的理解解释一下
    • 阶码采用移码表示,为的是便于比较。因为当浮点数进行加减的时候,必须在统一了阶码的前提下才可以对尾数进行加减。
    • 单精度格式阶码E为例,其范围是1~254,也就是

      单精度阶码   E  :  00000001 ~ 11111110

      偏移值是127,也就是说实际的阶码值是 1-127 ~ 254-127 即 -126~+127之间,也就是

      单精度阶码   E  :  10000010 ~ 01111111

      此时的表示方式就变成了补码

    • 上一条中偏移值是127可能需要再解释一下。普通的移码的定义是,为了使得最高位为符号位下编码的二进制正负直接可以直接比较,我们把最高位取反来得到移码,而最高位取反的操作,以4 bit的“0000”为例,也就相当于加上了“1000” 即 2^3=8,对应上条来说,偏移值本应该是128。但别忘了,移码的最终目的是为了使二进制编码的数字可以在正负之间直接比较,达成这个目的同样可以用加上2^3-1 = 7即“0111”来达到,对应可解释上条中的偏移值为什么是127也同样可以了。
    • 阶码E中上有 全0 和 全1 没有编入,这个有特殊的用途,见下面的表格
    • 还记得规格化的要求吗,即M1=1,既然强制了M1=1,那么就不需要存储了嘛,所以IEEE标准754引入了“隐藏位”技术,即不存储规格化要求了的M1=1,这样就使得尾数多出一位来,精度也就提升了一位。
  • IEEE的五种实体

实体 阶码E 尾数F
零0 全0 全0
非规格化数 全0 非全0
规格化数 [1,254] F
无穷大 全1 全0
非数NaN 全1 非全0
  • 还记得没编入阶码的 全0 和 全1 吗,这两种状态分别与尾数的全0和非全0组合成了四种特殊情况,分别表示了除了规格化数之外的四种实体,这也使得IEEE在处理浮点数操作的时候变更为灵活
  • 非数是Kahan的一个创新,其目的是当浮点运算发生一些特殊情况的时候,软件可以根据NaN的内容进行相应的处理,从而减少了特殊情况下软件处理的工作量
    • 非数分为“发信号的非数”Signaling NaN 和“静默的非数”Quiet NaN两类
    • “发信号的非数”用于在出现无效运算时发出异常信号
    • “静默的非数”只记录发生的特殊请况,而不发出异常信号,比如

      (+∞)±(?∞)

      0?∞

      0/0

      负数????√

    • 非数的有效部分是尾数,用于区分“发信号”还是“静默”,并可以指明是那种异常情况产生了这个非数,从而可以根据非数的内容进行处理。对于不同异常情况对应的编码标准没有规定,不同的实现方案可以有不同的尾数编码方案。
  • 非规格化数也是一种特殊的处理方案,目的是为了避免出现下溢,从而允许用非规格化的形式来表示很小的数,而此时隐藏位就不在是 1 而是 0 了,因为已经不是规格化的范围。这种方案也叫“逐渐下溢(Gradual Underflow)”
时间: 2024-10-12 16:12:28

计算机组成.运动中的小数点.浮点数的相关文章

Unity游戏开发的数学与物理 4 ( 在物体运动中加入重力 )

在物体运动中加入重力 实现注意: 使用级数叠加算法 y += vy; //对位置上的加速度 vy += GR: //速度上的加速度 GR为重力加速度,在计算机中使用的加速度单位是特殊的dot/F^2 (像素/平方帧),而不是9.8 m/s^2 (米/平方秒) 微分是一种操作,是一种求微分系数的操作, 而微分系数是指函数关于某个值的变化率,这个概念在游戏开发中经常被用来考察某个函数变化的速度; f(x)关于x的变化率,基本的微分公式 d/dx(x) = 1 d/dx(x^2) = 2x d/dx(

【Cocos2d-html5】运动中速度效果

在我们使用Action系统动作的时候,比如MoveTo,在进行运动的时候总是在规定的时间内进行匀速运动,有时候可能会想添加一些加速度的效果,cocos2d-html5就依然和cocos2dx一样为我们提供了这套. 主要分为5种运动速度效果: 第1种  指数缓冲 [javascript] view plain copy cc.EaseExponentialIn.create(); cc.EaseExponentialOut.create(); cc.EaseExponentialInOut.cre

浅议计算机在金融业中的应用

近年来,计算机技术在人们的日常工作生活中得到了广泛的应用.它贯穿于各个行业的方方面面,预示着我国的电子计算机技术得到深入的发展.同样的,电子计算机技术在金融行业中也得到了广泛的应用,促进了我国金融行业的变革.但是,计算机在我国现阶段金融业中的应用水平还很差,同时也面临着许多挑战.通过分析存在的问题,找到解决问题的措施.总结经验,从而尽快改变计算机在我国金融业中的应用. 金融软件开发就显得十分的重要.中国论文网 http://www.xzbu.com/9/view-5085577.htm 计算机金

avascript 运动中Offset的bug解决方案

这篇文章主要介绍了Javascript 运动中Offset的bug解决方案,需要的朋友可以参考下 我们先来看看这个bug 是怎么产生的. 代码如下: 1 <style type="text/css"> 2 #div1 { 3 width: 200px; 4 height: 200px; 5 background: red; 6 7 } 8 </style> 代码如下: 1 <body> 2 <div id="div1">

JS运动中的封装的部分实用函数(框架)总结

JS运动中的封装的部分实用函数(框架)总结 前段时间学习JS运动时做的很实用的几个函数,应该可以称之为小的框架了,现在总结一下.为什么不当时就总结呢?我认为所谓总结不是趁着大脑中还残留着对新知识印象的时候将其写下来,而是过了一段时间之后再回头去看,将其重新拾起,这个时候一般会有对这些新东西的新看法和新的体会,我把这个过程称为"知识的发酵".对于我来说经过 "发酵"之后的带有自己的见解和体会东西才可以称之为总结. 下面分为几个版本来说,也反映了他们的进化过程,这几个函

C/C++中整数与浮点数在内存中的表示方式

在C/C++中数字类型主要有整数与浮点数两种类型,在32位机器中整型占4字节,浮点数分为float,double两种类型,其中float占4字节,而double占8字节.下面来说明它们在内存中的具体表现形式: 整型: 整型变量占4字节,在计算机中都是用二进制表示,整型有无符号和有符号两种形式. 无符号变量在定义时只需要在相应类型名前加上unsigned 无符号整型变量用32位的二进制数字表示,在与十进制进行转化时只需要知道计算规则即可轻松转化.需要注意的是在计算机中一般使用主机字节序,即采用“高

Java中的简单浮点数类型float和double不能够进行精确运算

在java中,简单的浮点类型float和double是不能够进行运算.我们先看下面的两个程序代码: 代码一: import java.util.Scanner; class Circle { double radius; static final double PI=3.14; public Circle(){this.radius=0;} public Circle(double r){this.radius=r;} public double getArea(){return PI*this

Python中整数和浮点数

Python支持对整数和浮点数直接进行四则混合运算,运算规则和数学上的四则运算规则完全一致. 基本的运算: 1 + 2 + 3 # ==> 6 4 * 5 - 6 # ==> 14 7.5 / 8 + 2.1 # ==> 3.0375 使用括号可以提升优先级,这和数学运算完全一致,注意只能使用小括号,但是括号可以嵌套很多层: (1 + 2) * 3 # ==> 9 (2.2 + 3.3) / (1.5 * (9 - 0.3)) # ==> 0.4214559386973180

java中两个浮点数进行比较

进行比较因为浮点数在计算机中不准确 所以判定==时会出错 解决方式 double preErrorKey=1e-6; //1*10的-6次方即0.000001 double key1=0.0000001d; double key2=0d; // System.out.println(key1==key2); //结果是flase // System.out.println(Math.abs(key1-key2)<preErrorKey); if(Math.abs(daohuoshuliang-