浮点数的表示和基本运算 【转载】

1 浮点数的表示

通常,我们可以用下面的格式来表示浮点数

SPM


其中S是符号位,P是阶码,M是尾数

对于IBM-PC而言,单精度浮点数是32位(即4字节)的,双精度浮点数是64位(即8字节)的。两者的S,P,M所占的位数以及表示方法由下表可知

SPM表示公式偏移量
1823(-1)S*2(P-127)*1.M127
11152(-1)S*2(P-1023)*1.M1023


以单精度浮点数为例,可以得到其二进制的表示格式如下

S(第31位)P(30位到23位)M(22位到0位)

其中S是符号位,只有0和1,分别表示正负;P是阶码,通常使用移码表示(移码和补码只有符号位相反,其余都一样。对于正数而言,原码,反码和补码都一样;对于负数而言,补码就是其绝对值的原码全部取反,然后加1.)

为了简单起见,本文都只讨论单精度浮点数,双精度浮点数也是用一样的方式存储和表示的。

2 浮点数的表示约定

单精度浮点数和双精度浮点数都是用IEEE754标准定义的,其中有一些特殊约定。

(1) 当P = 0, M = 0时,表示0。

(2) 当P = 255, M = 0时,表示无穷大,用符号位来确定是正无穷大还是负无穷大。

(3) 当P = 255, M != 0时,表示NaN(Not a Number,不是一个数)。

当我们使用.Net Framework的时候,我们通常会用到下面三个常量

Console.WriteLine(float.MaxValue); //3.402823E+38
Console.WriteLine(float.MinValue);  //-3.402823E+38
Console.WriteLine(float.Epsilon);    //1.401298E-45
//如果我们把它们转换成双精度类型,它们的值如下
Console.WriteLine(Convert.ToDouble(float.MaxValue)); //3.40282346638529E+38
Console.WriteLine(Convert.ToDouble(float.MinValue));  //-3.40282346638529E+38
Console.WriteLine(Convert.ToDouble(float.Epsilon));    //1.40129846432482E-45

那么这些值是如何求出来的呢?

根据上面的约定,我们可以知道阶码P的最大值是11111110(这个值是254,因为255用于特殊的约定,那么对于可以精确表示的数来说,254就是最大的阶码了)。尾数的最大值是11111111111111111111111。

那么这个最大值就是:0 11111110 11111111111111111111111。

也就是 2(254-127) * (1.11111111111111111111111)2 = 2127 * (1+1-2-23) = 3.40282346638529E+38

从上面的双精度表示可以看出,两者是一致的。最小的数自然就是-3.40282346638529E+38。

对于最接近于0的数,根据IEEE754的约定,为了扩大对0值附近数据的表示能力,取阶码P = -126,尾数 M = (0.00000000000000000000001)2 。此时该数的二进制表示为:0 00000000 00000000000000000000001

也就是2-126 * 2-23 = 2-149 = 1.40129846432482E-45。这个数字和上面的Epsilon是一致的。

如果我们要精确表示最接近于0的数字,它应该是 0 00000001 00000000000000000000000

也就是:2-126 * (1+0)  =  1.17549435082229E-38。 

3 浮点数的精度问题

浮点数以有限的32bit长度来反映无限的实数集合,因此大多数情况下都是一个近似值。同时,对于浮点数的运算还同时伴有误差扩散现象。特定精度下看似相等的两个浮点数可能并不相等,因为它们的最小有效位数不同。

由于浮点数可能无法精确近似于十进制数,如果使用十进制数,则使用浮点数的数学或比较运算可能不会产生相同的结果。

如果涉及浮点数,值可能不往返。值的往返是指,某个运算将原始浮点数转换为另一种格式,而反向运算又将转换后的格式转换回浮点数,且最终浮点数与原始浮点数相等。由于一个或多个最低有效位可能在转换中丢失或更改,往返可能会失败。 

4 将浮点数表示为二进制

4.1 无小数的浮点数转换成二进制表示

首先,我们用一个不带小数的浮点数来说明如何将一个浮点数转换成二进制表示。假设要转换的数据是45678.0f。

在处理这种不带小数的浮点数时,直接将整数部分转化为二进制表示:

1011001001101110.0

然后将小数点向左移,一直移到离最高位只有1位,也就是 1.011001001101110,一共移动了15位,我们知道,左移位表示乘法,右移位表示除法。所以原数就等于这样:1.011001001101110 * ( 215 )。现在尾数和指数都出来了。尾数的二进制就变成了:011001001101110。

最后在尾数的后面补0,一直到补够23位,就是:011001001101110000000000。

