浮点数原理探究

一、文章来由

今天听到实验室有人问道浮点数的实现机制,之前刚好研究过原码、反码、补码、移码的关系,而这类问题很底层,一般容易忽视。干脆打破沙锅问到底,彻底搞清楚这个问题并留下证据,于是就有了这篇博文。

二、原码、反码、补码、移码

不要背复杂的公式,简记如下,都是用的最简单易懂的语言:

特别注意:首先要说明的是,正数的原、反、补码都一样;0的原码跟反码都有两个,因为这里0被分为+0和-0。

原码:

即直接的二进制表示,最高位为符号位:正数为0,负数为1 例如: X=+101011 , [X]原= 00101011

X=-101011 , [X]原= 10101011 位数不够的用0补全。

反码:

正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。 例如:X=-101011 , [X]原= 10101011,[X]反=11010100

补码:

正数的补码与其原码相同;负数的补码是在其反码的末位加1。

例如:X=-101011 , [X]原= 10101011,[X]反=11010100,[X]补=11010101

注:补码还有一种速算法,符号位不变,从原码低位开始从右向左数,直到遇到第一个1,保留这个1,以后的按位取反

PS:0的补码是唯一的,如果机器字长为8那么 [0]补=00000000

移码【最简单】:

不论正负数,只要将其补码的符号位取反即可。

例如:X=-101011 , [X]原= 10101011 ,[X]反=11010100,[X]补=11010101,[X]移=01010101

三、从定点到浮点

首先定点到浮点是一个飞跃,这里面的内容其实可以很简单也可以很复杂。我们一般说的整数都是定点整数,即小数点固定最后一位。但是整数既可以是整数,也可以是浮点数,例如255 是整数,而255.0 则是浮点数。

什么是浮点数?这需要从小数的表示讲起:

3.1 浮点数的表示

计算机中一个任意进制数 N 可以写成

m :尾数,是一个纯小数。

e :浮点的指数, 是一个整数。

R :基数,对于二进计数值的机器是一个常数,一般规定R 为2,8或16

尾数主要是决定有效位,阶码主要表示位数(小数点位置)。

阶码:用定点整数形式表示,指明小数点在数据中的位置,决定了浮点数的表示范围,常用补码或者移码表示

尾数: 决定了浮点数的数值精度,是定点小数,用补码表示,也决定了整个浮点数的符号

机器字长一定时,阶码越长,表示范围越大,精度越低

浮点数表示范围比定点数大,精度高

画一个简单易懂的表格:

c语言float型数表示

符号位(S) 阶码(E) 尾数(M)
1 8 23

浮点数表示范围如下图:

例:

8位定点小数可表示的范围

0.0000001 — 0.1111111

1/128 — 127/128

设阶码2位,尾数4位

可表示2-11*0.0001 — 211*0.1111

0.0000001 — 111.1

设阶码3位,尾数3位

可表示2-111*0.001 — 2111*0.111

0.0000000001 — 1110000

注:float和double的范围是由指数的位数来决定的。

float的指数位有8位,而double的指数位有11位,分布如下:

float:

1bit(符号位) 8bits(指数位) 23bits(尾数位)

double:

1bit(符号位) 11bits(指数位) 52bits(尾数位)

3.2 浮点数的规格化

规格化目的:

(1)为了提高数据的表示精度

(2)为了数据表示的唯一性

(3)尾数为R进制的规格化: 绝对值大于或等于1/R

二进制原码的规格化数的表现形式:

正数 0.1xxxxxx

负数 1.1xxxxxx

补码尾数的规格化的表现形式:尾数的最高位与符号位相反:

正数 0.1xxxxxx

负数 1.0xxxxxx

【32位浮点数,IEEE754采用127做阶码的偏移量】

IEEE754规定这个偏移量为2^(e-1)-1,e为存储指数的位元的长度,在32位浮点数中存储指数的域有8位因此偏移量位2^(8-1)-1=127。这里根据标准,并没有使用移码作为阶码

