-
2020-12-16 13:37:41
% IEEE754 to dec a = 'BF896BF8' a = dec2bin(hex2dec(a),32); M = bin2dec(a(10:32)); E = bin2dec(a(2:9)); x = (-1)^a(1)*(1 + M*2^-23)*2^(E-127); % dec to IEEE754 result = 1./(1+exp(-x)) if(result<0) S = '1'; else S= '0'; end result = abs(result); i = 0; while(result<1) result = result * 2; i = i+1; end j = 0; while(result>2) result = result/2; j = j+1; end E = i + j; if(j == 0) E = -E; end E = E+127; E = dec2bin(E,8); M23 =dec2bin(floor((result-1)*2^23),23); r = [S,E,M23]; dec2hex(bin2dec(r))
matlab 单精度浮点数和十进制数相互转换
更多相关内容 -
IEEE 754精度格式:目的是说明IEEE 754双精度和单精度格式。-matlab开发
2021-05-30 20:33:01以下特殊情况,即。 inf、NaN、DeNorm,这里没有演示。 2. 仅供参考。 如果说明性演示有更优雅的演示,请不要犹豫,向作者提出建议和反馈。 电子邮件:promethevx@yahoo.com。 谢谢你。 问候, 迈克尔·陈 JT -
为什么单精度浮点数的精度是7位
2019-11-13 23:23:10layout: post ...tags: c++ 浮点数起因浮点数的精度IEEE754表示测试浮点数运算浮点数精度我的理解自己的理解总结参考 起因 今天遇到一个问题,角色卡在一个模型边上,在PVD看模型也比较正常。最...起因
今天遇到一个问题,角色卡在一个模型边上,在PVD看模型也比较正常。最终原因呢是因为模型的一个三角形的两个顶点非常进,结果在浮点数运算的时候这种非常小的差异就被丢掉了,所以在PhysX中会判定移动了距离为0的位置,所以一直就卡在原地,跳也跳不起来。来看下两个顶点的信息:
[0] = {x = -4.10000086, y = -0.200000167, z = -3.56512594} [1] = {x = -4.10000086, y = -0.200000077, z = -3.56512594}
只有y值有一丁点的差异,这个时候起码还在浮点数的有效范围内。带上几个问题对研究这个问题会有帮助:
- 1.为什么 -0.200000167和 -0.200000077浮点数表示不一样,最后加上4.76143503(运算用到的一个坐标)结果就一样了?是什么原因?
- 2.浮点数运算的逻辑是什么?
- 3.浮点数的精度为什么是7位?
浮点数的精度
IEEE754表示
测试
把上面出问题的数据抽出来测试以下
float y = 4.76143503; float y1 = -0.200000167; float y2 = -0.200000077; float y1Add = y + y1; float y2Add = y + y2; std::cout << std::bitset<32>(*(_ULonglong*)&y) << std::endl; std::cout << std::bitset<32>(*(_ULonglong*)&y1) << std::endl; std::cout << std::bitset<32>(*(_ULonglong*)&y1Add) << std::endl; std::cout << std::bitset<32>(*(_ULonglong*)&y2) << std::endl; std::cout << std::bitset<32>(*(_ULonglong*)&y2Add) << std::endl; cout << "fTest = " << y1Add << endl; cout << "fTest1 = " << y2Add << endl;
结果可以看到:
01000000100110000101110110101101 10111110010011001100110011011000 01000000100100011111011101000110 10111110010011001100110011010010 01000000100100011111011101000110 fTest = 4.56143 fTest1 = 4.56143
小结:
- y1和y2的浮点数表示的确不一样,即IEEE754的23位小数位是满足条件的
- 做了加法之后,结果变成一样了
那么接下来根据问题来分析原因是什么样的。
浮点数运算
参考[2],[3]的主要步骤:
- 1.规格化表示
- 2.对阶
- 3.尾数标数
- 4.规格化
- 5.舍入
IEEE 754 standard floating point Addition Algorithm Floating-point addition is more complex than multiplication, brief overview of floating point addition algorithm have been explained below X3 = X1 + X2 X3 = (M1 x 2E1) +/- (M2 x 2E2) 1) X1 and X2 can only be added if the exponents are the same i.e E1=E2. 2) We assume that X1 has the larger absolute value of the 2 numbers. Absolute value of of X1 should be greater than absolute value of X2, else swap the values such that Abs(X1) is greater than Abs(X2). Abs(X1) > Abs(X2). 3) Initial value of the exponent should be the larger of the 2 numbers, since we know exponent of X1 will be bigger , hence Initial exponent result E3 = E1. 4) Calculate the exponent's difference i.e. Exp_diff = (E1-E2). 5) Left shift the decimal point of mantissa (M2) by the exponent difference. Now the exponents of both X1 and X2 are same. 6) Compute the sum/difference of the mantissas depending on the sign bit S1 and S2. If signs of X1 and X2 are equal (S1 == S2) then add the mantissas If signs of X1 and X2 are not equal (S1 != S2) then subtract the mantissas 7) Normalize the resultant mantissa (M3) if needed. (1.m3 format) and the initial exponent result E3=E1 needs to be adjusted according to the normalization of mantissa. 8) If any of the operands is infinity or if (E3>Emax) , overflow has occurred ,the output should be set to infinity. If(E3 < Emin) then it's a underflow and the output should be set to zero. 9) Nan's are not supported.
然后,我就自己手动计算了一下:
01000000100110000101110110101101 = 4.76143503 阶码:10000001 = 129 - 127 = 2 尾数:1.00110000101110110101101 -------------------------------------------------- 10111110010011001100110011011000 = -0.200000167 阶码:01111100 = 124 - 127 = -3 尾数:1.10011001100110011011000 01000000100100011111011101000110 = 4.56143475 = 4.76143503 + -0.200000167 阶码:10000001 = 129 - 127 = 2 尾数:1.00100011111011101000110 加法运算: 1.1001 1001 1001 1001 1011 000 对齐:小数点左移2-(-3) = 5位 0.00001.1001 1001 1001 1001 1011 000 相减: 1.0011 0000 1011 1011 0101 101 - 1.0000 1100 1100 1100 1100 110 11 000 = 1.0010 0011 1110 1110 1000 111 比较 1.0010 0011 1110 1110 1000 110 -------------------------------------------------- 10111110010011001100110011010010 = -0.200000077 阶码:01111100 = 124 - 127 = -3 尾数:1.10011001100110011010010 01000000100100011111011101000110 = 4.56143475 = 4.76143503 + -0.200000077 阶码:10000001 = 129 - 127 = 2 尾数:1.00100011111011101000110 加法运算: 1.10011001100110011010010 对齐:小数点左移2-(-3) = 5位 0.0000110011001100110011010010 相减:计算器去掉小数点和前面的1来的比较快 1.0011 0000 1011 1011 0101 101 - 0.0000 1100 1100 1100 1100 110 10010 = 1.0010 0011 1110 1110 1000 111 比较 1.0010 0011 1110 1110 1000 110
小结:
- 计算的结果的确是一样的,但是和最终的4.76143503还是有点不一样(最后一个比特位),这说明我手动计算和机器计算还是有点区别,包括后面的规格化,舍入我就没去细看了,留个问题在这里吧
// 4.76143503 + -0.200000167 1.0010 0011 1110 1110 1000 111 // 4.76143503 + -0.200000077 1.0010 0011 1110 1110 1000 111 // 最终结果的二进制 1.0010 0011 1110 1110 1000 110
- 这里解释了前两个问题:最主要是在浮点数的运算过程中(这里是加法),因为要对齐阶码,所以更小的数字的尾数后面几位(这里是5位)都忽略掉了,所以-0.200000167和 -0.200000077的差异也就没有了
再来看看IEEE754有23位小数,为什么精度是7位小数位?
浮点数精度
先确定下自己的问题:
- 精度指的是十进制的小数点后面的个数,而IEEE754标准的23位指的是二进制有效位
- 我想理解的是23位二进制有效位是如何换算到十进制的7位有效位的
- 网上搜索了之后,最终可以确定的是十进制小数点后面可以精确到6-7位
- 自己最终问题是如何用数学方法证明?
最常见的解释如下,参考[5][6]:
因为float类型的数值由二进制下的后23位决定的,而这后23位表示的十进制的数最大为2^23=8388608,也就是说在二进制下能表示的准确的23位的数转换 到十进制下最大的数是7位的,数值是多少不重要,因为这个数是在十进制下是7位,所以float在十进制下的精度位7位。再说白一点,二进制下能表示的最大的准确的数值转换为十进制是7位。
简单来讲,就是二进制可以表示的8388608是一个7位数字,但是并不能包括完全包括所有7位有效位,所以是6-7位有效位。但是,这里我还是有疑问的,这个算法应该是小数点前面可以这么算,小数点后面怎么算的,如果可以这么算,又如何解释?
我的理解
参考[7][8][12]之后,相对而言,我比较喜欢[8][12]的解释。但最终我自己理解又是另外一个。
- 1.小数点后面的二进制和十进制转换应该是这样的表达式,当然应该要乘以一个0或者1表示有效位上面有数据
0. x x x x = 2 − 1 + 2 − 2 + . . . + 2 − 23 0.xxxx = 2^{-1} + 2^{-2} + ... + 2^{-23} 0.xxxx=2−1+2−2+...+2−23
那么,小数点后面最小的单位是$2^{-23} = $
这里其实也说明了浮点数的有些数值只能是近似表示的- 2.[8]数学推导
− l o g 10 2 − 23 = 6.924 -{log_{10}}{2^{-23}} = 6.924 −log102−23=6.924
自己的理解
- (1)23位小数,能表示的最小小数位,其他的小数都是乘以这个最小单位构成的[12]
2 − 23 = 0.00000011920928955078125 2^{-23}= 0.00000011920928955078125 2−23=0.00000011920928955078125
一开始我想,这后面明显有这么多小数,为什么是7位?
- (2)这个最小单位表示的就是精度的尾数,怎么理解!
如果最小单位是0.1,那么精度就是小数点后面1位,因为你永远也组合不了0.1后面的小数(整数个最小单位求和),比如0.01、0.02等
如果最小单位是0.000001,那么精度就是小数点后面6位,同样的你也永远组合不了0.000001更小单位的小数,比如0.0000001、0.0000002等等 - (3)准确来说二进制23位有效位表示的精度为小数点后面6~7位。
由上面一条可以知道,0.00000011920928955078125这个最小单位用23位二进制任意组合(求最小单位的倍数),只能得到比这个0.00000011920928955078125更大的数。所以永远得不到0.00000001这样的小数(精度为小数点后面8位),但是肯定可以得到0.000001(精度为小数点后面6位)的小数。但是不能完全表示精度位小数点后面为7位的小数。下面忽略舍入的算法,只取小数点后面7位有效位的计算结果:
0.00000011920928955078125 * 1 = 0.0000001 0.00000011920928955078125 * 2 = 0.0000002 0.00000011920928955078125 * 3 = 0.0000003 0.00000011920928955078125 * 4 = 0.0000004 0.00000011920928955078125 * 5 = 0.0000005 0.00000011920928955078125 * 6 = 0.0000007 0.00000011920928955078125 * 7 = 0.0000008 0.00000011920928955078125 * 8 = 0.0000009 0.00000011920928955078125 * 9 = 0.000001
可以看到0.0000006表示不出来,如果考虑舍入的话可能是其他的表示不出来,所以说不能完全表示所有的小数点后面7位小数
总结
- 浮点数的爱与恨
参考
[1]深入理解浮点数有效位
[2]二进制浮点数的加减法运算
[6]java浮点类型float和double的主要区别,它们的小数精度范围大小是多少?
[7]浮点计算精度损失原因
[8]单精度浮点数的有效数字为什么是7位,我算的明明是6位,你看我算的对吗?
[9]Why IEEE754 single-precision float has only 7 digit precision?
[10]In-depth: IEEE 754 Multiplication And Addition
[11]浮点数精度问题透析:小数计算不准确+浮点数精度丢失根源
[12]关于float型是单精度的有效位数是7位,为什么在下面的例子中这8位都是准确的呢?
[13]二进制计算器网页版
-
浮点数的表示和精度_单精度浮点数的表示
2021-04-18 14:50:41浮点数的表示和精度如果a>0,那么1+a一定大于1吗?...在matalb上,可以作以下计算:>> a=1/2^52a =2.220446049250313e-016>> 1+a>1ans =1>> a=1/2^53a =1.110223024625157e-016>>...浮点数的表示和精度
如果a>0,那么1+a一定大于1吗?在数学上,答案是肯定的。但在计算机上,答案就与a的大小和浮点数的精度有关了。在matalb上,可以作以下计算:
>> a=1/2^52
a =
2.220446049250313e-016
>> 1+a>1
ans =
1
>> a=1/2^53
a =
1.110223024625157e-016
>> 1+a>1
ans =
0
可见,当a等于1/2^53时,1+a>1是不成立的。
1 浮点数
IEEE754定义了单精度浮点数和双精度数浮点数,即float和double。float有32bit,double有64bit。它们都包括符号位、指数和尾数。
符号位
指数
尾数
float
31(1)
30-23(8)
22-0(23)
double
63(1)
62-52(11)
51-0(52)
符号位有1bit,0表示正、1表示负。设一个数的指数是e,指数部分的值是bias+e。加上一个bias是为了表示负数。 float的bias是127,double的bias是1023。指数全0或全1有特殊含义,不算正常指数。
float的指数部分有8bit,可以取值1~254,减掉127,得到对应的指数范围-126~127。
double的指数部分有11位,可以取值1~2046,减掉1023,得到对应的指数范围-1022~1023。
这里的指数是以2为底的,同样尾数也是二进制的。IEEE754要求浮点数以规范形式存储,即小数点前有1位非零数字。 对于二进制数,非零数字只有1。所以IEEE754在存储时省略了这个小数点前面的1,只存储小数点后面的位。
2 误差
看个例子,设:
double a=0.2;
在PC上,我们可以看到a对应的存储区数据是:
9A 99 99 99 99 99 C9 3F
PC的数据是小尾的,即低位字节在后,将其写成高位字节在前,得到:
3F C9 99 99 99 99 99 9A
可见符号位为0。指数位是0x3FC,即1020,减掉1023,得到指数-3。尾数是999999999999A。所以完整的数字就是16进制的1.999999999999A乘上2^-3。即:
a=(1+9*(1/16+1/16^2+...+1/16^12)+10/16^13)*2^-3
(1/16+…+1/16^12)可以用等比级数求和公式a1*(1-q^n)/(1-q)计算,其中a1=1/16,q=1/16,n=12,因此:
a=(1+9*(1-1/16^12)/15+10/16^13)*2^-3
用windows的计算器计算上式,得到
a=0.2000 0000 0000 0000 1110 2230 2462 5157
这也不是精确解,但已经可以看到用double表示0.2时存在的误差。这个例子说明在用有限字长的二进制浮点数表示任意实数a可能引入误差。 设实数a的指数为e,尾数位数为n,显然:
误差
3 精度
可以把机器精度定义为满足条件
fl(1+ε)>1
的最小浮点数ε。其中fl(1+ε)是1+ε的浮点表示。显然double的机器精度是1/2^52。float的机器精度是1/2^23。 matlab内部采用double,1+1/2^53对double来说就是1,所以1+1/2^53不会大于1。
对于规范数来说,因为小数点前默认有个1,所以float的有效数字是24bit,对应8位十进制有效数字; double的有效数字是53bit,对应16位十进制有效数字。
4 特殊的浮点数
前面提到浮点数的指数全0或全1有特殊含义,让我们来看看这些特殊的浮点数:
指数和尾数都是全0表示0。根据符号位不同可以分为+0和-0。
指数全0,尾数不为全0,这些数是非规范数,即尾数部分不假设前面存在小数点前的1。 或者说这些数太接近0了,因为指数已经不能再小,所以这些数不能写成规范形式。 例如:double数0000 0000 0000 0001的尾数是0 0000 0000 0001,即1/2^52,对应的数是1/(2^52)*2^-1022,即4.9406564584124654e-324。
指数全1,尾数全0表示无穷大,即inf。根据符号位不同可以分为+inf和-inf。
指数全1,尾数不为全0表示NaN,即Not a Number,不是数。尾数最高位为1的NaN被称作QNaN(Quiet NaN)。 尾数最高位为0的NaN被称作SNaN(Signalling NaN)。通常用QNaN表示不确定的操作,用SNaN表示无效的操作。
在计算机内部,double就是一个64位数。从0x0000 0000 0000 0000~0xFFFF FFFF FFFF FFFF,每个64位数都对应一个浮点数或NaN。 我写了一个小程序,按照64位无符号整数的顺序打印出典型的浮点数。 表格的第一列是浮点数的内部表示。为了便于阅读,按大尾顺序输出。第二列是对应的浮点数。 第三列是注释,对于非规范数和规范数给出了由内部表示计算数值的matlab算式。 注意在C/C++中,2^52要写成pow(2.0,52.0)。
0000 0000 0000 0000
0.0000000000000000e+000
+0
0000 0000 0000 0001
4.9406564584124654e-324
1/(2^52)*2^-1022
000F FFFF FFFF FFFF
2.2250738585072009e-308
.5*(1-.5^52)/(1-.5)*2^-1022
0010 0000 0000 0000
2.2250738585072014e-308
1.0*2^-1022
0010 0000 0000 0001
2.2250738585072019e-308
(1+1/2^52)*2^(-1022)
001F FFFF FFFF FFFF
4.4501477170144023e-308
(1+.5*(1-.5^52)/(1-.5))*2^-1022
0020 0000 0000 0000
4.4501477170144028e-308
1.0*2^-1021
3FF0 0000 0000 0000
1.0000000000000000e+000
1.0
3FF0 0000 0000 0001
1.0000000000000002e+000
1.0+1/(2^52)
3FFF FFFF FFFF FFFF
1.9999999999999998e+000
1+.5*(1-.5^52)/(1-.5)
4000 0000 0000 0000
2.0000000000000000e+000
1.0*2^1
7FEF FFFF FFFF FFFF
1.7976931348623157e+308
(1+.5*(1-.5^52)/(1-.5))*2^1023
7FF0 0000 0000 0000
1.#INF000000000000e+000
+INF
7FF0 0000 0000 0001
1.#SNAN00000000000e+000
SNaN
7FF7 FFFF FFFF FFFF
1.#SNAN00000000000e+000
SNaN
7FF8 0000 0000 0000
1.#QNAN00000000000e+000
QNaN
7FFF FFFF FFFF FFFF
1.#QNAN00000000000e+000
QNaN
8000 0000 0000 0000
0.0000000000000000e+000
-0
8000 0000 0000 0001
-4.9406564584124654e-324
-(1/(2^52)*2^-1022)
800F FFFF FFFF FFFF
-2.2250738585072009e-308
-(.5*(1-.5^52)/(1-.5)*2^-1022)
8010 0000 0000 0000
-2.2250738585072014e-308
-(1.0*2^-1022)
8010 0000 0000 0001
-2.2250738585072019e-308
-((1+1/2^52)*2^(-1022))
801F FFFF FFFF FFFF
-4.4501477170144023e-308
-((1+.5*(1-.5^52)/(1-.5))*2^-1022)
8020 0000 0000 0000
-4.4501477170144028e-308
-(1.0*2^-1021)
BFF0 0000 0000 0000
-1.0000000000000000e+000
-1.0
BFFF FFFF FFFF FFFF
-1.9999999999999998e+000
-(1+.5*(1-.5^52)/(1-.5))
C000 0000 0000 0000
-2.0000000000000000e+000
-(1.0*2^1)
FFEF FFFF FFFF FFFF
-1.7976931348623157e+308
-((1+.5*(1-.5^52)/(1-.5))*2^1023)
FFF0 0000 0000 0000
-1.#INF000000000000e+000
-INF
FFF0 0000 0000 0001
-1.#SNAN00000000000e+000
SNaN
FFF7 FFFF FFFF FFFF
-1.#SNAN00000000000e+000
SNaN
FFF8 0000 0000 0000
-1.#IND000000000000e+000
QNaN
FFFF FFFF FFFF FFFF
-1.#QNAN00000000000e+000
QNaN
从表中可以看到,double内部表示的设计是很有规律的,按照对应64位数的顺序依次为 +0、正非规范数、正规范数、正无穷大、符号位为正的NaN、-0、负非规范数、负规范数、负无穷大、符号位为负的NaN。
double内部表示的设计保持了浮点数的有序性。即:如果正double数a
4 结束语
float和int都是32bit,但float的尾数只用了23bit。int的精度高于float,float的表示范围大于int。float牺牲精度换取了更大的表示范围。 double的尾数是52bit,高于32bit的int,所以用dobule表示int不会有精度损失。 double是科学计算的常用类型,了解double的内在和限制,有助于我们更好地使用它。
喜欢 (1)or分享 (0)
-
详谈单精度浮点数在内存中的存储及其误差问题
2021-11-14 17:25:53一、单精度浮点数的取值范围: 二、单精度浮点数在内存中的存储形式本文主要对单精度浮点数的范围大小进行一些简单的讨论。
分为五部分:
一、单精度浮点数的取值范围
二、单精度浮点数在内存中的存储形式
三、单精度浮点数的范围及其实现原理的关系
四、单精度浮点数在计算中造成误差的原因
一、单精度浮点数的取值范围:
二、单精度浮点数在内存中的存储形式
MS是符号部分,1为负 0为正
E是阶码部分,为31位到第24位这8个二进制位,表示该实数转化为规格化的二进制实数后的指数与127(127即所谓偏移量)之和即所谓阶码.
M是尾数部分,为第22位到第0位,表示该实数转化为规格化的二进制实数后小数点以后的其余各位即所谓尾数.那么150 .125(十进制)在内存中如何存储
第一步:求出其尾数部分
先将十进制数转化为二进制数并将其用科学计数法表示。
150.125(十进制)=10010110.001=1.0010110001*2^7
舍去小数点前的整数后,其小数部分0010110001并在后面补0直至位数达到23位,得到尾数部分
第二步:求出阶码部分
在第一步中的1.0010110001*2^7,得到指数7,那么其阶码为134(127+7),二进制形式为10000110
所以150.125在内存中的存储形式为:0 10000110 00101100010000000000000
三、单精度浮点数的范围及其实现原理的关系
在讨论这个问题之前需要提出几个前提的概念
概念1:normal number& subnormal number
根据IEEE754的规定, 按照尾数位隐藏的整数部分是 1 还是0可以将浮点数划分为两类: normal number和 subnormal number
normal number
就是尾数位隐藏的整数部分是1的数, 这种数叫做normal number, 可以理解为"正常的数",我们一般使用的单精度数为该种类型。
例子:
单精度数150.125在内存中的存储形式为:0 10000110 00101100010000000000000,
其尾数为00101100010000000000000舍去0010110001后的0,即0010110001,但其真正的尾数是1.0010110001,因为其整数部分被我们给舍去了。
这种数就为normal number。
subnormal number
尾数位隐藏的整数部分为0的数, 叫做subnormal number, 也叫作denormal number, 可以理解为"低于正常数的数"
IEEE754规定: 如果将阶码位全部填充为0, 则表示这个数是个subnormal number
当我们发现内存中阶码位全为0,那么这个数为subnormalnumber,并且其尾数舍去的整数部分部分为1。
这个概念的引入在浮点数下溢时, 可以逐位的损失精度, 以尽可能精确的表达0附近的极小数, 之后会具体讲解.
概念2: non-number
IEEE754规定:当阶码位全部被1填充, 即阶码表示的值为255时,那么这个数为non-number,表示这个值为±infinity或NaN(分别表示无穷和Not a Number)。
同样的当我们发现内存中阶码位全为1,那么这个数为non-number。
至此我们可以作以下总结。
阶码位情况 阶码位全为0 阶码在[1,254]
(十进制)
阶码位全为1 浮点数的类型 subnormal number normal number non-number -127的阶码用于表示subnormal number(阶码位全为0),128的阶码用于表示non-number(阶码位全为1)
所以normal number的阶码范围[1,254],在减去偏移量127之后为[-126,127],实际上单精度浮点数的有效阶码的范围在[-126,127]
对于normal number,其舍去(隐藏)的整数部分数为1
而尾数位用于表示十进制数转化为二进制数的科学计数法中的小数位,所以尾数的表示范围在[1.00000......,1.11111.....](二进制)=[1,2)(十进制)
由于尾数位位数有限,所以尾数的最大值只能尽可能接近2,且永远不会等于2。
这里开始体现出浮点数对于绝大部分实数只能尽可能近似等于的思想,这也是导致浮点数运算会导致误差的原因之一,下一节还会对浮点数误差进行讨论。
至此,我们可以对浮点数的范围进行估计了:
范围=±尾数*2^阶码
=±[1,2)*2^[-126,127]
=(-2*2^127,-1*2^-126]∪[1*2^-126,2*2^127)
=(-3.4028...*10^38,-1.1754...*10^-38]∪[1.1754...*10-38,34028...*10^38)
取其子集:
得到(-3.4*10^38,-1.8*10^-38]∪[1.8*10^-38,3.4*10^38)即为单精度浮点数范围
四、单精度浮点数在计算中造成误差的原因
原因一:数值溢出
单精度浮点数数值溢出分为上溢出和下溢出:
上溢出:
|浮点数运算结果|>|浮点数所能表示的最大数|
下溢出:
|浮点数运算结果|<|浮点数所能表示的最大数|
****下溢出时候,系统将运算结果处理为0
(解决方法:估算数据精度后,自定义数据类型或者采用更高精度的数据类型)
原因二:类型转换
我们很多人包括我之前也是,认为取值范围小的数据类型向取值范围大的数据类型进行赋值认为是安全的,但并不是,虽然这样不会造成数值溢出,但是会造成数值精度的损失。
long a=123456789;
float b;
b=a;
这时候单精度类型b的结果会是123456792.000000.
我们引入有效数字的概念:
从左边第一个非0的数字起,到精确的位数为止,期间的有效数字。
我们发现单精度类型b的有效数字是7.
原因三:二进制小数与十进制小数之间并不是一一对应的关系
二进制小数 十进制小数 2^-23 0.00000011920928955078125 2^-22 0.0000002384185791015625
2^-21 0.000000476837158203125 2^-20 0.00000095367431640625 2^-19 0.0000019073486328135 ...... ....... 我们可以发现二进制小数是连续的,而且有与之一一对应的十进制小数。
但是十进制小数同样有实数的稠密性,在相邻两个二进制小数所对应的十进制小数之间还有无数个小数,而十进制小数不一定有其所对应的二进制小数,。
这就导致我们在为单精度值进行赋值的时候,所用十进制数,不一定能有与之对应的二进制数,那么计算机是如何处理的呢?
计算机会让我们输入的十进制数近似等于某一个二进制数,这就是浮点数出现误差的原因。这是由于数字的性质和浮点数的构成所导致的误差,是无法避免的,我们在给一个浮点数赋值一个十进制数时,有确切与之对应的二进制数的可能性接近于0,所以从宏观上来看浮点数的误差无法避免,我们只能在能够解决问题的前提下相应地控制浮点数的误差。
最后,谢谢大家的阅读,对单精度浮点数的有效数字为何等于7的问题,我也会近期赶出来。
-
为什么IEEE754标准中单精度浮点数的阶码取值范围是1~254(-126~127)?
2020-03-15 16:38:45前提:以下都是建立在IEEE754标准中 2^8 = 256 2^7 = 128 带符号8位2进制本来应该是[-127, -0]U[+0, 127] 而该标准规定: E = 0000 0000 M = 000…000 用来表示了正、负零 E = 1111 1111 M = 000…000 用来表示了正... -
浮点数双精度,单精度以及半精度知识总结
2021-08-07 21:38:251.单精度(32位)浮点数的结构: 名称 长度 比特 位置 符号位 Sign(S): 1bit (b31) 指数部分Exponent(E): 8bit (b30-b23) 尾数部分Mantissa(M): 23bit (b22-b0) 其中的指数部分(E)采用的偏置码(biased)... -
输入(不少于20)个单精度数存入一维数组,将其逆序存放后输出。n从键盘输入。
2020-05-29 22:32:53#include<stdio.h> #define N 20 int main() { float a[N],t; float *p=a; int i; for(i=0;i<N;i++) scanf("%f",&a[i]); for(i=0;i<N/2;i++) { t=*(p+i); *(p+i)=a[N-1-i];... retur -
浮点运算/半精度,单精度,双精度/浮点和定点
2019-09-26 17:40:39参考深入理解C语言-03-有符号数,定点数,浮点数 1.1定点数 一般在没有FPU寄存器的嵌入式系统中使用比较多。比如常见的32位系统中,将高16位作为整数部分,低16位作为小数部分。 这样就可以用整数来模拟定点数的..... -
c语言中,常量,变量,浮点,单精度,双精度是什么意思?举例
2020-12-21 08:32:37在C语言中可以用单精度型和双精度型两种形式表示实型常量,分别用e68a843231313335323631343130323136353331333431376561类型名float和double进行定义。实型常量在一般的微型集中占用4个字节,一般形式或者指数形式... -
python - 接近完美的单精度浮点数转换代码
2020-07-01 17:11:36num = str(input("输入一个数,显示其浮点数在二进制中的存储,输入exit退出:")) if num=="exit":#此处几个if是float定义的几个量 print("退出运算") break if num=="0":#此处几个if是float定义的几个量 ... -
单精度和双精度浮点数数据类型
2016-07-16 09:58:44C、C++中使用到的单精度浮点数(float)类型和双精度浮点数(double)类型是在IEEE二进制浮点数算术标准(ANSI/IEEE Std 754-1985)中定义的。下面分别从存储格式、内存分布、编码规则、取值范围、有效数字位数和... -
C# 四个字节十六进制数和单精度浮点数之间的相互转化
2018-10-12 11:54:02单精度浮点数占4个字节,表示范围为:在负数的时候是从 -3.402823E38 到 -1.401298E-45,而在正数的时候是从 1.401298E-45 到 3.402823E38 。 一、在C#中的转换函数为: 1,由四个字节的十六机制数组转浮点数: ... -
Access中单精度类型运算过程中精度误差问题及处理
2018-12-13 18:37:14在Access中单精度类型在运算过程中会有产生精度误差,比如,一个双精度乘于一个单精度的值四舍五入保留为两位小数的双精度会有精度问题。 求KCMJ: KCMJ=TBMJ*KCXS,并将KCMJ四舍五入保留两位小数。 其中... -
单精度与双精度浮点型
2014-09-16 20:41:53这种结构是一种科学计数法,用符号、指数和尾数来表示,底数定为2—— 即把一个浮点数表示为尾数乘以2 的指数次方再添上符号。下面是具体的规格: 符号位 阶码 尾数 长度 float 1 8 23 -
JS - 4字节转单精度浮点数
2020-07-20 20:04:12虽然我们的数值类型包含浮点数整数等,但是在这里统称为 数值类型。同时 JavaScript 拥有动态类型,我们定义变量时无须指定数据类型。这也意味着我们的强制转换在JS中将失效。 若在 C/C++ 中,可以通过内存转换或... -
科普 | 单精度、双精度、多精度和混合精度计算的区别是什么?
2021-09-05 14:02:27科普 | 单精度、双精度、多精度和混合精度计算的区别是什么? 转自:https://zhuanlan.zhihu.com/p/93812784 我们提到圆周率 π 的时候,它有很多种表达方式,既可以用数学常数3.14159表示,也可以用一长串1和0的二... -
谨慎使用单精度/双精度数值类型
2011-12-26 21:51:15摘 要:在近日几个帖子里面,和QQ群的讨论里面,我发现很多网友都遇到的问题都是因为不恰当地使用了单精度/双精度数值。因此想专门就这个话题谈一下。 正 文: 前言 单精度和双精度数值类型最早出现在C语言中... -
单精度float变量在内存中的存储形式
2016-09-06 23:10:21首先我们知道单精度型占4个字节的大小也就是32个bit位和整形大小一样 但是存储方式却有很大的区别。 32个bit位可以分为三个部分 0 00000000 00000000000000000000000 1 8 23 (位数) 第一部分是 符号部分 -
JB∕T 11999-1-2014 数控往复走丝型多次切割电火花线切割机床 - 第1 部分:精度检验 - 完整中文版(30页)
2021-10-13 10:48:13JB/T 1999 的本部分规定了具有多次切割功能的数控往复走丝型电火化线切割机床(以下简称机 床)的几何精度检验 数控轴定位精度和重复定位精度检验及加工检验 还规定了与上述检验相对应的 允差值。 本部分也界定了用... -
[转载]用四个字节十六进制数表示单精度浮点数
2014-01-21 08:50:10原文地址:用四个字节十六进制数表示单精度浮点数作者:无名指 即是所谓的IEEE754标准,这也是大多数硬件存储浮点数的标准。单精度浮点数占4个字节,表示范围为:在负数的时候是从 -3.402823E38 到 -1.401298E-45,... -
C语言实现输出单精度、双精度小数十进制形式
2013-12-07 23:38:56故特意查找了一下单精度、双精度小数的二进制编码,自己实现一个输出十进制字符串的函数。具体代码如下所示。 #include"decimalString.h" #include int lengthOfInt(int a);//a十进制绝对值的位数 //整数a十进制... -
mysql的float类型是单精度浮点类型导致数据误差.
2012-04-20 16:02:32单精度浮点数用4字节(32bit)表示浮点数 ...对于单精度浮点数Float: 当数据范围在±131072(65536×2)以内的时候,float数据精度是正确的,但是超出这个范围的数据就不稳定,没有发现有相关的参数设 -
单精度浮点数(IEEE754)
2010-05-22 12:11:00单精度浮点数占据4个字节,4个字节的分配如下: (a)第一位为符号位,0表示正,1表示负; (b)第2~9位为阶码,采用移码表示; (c)第10~32位为尾数,采用原码表示。 (1)给定32位串,如何转换成十进制数... -
Java将字符串转换为双精度
2020-07-13 05:54:52例如,如果String为“ 1,11,111.23d”,则可以使用DecimalFormat将此字符串解析为以下形式的两倍: 请注意,parse()方法返回Number实例,因此我们正在调用doubleValue()以从中获取double基本类型。 如果字符串的... -
单精度浮点数计算机存储的理解(IEEE 754)
2013-03-30 18:42:00以下是该标准对浮点数格式的描述。 [编辑]本文表示比特的约定 把W个比特(bit)的数据,从内存地址低端到高端,以0到W−1编码。通常将内存地址低端的比特写在最右边,称作最低有效位(least significant bit或lsb),... -
C语言单精度浮点型转换算法
2017-06-16 16:02:00关于16进制浮点数对于大小为32-bit的浮点数(32-bit为单精度,64-bit浮点数为双精度,80-bit为扩展精度浮点数),1、其第31 bit为符号位,为0则表示正数,反之为复数,其读数值用s表示;2、第30~23 bit为幂数,其读... -
C语言中的单精度、双精度、常量等都有什么意思?
2021-05-25 01:29:17单(float) :占用比特数32,有效数位6-7,数值范围(-3.4e-38 ~ 3.4e+38)双(double):占用比特数64,有效数位15-16,数值范围(-1.7e-308 ~ 1.7e+308)以下为对于中整型、字符型、浮点型的解释:引用c语言中,...