再回来看指数,根据前面的定义,P-127=15,那么P = 142,表示成二进制就是:10001110。

45678.0f这个数是正的,所以符号位是0,那么我们按照前面讲的格式把它拼起来,就是:0 10001110 01100100110111000000000。

这就是45678.0f这个数的二进制表示,如果我们要得到16进制的表示,非常简单,我们只需要把这个二进制串4个一组,转换成16进制数就可以了。但是要注意的是x86架构的CPU都是Little Endian的(也就是低位字节在前,高位字节在后),所以在实际内存中该数字是按上面二进制串的倒序存储的。要知道CPU是不是little endian的也很容易。

4.2 含小数的浮点数表示为二进制

对于含小数的浮点数,会有精度的问题,下面举例说明。假设要转换的小数为123.456f。

对于这种带小数的就需要把整数部和小数部分开处理。对于整数部分的处理不再赘述,直接化成二进制为:1111011。小数部份的处理比较麻烦一些,我们知道,使用二进制表示只有0和1,那么对于小数就只能用下面的方式来表示:

a1*2-1+a2*2-2+a3*2-3+......+an*2-n

其中a1等数可以是0或者1,从理论上将,使用这种表示方法可以表示一个有限的小数。但是尾数只能有23位,那么就必然会带来精度的问题。

在很多情况下,我们只能近似地表示小数。来看0.456这个十进制纯小数,该如何表示成二进制呢?一般说来,我们可以通过乘以2的方法来表示。

首先,把这个数字乘以2,小于1,所以第一位为0,然后再乘以2,大于1,所以第二位为1,将这个数字减去1,再乘以2,这样循环下去,直到这个数字等于0为止。

在很多情况下,我们得到的二进制数字都大于23位,多于23位的就要舍去。舍入原则是0舍1入。通过这样的办法,我们可以得到二进制表示:1111011.01110100101111001。

现在开始向左移小数点,一共移了6位,这时候尾数为:1.11101101110100101111001,阶码为6加上127得131,二进制表示为:10000101,那么总的二进制表示为:

0  10000101  11101101110100101111001

表示成十六进制是:42  F6  E9  79

由于CPU是Little Endian的,所以在内存中表示为:79  E9  F6  42。

4.3 将纯小数表示成二进制

对于纯小数转化为二进制来说,必须先进行规格化。例如0.0456,我们需要把它规格化,变为1.xxxx * (2n )的形式,要求得纯小数X对应的n可用下面的公式:
n = int( 1 + log 2X )

0.0456我们可以表示为1.4592乘以以2为底的-5次方的幂,即1.4592 * ( 2-5 )。转化为这样形式后,再按照上面处理小数的方法处理,得到二进制表示

1. 01110101100011100010001

去掉第一个1,得到尾数

01110101100011100010001

阶码为:-5 + 127 = 122,二进制表示为

0  01111010  01110101100011100010001

最后转换成十六进制
11 C7 3A 3D
5 浮点数的数学运算

5.1 浮点数的加减法

设两个浮点数 X=Mx*2Ex ,Y=My*2Ey

实现X±Y要用如下5步完成:

(1)对阶操作:小阶向大阶看齐
(2)进行尾数加减运算
(3)规格化处理:尾数进行运算的结果必须变成规格化的浮点数,对于双符号位(就是使用00表示正数,11表示负数,01表示上溢出,10表示下溢出)的补码尾数来说,就必须是
001×××…×× 或110×××…××的形式
若不符合上述形式要进行左规或右规处理。
(4)舍入操作:在执行对阶或右规操作时常用“0”舍“1”入法将右移出去的尾数数值进行舍入,以确保精度。
(5)判结果的正确性:即检查阶码是否溢出

若阶码下溢(移码表示是00…0),要置结果为机器0;
若阶码上溢(超过了阶码表示的最大值)置溢出标志。

现在用一个具体的例子来说明上面的5个步骤

例题:假定X=0 .0110011*211,Y=0.1101101*2-10(此处的数均为二进制), 计算X+Y;

首先,我们要把这两个数变成2进制表示,对于浮点数来说,阶码通常用移码表示,而尾数通常用补码表示。

要注意的是-10的移码是00110
        [X]: 0        1 010  1100110
        [Y]: 0        0 110  1101101
                   符号位 阶码   尾数

(1)求阶差:│ΔE│=|1010-0110|=0100

(2)对阶:Y的阶码小,Y的尾数右移4位
        [Y]变为 0 1 010 0000110 1101暂时保存 

(3)尾数相加,采用双符号位的补码运算 
     00 1100110 
   +00 0000110 
     00 1101100

(4)规格化:满足规格化要求 

(5)舍入处理,采用0舍1入法处理

