-
浮点数
2020-04-02 22:16:51浮点数基本格式浮点数的表示格式化表示范围IEEE 754标准 基本格式 浮点数的表示 r进制: 定点数:如纯小数0.1011和纯整数11110 浮点数: 浮点数的真值: 阶码(E): 常用补码或移码表示 反映浮点数的表示范围及...基本格式
浮点数的表示
r进制:
定点数:如纯小数0.1011和纯整数11110
浮点数:
- 浮点数的真值:
- 阶码(E):
- 常用补码或移码表示
- 反映浮点数的
表示范围
及小数点的实际位置
- 尾数(M):常用原码或补码表示
- 数值部分的位数n反映浮点数的
精度
- 数值部分的位数n反映浮点数的
十进制:
299792458m/s =2.998*108 m/s 定点数 浮点数 需要9个数据的位 需要5个数据的位(会损失精度)
由上图可知,b需要9位,而只能提供8位,所以需要进行规格化
格式化
规格化:规定尾数的最高位必须是一个有效值。对于二进制来说,要求最高位是1;对于其他进制来说,要求最高位非0
表示范围
(n 为尾数的尾数)
(负数由原码取反+1得来的)
由
小数就是以上向右移2位,即除以4得
正上溢和负上溢会错误中断
IEEE 754标准
数符:决定整个数的正负
隐藏表示最高位1放在小数点左边,尾数放在右边,因为规格化后尾数的最高位为1,为节约空间,故省去
建议采取空间记忆
1000 0001 1100 1010 0101 0000 1000 0000
依次为:数符 阶码 尾数数值
偏置值:阶码10000000-1=01111111=127(阶码最高位为1,后面全为0,减去1得到的值为偏置值)
- 浮点数的真值:
-
IEEE754 浮点数的表示方法
2016-01-09 17:08:191.浮点数的存储格式 浮点数在C/C++中对应float和double类型,我们有必要知道浮点数在计算机中实际存储的内容。 IEEE754标准中规定float单精度浮点数在机器中表示用 1 位表示数字的符号,用 8 位来表示指数,用...1.浮点数的存储格式
浮点数(Floating-point Number)是对实数的一种近似表示,由一个有效数字(即尾数)加上幂数来表示,通常是乘以某个基数的整数次幂得到。以这种表示法表示的数值,称为浮点数。表示方法类似于基数为10的科学计数法。利用浮点进行运算,称为浮点计算,这种运算通常伴随着因为无法精确表示而进行的近似或舍入。
计算机对浮点数的表示规范遵循电气和电子工程师协会(IEEE)推出的 IEEE754 标准,浮点数在 C/C++ 中对应 float 和 double 类型,我们有必要知道浮点数在计算机中实际存储的内容。
IEEE754 标准中规定 float 单精度浮点数在机器中表示用 1 位表示数字的符号,用 8 位表示指数,用 23 位表示尾数,即小数部分。对于 double 双精度浮点数,用 1 位表示符号,用 11 位表示指数,52 位表示尾数,其中指数域称为阶码。IEEE754 浮点数的格式如下图所示。
注意,IEE754 规定浮点数阶码 E 采用"指数e的移码-1"来表示,请记住这一点。为什么指数移码要减去 1,这是 IEEE754 对阶码的特殊要求,以满足特殊情况,比如对正无穷的表示。2.移码
移码(又叫增码)是对真值补码的符号位取反,一般用作浮点数的阶码,引入的目的是便于浮点数运算时的对阶操作。
对于定点整数,计算机一般采用补码的来存储。正整数的符号位为 0,反码和补码等同于原码。负整数符号位为1,原码、反码和补码的表示都不相同,由原码变成反码和补码有如下规则:
(1)原码符号位为1不变,整数的每一位二进制数位求反得反码;
(2)反码符号位为1不变,反码数值位最低位加1得补码。比如,以一个字节 8bits 来表示 -3,那么[−3]原=10000011[-3]_原=10000011[−3]原=10000011,[−3]反=11111100[-3]_反=11111100[−3]反=11111100,[−3]补=11111101[-3]_补=11111101[−3]补=11111101,那么 -3 的移码就是[−3]移=01111101[-3]_移=01111101[−3]移=01111101。
如何将移码转换为真值 -3 呢?先将移码转换为补码,再求值。
3.浮点数的规格化
若不对浮点数的表示作出明确的规定,同一个浮点数的表示就不是唯一的。例如(1.75)10(1.75)_{10}(1.75)10可以表示成1.11×201.11\times 2^01.11×20,0.111×210.111\times2^10.111×21,0.0111×220.0111\times2^20.0111×22等多种形式。当尾数不为0时,尾数域的最高有效位为1,这称为浮点数的规格化。否则,以修改阶码同时左右移动小数点位置的办法,使其成为规格化数的形式。
3.1 单精度浮点数真值
IEEE754 标准中,一个规格化的 32 位浮点数 x 的真值表示为:
x=(−1)S×(1.M)×2ex=(-1)^S\times(1.M)\times2^ex=(−1)S×(1.M)×2e
e=E−127e=E-127e=E−127
其中尾数域值是1.M。因为规格化的浮点数的尾数域最左位总是1,故这一位不予存储,而认为隐藏在小数点的左边。在计算指数 e 时,对阶码E的计算采用原码的计算方式,因此 32 位浮点数的 8bits 的阶码 E 的取值范围是 0 到 255。其中当E为全 0 或者全 1 时,是 IEEE754 规定的特殊情况,下文会另外说明。
3.2 双精度浮点数真值
64 位的浮点数中符号为 1 位,阶码域为 11 位,尾数域为 52 位,指数偏移值是 1023。因此规格化的 64 位浮点数 x 的真值是:
x=(−1)S×(1.M)×2ex=(-1)^S\times(1.M)\times2^ex=(−1)S×(1.M)×2e
e=E−1023e=E-1023e=E−10234.浮点数的具体表示
4.1 十进制到机器码
(1)0.5
0.5=(0.1)20.5=(0.1)_20.5=(0.1)2,符号位S为0,指数为e=−1e=-1e=−1,规格化后尾数为1.0。单精度浮点数尾数域共23位,右侧以0补全,尾数域:
M=[000 0000 0000 0000 0000 0000]2M=[000\ 0000\ 0000\ 0000\ 0000\ 0000]_2M=[000 0000 0000 0000 0000 0000]2阶码E:
E=[−1]移−1=[0111 1111]2−1=[0111 1110]2E=[-1]_移-1=[0111\ 1111]_2-1=[0111\ 1110]_2E=[−1]移−1=[0111 1111]2−1=[0111 1110]2对照单精度浮点数的存储格式,将符号位S,阶码E和尾数域M存放到指定位置,得0.5的机器码:
0.5=[0011 1111 0000 0000 0000 0000 0000 0000]20.5=[0011\ 1111\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000]_20.5=[0011 1111 0000 0000 0000 0000 0000 0000]2。十六进制表示为0.5=0x3f000000。
(2)1.5
1.5=[1.1]21.5=[1.1]_21.5=[1.1]2,符号位为0,指数e=0e=0e=0,规格化后尾数为1.1。尾数域M右侧以0补全,得尾数域:
M=[100 0000 0000 0000 0000 0000]2M=[100\ 0000\ 0000\ 0000\ 0000\ 0000]_2M=[100 0000 0000 0000 0000 0000]2阶码E:
E=[0]移−1=[10000000]2−1=[01111111]2E=[0]_移-1=[1000 0000]_2-1=[0111 1111]_2E=[0]移−1=[10000000]2−1=[01111111]2得1.5的机器码:
1.5=[0011 1111 1100 0000 0000 0000 0000 0000]21.5=[0011\ 1111\ 1100\ 0000\ 0000\ 0000\ 0000\ 0000]_21.5=[0011 1111 1100 0000 0000 0000 0000 0000]2十六进制表示为1.5=0x3fc00000。
(3)-12.5
−12.5=[−1100.1]2-12.5=[-1100.1]_2−12.5=[−1100.1]2,符号位S为1,指数e为3,规格化后尾数为1.1001,尾数域M右侧以0补全,得尾数域:
M=[100 1000 0000 0000 0000 0000]2M=[100\ 1000\ 0000\ 0000\ 0000\ 0000]_2M=[100 1000 0000 0000 0000 0000]2阶码E:
E=[3]移−1=[1000 0011]2−1=[1000 0010]2E=[3]_移-1=[1000\ 0011]_2-1=[1000\ 0010]_2E=[3]移−1=[1000 0011]2−1=[1000 0010]2即-12.5的机器码:
−12.5=[1100 0001 0100 1000 0000 0000 0000 0000]2-12.5=[1100\ 0001\ 0100\ 1000\ 0000\ 0000\ 0000\ 0000]_2−12.5=[1100 0001 0100 1000 0000 0000 0000 0000]2十六进制表示为-12.5=0xc1480000。
用如下程序验证上面的推算,代码编译运行平台Win32+VC++ 2012:
#include <iostream> using namespace std; int main() { float a=0.5; float b=1.5; float c=-12.5; unsigned int* pa=NULL; pa=(unsigned int*)&a; unsigned int* pb=NULL; pb=(unsigned int*)&b; unsigned int* pc=NULL; pc=(unsigned int*)&c; cout<<hex<<"a=0x"<<*pa<<endl; cout<<hex<<"b=0x"<<*pb<<endl; cout<<hex<<"c=0x"<<*pc<<endl; return 0; }
输出结果:
a=0x3f000000 b=0x3fc00000 c=0xc1480000
验证正确。
4.2 机器码到十进制
(1)若浮点数 x 的 IEEE754 标准存储格式为 0x41360000,那么其浮点数的十进制数值的推演过程如下:
0x41360000=[0 10000010 011 0110 0000 0000 0000 0000]0x41360000=[0\ 10000010\ 011\ 0110\ 0000\ 0000\ 0000\ 0000]0x41360000=[0 10000010 011 0110 0000 0000 0000 0000]
根据该浮点数的机器码得到符号位
S=0
,指数e=阶码-127=1000 0010-127=130-127=3
。注意,根据阶码求指数时,可以像上面直接通过 "阶码-127"求得指数e,也可以将阶码+1=移码阶码+1=移码阶码+1=移码,再通过移码求其真值便是指数 e。比如上面阶码 10000010+1=10000011[移码]=>00000011[补]=3(指数e)10000010+1=10000011_{[移码]}=>00000011_{[补]}=3(指数e)10000010+1=10000011[移码]=>00000011[补]=3(指数e)。
包括尾数域最左边的隐藏位1,那么尾数 1.M=1.011 0110 0000 0000 0000 0000=1.011011。
于是有:
x=(−1)S×1.M×2e=+(1.011011)×23=+1011.011=(11.375)10x=(-1)^S\times1.M\times2^e=+(1.011011)\times2^3=+1011.011=(11.375)_{10}x=(−1)S×1.M×2e=+(1.011011)×23=+1011.011=(11.375)10通过代码同样可以验证上面的推算:
#include <iostream> using namespace std; int main() { unsigned int hex=0x41360000; float* fp=(float*)&hex; cout<<"x="<<*fp<<endl; return 0; }
输出结果:
x=11.375
验证正确。
5.浮点数的几种特殊情况
(1)0 的表示
对于阶码为 0 或 255 的情况,IEEE754 标准有特别的规定:
如果 阶码 E=0 并且尾数 M 是 0,则这个数的真值为 ±0(正负号和数符位有关)。因此 +0 的机器码为:0 00000000 000 0000 0000 0000 0000 0000。
-0 的机器码为:1 00000000 000 0000 0000 0000 0000 0000。需要注意一点,浮点数不能精确表示 0,而是以很小的数来近似表示 0,因为浮点数的真值等于(以32bits单精度浮点数为例):
x=(−1)S×(1.M)×2ex=(-1)^S\times(1.M)\times2^ex=(−1)S×(1.M)×2e
e=E−127e=E-127e=E−127
那么 +0 的机器码对应的真值为1.0×2−1271.0\times2^{-127}1.0×2−127。同理,-0 机器码真值为−1.0×2−127-1.0\times2^{-127}−1.0×2−127。(2)+∞+\infty+∞ 和 −∞-\infty−∞ 的表示
如果阶码 E=255 并且尾数 M 全是0,则这个数的真值为 ±∞(同样和符号位有关)。因此+∞+\infty+∞的机器码为:0 11111111 000 0000 0000 0000 0000 0000。−∞-\infty−∞的机器吗为:1 11111111 000 0000 0000 0000 0000 0000。(3)NaN(Not a Number)
如果 E = 255 并且 M 不是0,则这不是一个数(NaN)。6.浮点数的精度和数值范围
6.1 浮点数的数值范围
根据上面的探讨,浮点数可以表示-∞到+∞,这只是一种特殊情况,显然不是我们想要的数值范围。
以 32 位单精度浮点数为例,阶码 E 由 8 位表示,取值范围为 0-255,去除 0 和 255 这两种特殊情况,那么指数 e 的取值范围就是 1-127=-126 到 254-127=127。
(1)最大正数
因此单精度浮点数最大正数值的符号位S=0,阶码E=254,指数e=254-127=127,尾数M=111 1111 1111 1111 1111 1111,其机器码为:0 11111110 111 1111 1111 1111 1111 1111。那么最大正数值:
PosMax=(−1)S×1.M×2e=+(1.11111111111111111111111)×2127≈3.402823e+38PosMax=(-1)^S\times1.M\times2^e=+(1.111 1111 1111 1111 1111 1111)\times2^{127}\approx3.402823e+38PosMax=(−1)S×1.M×2e=+(1.11111111111111111111111)×2127≈3.402823e+38
这是一个很大的数。(2)最小正数
最小正数符号位S=0,阶码E=1,指数e=1-127=-126,尾数M=0,其机器码为0 00000001 000 0000 0000 0000 0000 0000。那么最小正数为:
PosMin=(−1)S×1.M×2e=+(1.0)×2−126≈1.175494e−38PosMin=(-1)^S\times1.M\times2^e=+(1.0)\times2^{-126} \approx1.175494e-38PosMin=(−1)S×1.M×2e=+(1.0)×2−126≈1.175494e−38这是一个相当小的数。几乎可以近似等于0。当阶码E=0,指数为-127时,IEEE754就是这么规定1.0×2−1271.0\times2^{-127}1.0×2−127近似为0的,事实上,它并不等于0。
(3)最大负数
最大负数符号位S=1,阶码E=1,指数e=1-127==-126,尾数M=0,机器码与最小正数的符号位相反,其他均相同,为:1 00000001 000 0000 0000 0000 0000 0000。最大负数等于:
NegMax=(−1)S×1.M×2e=−(1.0)×2−126≈−1.175494e−38NegMax=(-1)^S\times1.M\times2^e=-(1.0)\times2^{-126} \approx-1.175494e-38NegMax=(−1)S×1.M×2e=−(1.0)×2−126≈−1.175494e−38(4)最小负数
符号位S=0,阶码E=254,指数e=254-127=127,尾数M=111 1111 1111 1111 1111 1111,其机器码为:1 11111110 111 1111 1111 1111 1111 1111。计算得:
NegMin=(−1)S×1.M×2e=+(1.11111111111111111111111)×2127=−3.402823e+38NegMin=(-1)^S\times1.M\times2^e=+(1.111 1111 1111 1111 1111 1111)\times2^{127}=-3.402823e+38NegMin=(−1)S×1.M×2e=+(1.11111111111111111111111)×2127=−3.402823e+386.2 浮点数的精度
说到浮点数的精度,先给精度下一个定义。浮点数的精度是指浮点数的小数位所能表达的位数。
阶码的二进制位数决定浮点数的表示范围,尾数的二进制位数表示浮点数的精度。以 32 位浮点数为例,尾数域有 23 位。那么浮点数以二进制表示的话精度是 23 位,23 位所能表示的最大数是223−1=83886072^{23}-1=8388607223−1=8388607,所以十进制的尾数部分最大数值是 8388607,也就是说尾数数值超过这个值,float 将无法精确表示,所以 float 最多能表示小数点后 7 位,但绝对能保证的为 6 位,即 float 的十进制的精度为 6~7 位。
64 位双精度浮点数的尾数域 52 位,因252−1=4,503,599,627,370,4952^{52}-1=4,503,599,627,370,495252−1=4,503,599,627,370,495,所以双精度浮点数的十进制的精度最高为 16 位,绝对保证的为 15 位,所以 double 的十进制的精度为 15~16 位。
7.小结
本文操之过急,难免出现编辑错误和不当说法,请网友批评指正。不明之处,欢迎留言交流。对浮点数的加减乘除运算还未涉及,后续可能会去学习并记录学习所得,与大家分享。
参考文献
[1] 百度百科.移码
[2] 百度知道.关于IEEE754标准浮点数阶码的移码
[3] 白中英.计算机组成原理第四版[M].科学出版社:P16-30
[4] 维基百科.浮点数 -
C语言浮点数
2019-08-03 20:23:07浮点数的概念 浮点数也称小数或实数。例如,0.0、75.0、4.023、0.27、-937.198 都是合法的小数。这是常见的小数的表现形式,称为十进制形式。 C语言中采用float和double关键字来定义小数,float称为单精度浮点型...浮点数的概念
浮点数也称小数或实数。例如,0.0、75.0、4.023、0.27、-937.198 都是合法的小数。这是常见的小数的表现形式,称为十进制形式。
C语言中采用float和double关键字来定义小数,float称为单精度浮点型,double称为双精度浮点型,long double更长的双精度浮点型。
在任何区间内(如1.0 到 2.0 之间)都存在无穷多个实数,计算机的浮点数不能表示区间内所有的值。浮点数通常只是实际值的近似值,例如7.0可能被储存为浮点值6.99999。
点用内存的情况
我们先来测试一下float、double和long double三种浮点数据类型占用内存的字节数。
示例(book71.c)
运行结果
浮点数的精度
C标准规定,float类型必须至少能表示6位有效数字,且取值范围至少是10-37~10+37。
double类型和 float类型的最小取值范围相同,但至少必须能表示10位有效数字。
long double,以满足比double类型更高的精度要求。不过,C只保证long double类型至少与double类型的精度相同。
看了上面这段文字,估计大家有点晕,在之前的整数章节中,long比int的占用的内存多,存放数据的值也就越大,并且有一个准确的范围,但是,为什么各种浮点数存放数据的值怎么就这么模糊呢?我先不解释原因,浮点数的存储方式比较复杂,暂时不讨论,先用几个程序来测试一下它们的特征。
1、测试float类型
示例(book73.c)
运行结果
从程序的运行我们可以看出float数的两个特征:
1)float数据类型表达的是一个近似的数,不是准确的,小数点后的n位有误差,浮点数的位数越大,误差越大,到8位的时候,误差了1,基本上不能用了。
2)用“==”可以比较两个整数或字符是否相等,但是,看起来相等的两个浮点数,就是不会相等。
2、测试double类型
示例(book74.c)
运行结果
从程序的运行我们可以看出double数的两个特征:
1)double数据类型表达的也是一个近似的数,不是准确的,小数点后的n位有误差,浮点数的位数越大,误差越大,到17位的时候,误差了1,基本上不能用了。
2)用“==”可以比较两个double数值是否相等。
3、测试long double类型
示例(book75.c)
运行结果
long double的测试结果与double相同。
4、测试总结
float只能表达6-7位的有效数字,不能用“==”判断两个数字是否相等。
double能表达15-16位有效的数字,可以用“==”判断两个数字是否相等。
long double和double的特征相同。
在实际开发中,建议弃用float,只采用double就可以,long double暂时没有必要,但不知道以后的操作系统和编译器对long double是否有改进。
浮点数的输出
float采用%f输出,double采用%lf输出,测试结果证明,double也可以采用%f输出。
long double采用%Lf输出,注意,L是大写。
%lf缺省显示小数点后六位。
如果要显示小数点后n位,用%.nlf,例如:
double ff=7.5;
%.2lf 显示 7.50
浮点数采用%lf输出,完整的输出格式是%m.nlf,指定输出数据整数部分和小数部分共占m位,其中有n位是小数。如果数值长度小于m,则左端补空格,若数值长度大于m,则按实际位数输出。
常用的库函数
在接下来的内容中,我只介绍double,不再介绍float和long double两种数据类型相关的知识。
以下是常用的浮点数函数,必须掌握。
double atof(const char *nptr); // 把字符串nptr转换为double
double fabs(double x); // 求双精度实数x的绝对值
double pow(double x, double y); // 求 x 的 y 次幂(次方)
double round(double x); // double四舍五入
double ceil(double x); // double向上取整数
double floor(double x); // double向下取整数
double fmod(double x,double y); // 求x/y整除后的双精度余数
double modf(double val,double *ip); // 把双精度val分解成整数部分和小数部分,整数部分存放在ip所指的变量中,返回小数部分。
还有一些数据计算函数,如正弦、对数、指数等,实际开发中极少使用,大家要用的时候再查资料,我就不介绍了。
整数转换为浮点数
我们先来看一个示例(book77.c):
运行结果
需要特别注意的是dd=ii/jj这一行代码,dd的值0,不是0.75,有点意外,所以,如果对整数转换为浮点数没有把握,加(double)强制转换是个好办法。
应用技巧
浮点数有一些坑,例如两个浮点数不相等和精度的问题,在实际开发中,我们经常用整数代替浮点数,因为整数是精确的,效率也更高。
例如人的身高一米七五,以米为单位,用浮点数表示是1.75米,如果以厘米为单位,用整数表示是175。
long整数的取值是-9223372036854775808~9223372036854775807,有效数字是19位,而double的有效数字才15-16位,所以,整数可以表达的小数更大的数,更实用,麻烦也更少。
货币:1.75元,如果采用0.01元为单位就是175,采用0.001元为单位就是1750,如果你说要更多小数怎么办?你这是钻牛角尖。
给大家说一个道,高水平的程序员不容易掉坑里,注意,是不容易,不是一定不会,最好的方法是没有坑。
科学计数法
在实际开发中,我们很少使用科学计数法,但是它经常出现在计算机系统中,例如浮点数在内存中的存放方式就是科学计数法,所以我们还是有必要学习科学计数法。
科学记数法是一种记数的方法。把一个数表示成a与10的n次幂相乘的形式(1≤|a|<10,n为整数),这种记数法叫做科学记数法。当我们要书写或运算某个较大或较小且位数较多时,用科学记数法免去浪费很多空间和时间。
例如:51400000000=5.14×1011。计算器或电脑表达10的幂是一般是用E或e,也就是51400000000=5.14E11或5.14e11。
用科学记数法表示数时,不改变数的符号,只是改变数的书写形式而已,可以方便的表示日常生活中遇到的一些极大或极小的数 。如:光的速度大约是300,000,000米/秒;全世界人口数大约是:6,100,000,000。
这样的数,书写和显示都很不方便,我们可以免去写这么多重复的0,将其表现为这样的形式:6,100,000,000=6.1×109,即6.1E9或6.1e9。
或:0.00001=1×10-5,即绝对值小于1的数也可以用科学记数法表示为a乘10 的负n次方的形式。即1E-5或1e-5。
科学计数法采用%e或%E输出,完整的输出格式是%m.ne或%m.nE,指定输出数据整数部分和小数部分共占m位,其中有n位是小数。如果数值长度小于m,则左端补空格,若数值长度大于m,则按实际位数输出。
示例(book78.c):
运行结果
版权声明
C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。
来源:C语言技术网(www.freecplus.net)
作者:码农有道
如果这篇文章对您有帮助,请点赞支持,或在您的博客中转发我的文章,谢谢!!!
如果文章有错别字,或者内容有误,或其他的建议或意见,请您留言指正,非常感谢!!!
-
浮点数表示
2016-12-22 15:00:17之前的一些工作当中碰到了很多有关浮点数的问题,比如浮点数的表达范围、表达精度、浮点数的存储方式、浮点数的强制类型转换等等,因此感觉有必要系统了解一下有关浮点数的问题。 —————————— 浮点数表示 ...之前的一些工作当中碰到了很多有关浮点数的问题,比如浮点数的表达范围、表达精度、浮点数的存储方式、浮点数的强制类型转换等等,因此感觉有必要系统了解一下有关浮点数的问题。
—————————— 浮点数表示 ——————————
浮点数是一种 公式化 的表达方式,用来近似表示实数,并且可以在表达范围和表示精度之间进行权衡(因此被称为浮点数)。
浮点数通常被表示为:
\(N = M\times R^E\)
比如: \(12.345 = 1.2345\times 10^1\)
其中,M(Mantissa)被称为浮点数的 尾数 ,R(Radix)被称为阶码的 基数 ,E(Exponent)被称为阶的 阶码 。计算机中一般规定R为2、8或16,是一个确定的常数,不需要在浮点数中明确表示出来。
因此,在已知标准下,要表示浮点数,
一是要给出尾数M的值,通常用定点小数形式表示,它决定了浮点数的表示精度,即可以给出的有效数字的位数。
二是要给出阶码,通常用定点整数形式表示,它指出的是小数点在数据中的位置,决定了浮点数的表示范围。因此,在计算机中,浮点数通常被表示成如下格式:(假定为32位浮点数,基为2,其中最高位为符号位)
—————————— 浮点数的规格化表示 ——————————
按照上面的指数表示方法,一个浮点数会有不同的表示:
\(0.3\times10^0\);\(0.03\times10^1\);\(0.003\times10^2\);\(0.0003\times10^3\);
为了提高数据的表示精度同时保证数据表示的唯一性,需要对浮点数做规格化处理。
在计算机内,对非0值的浮点数,要求尾数的绝对值必须大于基数的倒数,即\(|M|\ge \frac{1}{R}\)。
即要求尾数域的最高有效位应为1,称满足这种表示要求的浮点数为规格化表示:把不满足这一表示要求的尾数,变成满足这一要求的尾数的操作过程,叫作浮点数的规格化处理,通过尾数移位和修改阶码实现。
比如,二进制原码的规格化数的表现形式:(0正1负)
正数 0.1xxxxxx
负数 1.1xxxxxx
注意,尾数的最高位始终是1,因此我们完全可以省略掉该位。
至此,我们引入IEEE754 标准,该标准约束了浮点数的大部分使用设置:(尾数用原码;阶码用“移码”;基为2)
(1) 尾数用原码,且隐藏尾数最高位。
原码非0值浮点数的尾数数值最高位必定为 1,因此可以忽略掉该位,这样用同样多的位数就能多存一位二进制数,有利于提高数据表示精度,称这种处理方案使用了隐藏位技术。当然,在取回这样的浮点数到运算器执行运算时,必须先恢复该隐藏位。
(2) 阶码使用“移码”,基固定为2
如下图的32bit浮点数和64bit浮点数,从最高位依次是符号位、阶码和尾数
于是,
一个规格化的32位浮点数x的真值为:
\(x = (-1)^s\times(1.M)\times2^{E-127}\)
一个规格化的64位浮点数x的真值为:
\(x = (-1)^s\times(1.M)\times2^{E-1023}\)
下面举一个32位单精度浮点数-3.75表示的例子帮助理解:
(1) 首先转化为2进制表示
\(-3.75 = -(2+1+1/2+1/4) = -1.111\times2^1\)
(2) 整理符号位并进行规格化表示
\(-1.111\times2^1 = (-1)^{(1)}\times(1+0.1110\ 0000\ 0000\ 0000\ 0000\ 000)\times2^1\)
(3) 进行阶码的移码处理
\((-1)^{(1)}\times(1+0.1110\ 0000\ 0000\ 0000\ 0000\ 000)\times2^1\)
\(=(-1)^{(1)}\times(1+0.1110\ 0000\ 0000\ 0000\ 0000\ 000)\times2^{128-127}\)于是,符号位S=1,尾数M为\(1110\ 0000\ 0000\ 0000\ 0000\ 000\)阶码E为\(128_{10}=1000\ 0000_2\),则最终的32位单精度浮点数为
\(1\ 1110\ 0000\ 0000\ 0000\ 0000\ 000\ 1000\ 0000\)
—————————— 浮点数的表示范围 ——————————
通过上面的规格化表示,我们可以很容易确定浮点数的表示范围:
既然有表示范围,那肯定也有不能表示的数值:
首先来说明溢出值,如下图:(1)无穷值:
如果指数\(E=11111111_2=255_{10}\)且尾数\(M=0\),则根据符号位S分别表示\(+\infty\)和\(-\infty\)。因此,一个有效的32位浮点数其指数最大只能为254。
此外,无穷具有传递性,比如
(+∞) + (+7) = (+∞)
(+∞) × (−2) = (−∞)
(+∞) × 0 = NaN
(2)零值:
如果指数\(E=0\)且尾数\(M=0\)时,表示机器0.需要注意的是,这里的0也是有符号的,在数值比较的时候 \(+0=-0\); 但在一些特殊操作下,二者并不显相等,比如\(\log(x)\), \(\frac{1}{+0} \neq \frac{1}{-0}\)。
此外,处于负下溢出和负上溢出之间的数值会被直接归为0。
(3)NAN:
如果\(E=0\)且尾数\(M\neq 0\),则表示这个值不是一个真正的值(Not A Number)。NAN又分成两类:QNAN(Quiet NAN)和SNAN(Singaling NAN)。QNAN与SNAN的不同之处在于,QNAN的尾数部分最高位定义为1,SNAN最高位定义为0;QNAN一般表示未定义的算术运算结果,如\(\frac{0}{0}\), \(\infty \times 0\), \(sqrt(-1)\);SNAN一般被用于标记未初始化的值,以此来捕获异常。
—————————— 浮点数的表示精度 ——————
一般提到浮点数的精度(有效位数)的时候,总是会出现 float的有效位为6~7位, double的有效位为15~16位 。
下面以float为例,解释一下有效位数是怎样来的。
有效位数只和规格化浮点数的尾数部分有关,而尾数部分的位数是23位,因此我们首先列出下表
由上面的表格可以看出:
\(2^{-23}\) 和 \(2^{-22}\) 之间是存在间隔的,即0.0000001和0.0000002之间的小数我们是没有办法描述的,因此23位尾数最多只能描述到小数点后第7位;此外,我们通过四舍五入可以很容易发现\(0.0000003 = 0.0000004 = 2^{-23}+2^{-22}\), 这表明第7位有效数字只是部分准确。而第6位及之前的都是可以准确描述的,因此我们说float的有效位为6~7位。
—————————— 参考资料 ——————————
(1) WIKI 词条 “Floating Point”: https://en.wikipedia.org/wiki/Floating_point
(2) WIKI 词条 “IEEE floating point”: https://en.wikipedia.org/wiki/IEEE_floating_point
(2) 浮点异常值:NAN,QNAN,SNAN:
http://www.cnblogs.com/konlil/archive/2011/07/06/2099646.html -
浮点数的表示方法
2019-02-13 23:44:28把一个数的有效数字和数的范围在计算机的一个存储...其中M称为浮点数的尾数,是一个纯小数。e是比例因子的指数,称为浮点数的指数,是一个整数。比例因子的基数2对二进记数制的机器是一个常数。 在机器中表示一个... -
python整数和浮点数相乘_关于浮点数:浮点数与整数相乘浮点数的精度
2020-12-04 21:50:22在我的计算机科学课程中,我们正在研究浮点数及其在内存中的表示方式。我已经了解了它们在内存中的表示方式(尾数/有效数,指数及其偏倚以及符号位),并且我了解了浮点数是如何相互加减的(非正规化和所有这些有趣的... -
浮点数构成
2018-05-15 20:02:24一般在写一些静态类型的语言的时候(c , golang等等),通常会提供一种单精度浮点数的数据类型,float(float32),这篇博文主要讲解单精度浮点数,对于双精度浮点数在构造上实际上与单精度浮点数差不了多少,懂了... -
TMS320C3x浮点数简介、IEEE754的32位转VC33的32位浮点数算法、IEEE754的64位浮点数转VC33的40位浮点数算法
2020-05-20 18:31:23本文档简介了TMS320C3x浮点数简介、IEEE754的32位转VC33的32位浮点数算法、IEEE754的64位浮点数转VC33的40位浮点数算法;给相关TI的DSP开发工程师提供开发参考。 -
浮点数小记
2020-06-25 15:29:02浮点数float分为 半精度浮点数(16位)、单精度浮点数(32位)以及双精度浮点数(64位)。 浮点数由符号位(signed)、指数位(Exponent)、尾数位(Mantissa)以及基数构成,二进制浮点数基数是2,十进制浮点数基数... -
单片机浮点数设计 单片机浮点数设计
2011-04-27 16:03:30单片机浮点数设计 单片机浮点数设计 单片机浮点数设计 -
浮点数运算案例
2020-03-31 17:35:24浮点数运算案例 -
C语言printf(““),浮点数打印保留有效位数,小数部分的四舍五入
2017-07-13 19:16:38说明:%3.0f表明待打印的浮点数(floatNum)至少占3个字符宽,且不带小数点和小数部分,整数部分至少占3个位宽; 注意:这里的3只代表整数部分至少占3位,舍弃小数点和小数点后面的部分 2.printf("%6.2f".floatNum)... -
输出浮点数
2020-01-14 11:44:26读入一个双精度浮点数,分别按输出格式“%f”,“%f”保留5位小数,“%e”和“%g”的形式输出这个整数,每次在单独一行上输出。 【输入】 一个双精度浮点数。 【输出】 第一行是按“%f”输出的双精度浮点数; 第二行... -
浮点数(单精度浮点数,双精度浮点数)
2010-10-23 01:32:05单精度浮点数,双精度浮点数,浮点数是属于有理数中某特定子集的数的数字表示,在计算机中用以近似表示任意某个实数。 -
学习笔记1 - 判断浮点数是否为整数浮点数还是小数浮点数
2019-12-08 15:08:43判断浮点数是否为整数浮点数还是小数浮点数 我们一般可以通过type(x)函数直接获取x的数据类型,或者通过isinstance(x, datatype)来判断x是否为datatype类型。但是,有时候,我们需要将如20.0这样小数位无值、类似于... -
浮点数和浮点数误差问题
2018-04-18 14:34:12浮点数 1.默认是double。 2.浮点数存在舍入误差,很多数字不能精确表示。如果需要进行不产生舍入误差的精确数字计算,需要使用BigDecimal类。 3.最好避免比较中使用浮点数。 类型 占用存储空间 表述范围 ... -
C语言菜鸟基础教程之单精度浮点数与双精度浮点数
2020-08-29 05:30:17在C语言中,单精度浮点数(float)和双精度浮点数(double)类型都是用来储存实数的,双精度是用记忆较多,有效数字较多,数值范围较大。 -
浮点数总结
2018-08-26 10:19:18浮点数在内存中的存储 根据IEEE standard 754,float用4个字节存储,double用8个字节存储。float 1个bit用来存储浮点数的符号,8个bit用来存储浮点数的指数,23个bit用来存储浮点数的尾数。对于double 1个bit用来... -
IEEE754标准浮点数转换
2018-08-02 16:13:13IEEE754标准是一种浮点数表示标准,一般分为单、双精度两种,单精度是32位的二进制数,双精度是64位的二进制数,一个浮点数的组成分为三个部分 ①第1位是数符s,s=1表示负数,s=0表示正数。 ②第2-9位为阶码E, (双...