**注意IEEE754中的移码和通常用的移码不相同,IEEE754用的是127移码,即在原数上加127

而不是通常的128移码(也就是所说的补码符号位取反)**

例1:

如果反过来求就是,

例2

例3

3.3 移码的来由

一个很有意思的问题

说了这么多,由移码当阶码,到移码-1到阶码,都不知道为什么,现在就来看看。

根据百度百科移码上说的:

移码(又叫增码)是符号位取反的补码,一般用做浮点数的阶码,引入的目的是为了保证浮点数的机器零为全0。

原因是:

用补码表示阶码的时候,当阶码无限小,产生了下溢的时候,阶码变成了0,那么这个浮点数的值变为了1。

而实际上这个数是无限接近于零的。那么我们就需要取出其中的 “-0“ 值作为机器零。

详细解释如下:

因为浮点数的表示是1.s * (2 ^ P), 所以浮点数0实际上是取无限接近于0,而不是其数值上确实得等于0

0的表示实际上是1.0 * (2 ^ -128),其中-128是阶码能表示的最小数

于是问题来了,如果用补码表示, -128实际上是10000000, 那么浮点数的0其数值就不能等于0. 所以采用移码.

但是IEEE754标准采用的是127移码,即在0的基础上加上127作为0,于是阶码表示范围是-127 - 128,而不是通常的-128 - 127

文章也基本上要告一段落了,这些应该已经可以对付日常理解,如果需要更深刻的理解,就需要查阅更多资料,如果博文中有不当的内容,欢迎批评指正,也欢迎讨论

附:

c++中,合法的浮点数表示形式:

(1)十进制小数形式。他有数字和小数点组成,必须有小数点。例如(123.)(123.0)(.123)。

(2)指数形式。如123e3。字母e(或E)之前必须有数字,e后面的指数必须为整数。

(3)规范化的指数形式里面,小数点前面有且只有一位非零的数字。如1.2345e8

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-29 00:51:17

浮点数原理探究的相关文章

《coredump问题原理探究》Windows版 笔记

<coredump问题原理探究>Windows版 笔记 Debug 一.环境搭建 1.Win7捕获程序dump 2.Windbg符号表设置(Symbols Search Path) 二.WinDbg命令 三.函数栈帧 1.栈内存布局 2.栈溢出 3.栈的规律 4.定位栈溢出问题的经验方法 四.函数逆向 五.C内存布局 1.基本类型 2.数组类型 3.结构体 六.C++内存布局 1.类的内存布局 2.this指针 3.虚函数表及虚表指针 4.单继承 5.多继承(无公共基类) 七.STL容器内存布

Cocos2d-x 3.2:定时器的使用和原理探究(2)

Cocos2d-x 3.2:定时器的使用和原理探究(2) 本文转载至深入了解Cocos2d-x 3.x:定时器的使用和原理探究(2) 上一篇说到定时器的使用方法,这篇主要分析它的实现原理. 1.哈希链表 Cocos2d-x封装了一个结构体,叫做UT_hash_handle,只要在自定义的结构体中声明这个结构体变量,就实现了哈希链表,并且能使用一系列的哈希链表专用的宏.这个结构体的具体实现如下: 1 2 3 4 5 6 7 8 9 10 typedef struct UT_hash_handle 

Cocos2d-x 3.2:定时器的使用和原理探究(1)

Cocos2d-x 3.2:定时器的使用和原理探究(1) 本文转载至深入了解Cocos2d-x 3.x:定时器的使用和原理探究(1) 注:本文开始,引擎升级到Cocos2d-x 3.6 在游戏开发过程中,经常会遇到使用计时器的情况,例如:倒计时,定时炸弹等.scheduler是Cocos2d-x 2.x时代就已经存在的产物,主要用于各种延时函数以及各种每帧运行的函数.本文主要介绍scheduler的API函数以及使用方法. 首先,所有继承Node的类都可以使用scheduler,以下是Node类