故最终运算结果的浮点数格式为: 0 1 010 1101101

即X+Y=+0. 1101101*210 

5.2 浮点数的乘除法

(1)阶码运算:阶码求和(乘法)或阶码求差(除法)
    即  [Ex+Ey]移= [Ex]移+ [Ey]补 
          [Ex-Ey]移= [Ex]移+  [-Ey]补
(2)浮点数的尾数处理:浮点数中尾数乘除法运算结果要进行舍入处理

例题:X=0 .0110011*211,Y=0.1101101*2-10  求X*Y

解:[X]: 0 1 010 1100110
        [Y]: 0 0 110 1101101

(1)阶码相加 
[Ex+Ey]移=[Ex]移+[Ey]补=1 010+1 110=1 000 
1 000为移码表示的0

(2)原码尾数相乘的结果为:
0 10101101101110

(3)规格化处理:已满足规格化要求,不需左规,尾数不变,阶码不变。

(4)舍入处理:按舍入规则,加1进行修正

所以 X※Y= 0.1010111*20
原文链接:http://www.cnblogs.com/FlyingBread/archive/2009/02/15/660206.html

转载于:https://www.cnblogs.com/xiaojiaohuazi/archive/2013/03/29/2988309.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/266251.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python list长度_python的入门阶段 编程思维100题 我跟罗志祥没关系

"""python的入门阶段 编程思维100题(适合学习了1周--1个月的新人) 第五题:我跟罗志祥没关系 朋友圈大家每天都看,那用python如何实现它那? 很简单,朋友的信息(名字,头…

全国计算机等级考试题库二级C操作题100套(第75套)

第75套&#xff1a; 给定程序中&#xff0c;函数fun的功能是&#xff1a;对形参ss所指字符串数组中的M个字符串按长度由短到长进行排序。ss所指字符串数组中共有M个字符串&#xff0c;且串长<N。请在程序的下划线处填入正确的内容并把下划线删除&#xff0c;使程序得出正确…

php7过滤,PHP7过滤unserialize()

PHP7引入了过滤 unserialize()函数以在反序列化不受信任的数据对象时提供更好的安全性。它可以防止可能的代码注入&#xff0c;使开发人员能够使用序列化白名单类。示例class MyClass1 {public $obj1prop;}class MyClass2 {public $obj2prop;}$obj1 new MyClass1();$obj1->…

windows系统查找文件-通配符的使用

在windows中可以使用通配符“* ”、“? ”查找文件。对于相同字符开头的单词和相同字符结尾的单词可以用“<”和“ >”通配符查找单词。1、如果要查找&#xff1a; 任意单个字符 &#xff1a;键入 ? 例如&#xff0c;s?t 可查找“sat”和“set”……。2、任意字符串 :…

python为什么是动态语言_python为什么是动态语言

首先要理解什么是动态语言&#xff1a;通俗地说&#xff1a;能够在运行时修改自身程序结构的语言&#xff0c;就属于动态语言。那怎样才算是“运行时修改自身程序结构”呢&#xff1f;比如下面这几个例子都算&#xff1a;在运行时给某个类增加成员函数及成员变量&#xff1b;在…

Android ----中文Api 百度地图

Android中文API最新中文版 [复制链接] kupekupe当前离线在线时间1 小时e望0 点最后登录2011-2-17注册时间2011-2-17积分12阅读权限10UID1341171 主题 0 好友 12 积分No.1 开发小菜鸟 No.1 开发小菜鸟, 积分 12, 距离下一级还需 88 积分升级 12% 当前用户组为 No.1 开发小菜鸟 …

全国计算机等级考试题库二级C操作题100套(第76套)

第76套&#xff1a; 给定程序中&#xff0c;函数fun的功能是&#xff1a;计算下式前n项的和作为函数值返回。 例如&#xff0c;当形参n的值为10时&#xff0c;函数返回&#xff1a;-0.204491。请在程序的下划线处填入正确的内容并把下划线删除,使程序得出正确的结 果。 注意&a…

正在启动oracle universal,oracle的常见问题与解决

刚接触oracle,在学习过程中遇到了很多的问题&#xff0c;本文章将会收藏我遇到的问题及如何解决。错误一&#xff1a;ORA-28009:connection as sys should be as sysdba解决方法:用户名称&#xff1a;sys,口令&#xff1a;password,主机字符串:orcl as sysdba(我设置的全局数据…

高性能MySQL(二)

MySQL基准测试 为什么需要benchmark 验证基于系统的假设&#xff0c;确认是否符合实际情况重现系统中的某些异常行为&#xff0c;以解决它们测试系统当前的运行情况&#xff0c;如果不清楚当前性能&#xff0c;就无法确认优化效果模拟比当前系统更高的负载&#xff0c;用于找出…

python的用算法进制转换详解_学习python第五天进制转换

6.进制之间的转换(重要)二进制&#xff1a;满二进一 范围&#xff1a;0、1符号:0b例如&#xff1a;0b10...【注意】计算机只能识别二进制数据八进制&#xff1a;满八进一 范围&#xff1a;0~7符号:0o例如&#xff1a;0o66十进制&#xff1a;满十进一 范围&#xff1a;0~9十六进…

android之多媒体篇(一)

2019独角兽企业重金招聘Python工程师标准>>> Android 4.0.3(Api Level 15&#xff09;支持的多媒体格式。 注意&#xff1a;有些设备可能支持其他的文件格式。 1.Audio AAC LC/LTP、HE-AACv1(AAC)、AMR-NB、AMR-WB、MP3、MIDI、Ogg Vorbis、PCM/WAVE、FLAC&#…

全国计算机等级考试题库二级C操作题100套(第77套)

第77套&#xff1a; 给定程序中&#xff0c;函数fun的功能是&#xff1a;将形参n中&#xff0c;各位上为偶数的数取出&#xff0c;并按原来从高位到低位相反的顺序组成一个新的数&#xff0c;并作为函数值返回。 例如&#xff0c;输入一个整数&#xff1a;27638496&#xff0c…

第二章:用户登录管理模块

本章简介 1.项目分层 2.创建MyHibernateSessionFactory 3.设计用户接口和实现类 4.设计所有Action父类 5.设计用户Action类 6.页面调用 7.完成显示登录成功用户名和注销功能 8.显示报错信息 1.项目分层 实体层&#xff08;模型层&#xff09;&#xff1a;entity包 学生类、用户…

python组合数据分类_Python 数据可视化:分类特征统计图

上一课已经体验到了 Seaborn 相对 Matplotlib 的优势&#xff0c;本课将要介绍的是 Seaborn 对分类数据的统计&#xff0c;也是它的长项。针对分类数据的统计图&#xff0c;可以使用 sns.catplot 绘制&#xff0c;其完整参数如下&#xff1a;seaborn.catplot(xNone, yNone, hue…

MongoDB 主从集群配置

创建必要的目录和认证文件&#xff1a; [rootmongo mongo]# mkdir keyfile [rootmongo mongo]# echo "mongo cluster one" > keyfile/m1[rootmongo mongo]# echo "mongo cluster one" > keyfile/m2[rootmongo mongo]# echo "mongo cluster one&…

linux进程互斥要点,linux进程之间互斥

总所周知&#xff0c;在linux中pthread_mutex_t可以用于同一进程内多个线程之间的同步。我们所需要做的工作&#xff0c;仅仅是定义一个全局的pthread_mutex_t类型变量即可。但是对于进程之间的互斥&#xff0c;就没有那么简单了。我们必须将pthread_mutex_t类型变量放到各个进…

java定时器_拾遗Timer定时器

一 Timer 介绍在开发中我们经常会遇到一些简单定时任务的需求&#xff0c;而不需要量级较重的定时任务就可以采取java定时器&#xff1b;java.util.Timer工具类中的Timer 是定时器&#xff0c;但定时任务写在java.util.TimerTask 中&#xff0c;由 Timer 执行 TimerTask &#…

逻辑门电路的知识点归纳

1.半导体二极管与MOS管的开关特性 二极管&#xff1a;正向导通&#xff0c;反向截止&#xff0c;但是要注意的是从反向截止到正向导通的时间极其短&#xff0c;但是从正向导通到反向截止要经过反向恢复&#xff08;电荷存储效应&#xff09;的过程&#xff0c;这个过程实际上就…

全国计算机等级考试题库二级C操作题100套(第78套)

第78套&#xff1a; 给定程序中&#xff0c;函数fun的功能是:将NN矩阵主对角线元素中的值与反向对角线对应位置上元素中的值进行交换。例如&#xff0c;若N3&#xff0c;有下列矩阵&#xff1a; 1 2 3 4 5 6 7 8 9 交换后为&#xff1a; 3 2 1 4 5 6 9 8 7 请在程序的下划线处…

善心

2019独角兽企业重金招聘Python工程师标准>>> 一个穷苦学生郝武德.凯礼&#xff0c;为了付学费&#xff0c;挨家挨户地推销货品。 到了晚上&#xff0c;发现自己的肚子很饿&#xff0c;而口袋里只剩下一个小钱。他在大街上犹豫徘徊了半天&#xff0c;终于鼓起勇气&a…