zookeeper使用和原理探究(一)(转)

zookeeper介绍zookeeper是一个为分布式应用提供一致性服务的软件,它是开源的Hadoop项目中的一个子项目,并且根据google发表的<The Chubby lock service for loosely-coupled distributed systems>论文来实现的,接下来我们首先来安装使用下这个软件,然后再来探索下其中比较重要一致性算法. zookeeper安装和使用zookeeper的安装基本上可以按照 http://hadoop.apache.org/zookee

vmware nat模式原理探究,实现虚拟机跨网段管理

vmware nat模式原理探究: 理解nat模式,我们能更加了解主机与虚拟机之间如何通信,以及虚拟机如何实现上网. 以及便于我们分析虚拟机与主机无法通信和无法上外网的问题. 下面通过实战:虚拟网络拓扑,抓包分析. 为什么要探究nat模式? 从日常需求出发: 我们电脑上用到的虚拟机越来越多,需要固定IP,方便管理. 网络环境经常会变,我们可能在家办公和在公司办公网段不一样,每次要改为同一个网段再连接使用,比较麻烦. 首先理解vmware的三种模式: bridge模式:相当于一台hub,真实主机与

Cocos2d-x 3.2:定时器的使用和原理探究(3)

Cocos2d-x 3.2:定时器的使用和原理探究(3) 本文转载至[深入了解cocos2d-x 3.x]定时器(scheduler)的使用和原理探究(3) 上篇文章分析到了定时器的定义,这篇的重点就是定时器是如何运行起来的. 1.从main中寻找定时器的回调 讲定时器的运行,就不得不触及到cocos2dx的main函数了,因为定时器是主线程上运行的,并不是单独线程的,所以它的调用必然会在main函数中,每帧调用. 以下代码就是win32平台下的main函数 [cpp] view plainco

DNN原理探究系列之目录与序章篇

序言: 神经网络结构,作为最成功的机器学习模型之一,其工作原理一直被埋藏得比较深,其解释性以至于被称为黑盒. 自己对于DNN的理解也只能算刚踏入了门槛,对于人脑的原理与DNN原理之间的互通性,一直是非常深信的,所以想一窥DNN成功背后的数学原理. 通过DNN原理探究系列博文,希望能总结归纳已经理解的知识点,梳理清楚知识点之间的关系结构,同时探讨各种流派对于DNN原理的解读. 目录会随着自己掌握的知识量逐渐扩展新的分支,以此记录自己的学习历程. 当前知识结构树(2017-11-11) DNN结构与

go---&gt;共享内存和通信两种并发模式原理探究

共享内存和通信两种并发模式原理探究 并发理解 人类发明计算机编程的本质目的是为了什么呢?毫无疑问是为了解决人类社会中的各种负责业务场景问题.ok,有了这个出发点,那么想象一下,比如你既可以一心一意只做一件事,你也可以同时做多件事,比如,你计划今天上午计划就是看足球比赛,ok,你今天的工作就是串行的,单进程的,你只需要完成一件事.但是不巧呢,你妈妈说让你帮她切肉,你妈妈上午要出门有点事,同时不巧呢,你老婆说她上午也要出门,让你帮着打扫家里卫生,这时你今天就要同时做三件事,看比赛,切肉,打扫卫生.这

ThreadPoolExcutor 原理探究

概论 线程池(英语:thread pool):一种线程使用模式.线程过多会带来调度开销,进而影响缓存局部性和整体性能.而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务.这避免了在处理短时间任务时创建与销毁线程的代价.线程池不仅能够保证内核的充分利用,还能防止过分调度.可用线程数量应该取决于可用的并发处理器.处理器内核.内存.网络 sockets 等的数量. 例如,线程数一般取 cpu 数量 +2 比较合适,线程数过多会导致额外的线程切换开销. Java 中的线程池是用 ThreadP