什么是定点数和浮点数
计算机中的数除了整数之外,还有小数。如何确定小数点的位置呢?通常有两种方法:
一种是规定小数点位置固定不变,称为定点数。
另一种是小数点的位置不固定,可以浮动,称为浮点数。
在计算机中,通常是用定点数来表示整数和纯小数,分别称为定点整数和定点小数。对于既有整数部分、又有小数部分的数,一般用浮点数表示。下面分别予以介绍:
(1)定点整数:在定点数中,当小数点的位置固定在数值位最低位的右边时,就表示一个整数。请注意:小数点并不单独占1个二进制位,而是默认在最低位的右边。定点整数又分为有符号数和无符号数两类。
(2)定点小数:当小数点的位置固定在符号位与最高数值位之间时,就表示一个纯小数。因为定点数所能表示数的范围较小,常常不能满足实际问题的需要,所以要采用能表示数的范围更大的浮点数。定点就是小数点确定在第几位的.如果是整数,规定小数点在最后一位.若是小数,小数点就在第一位和第二位之间,比如0.1234e3就是定点表示的123.4.浮点就是小数点位置不确定,比如123.43,6557.521.在C语言中,一般单精度数据类型比如int,数据的范围是2的31次方,而双精度类型
的整型比如long int的数据范围是2的63次方.所以双精度和单精度主要的区别在于数据的范围大小
(3)浮点数:浮点数是属于有理数中某特定子集的数的数字表示,在计算机中用以近似表示任意某个实数。具体的说,这个实数由一个整数或定点数(即尾数)乘以某个基数(计算机中通常是2)的整数次幂得到,这种表示方法类似于基数为10的科学记数法。浮点数在计算机中用以近似表示任意某个实数。浮点计算是指浮点数参与的运算,这种运算通常伴随着因为无法精确表示而进行的近似或舍入。一个浮点数a由两个数m和e来表示:a = m × be。在任意一个这样的系统中,我们选择一个基数b(记数系统的基)和精度p(即使用多少位来存储)。m(即尾数)是形如±ddd的p位数(每一位是一个介于0到b-1之间的整数,包括0和b-1)。如果m的第一位是非0整数,m称作规格化的。有一些描述使用一个单独的符号位(s 代表+或者-)来表示正负,这样m必须是正的。e是指数。 这种设计可以在某个固定长度的存储空间内表示定点数无法表示的更大范围的数。例如,一个指数范围为±4的4位十进制浮点数可以用来表示43210,4.321或0.0004321,但是没有足够的精度来表示432.123和43212.3(必须近似为432.1和43210)。当然,实际使用的位数通常远大于4。此外,浮点数表示法通常还包括一些特别的数值:+∞和−∞(正负无穷大)以及
NaN('Not a Number')。无穷大用于数太大而无法表示的时候,NaN则指示非法操作或者无法定义的结果。大部份计算机采用二进制(b=2)的表示方法。位(bit)是衡量浮点数所需存储空间的单位,通常为32位或64位,分别被叫作单精度和双精度。有一些计算机提供更大的浮点数,例如英特尔公司的浮
点运算单元Intel8087协处理器(以及其被集成进x86处理器中的后代产品)提供80位长的浮点数,用于存储浮点运算的中间结果。还有一些系统提供128位的浮点数。
在浮点数表示法中,小数点的位置是可以浮动的。在大多数计算机中,都把尾数S定为二进制纯小数,把阶码P定为二进制定点整数。尾数S的二进制位数决定了所表示数的精度;阶码P的二进制位决定了所能表示的数的范围。为了使所表示的浮点数既精度高、又范围大,就必须合理规定浮点数的存储格式。
计算机中的所有数据都是以二进制表示的,浮点数也不例外。然而浮点数的二进制表示法却不像定点数那么简单了。先澄清一个概念,浮点数并不一定等于小数,定点数也并不一定就是整数。所谓浮点数就是小数点在逻辑上是不固定的,而定点数只能表示小数点固定的数值,具用浮点数或定点数表示某哪一种数要看用户赋予了这个数的意义是什么。
C++中的浮点数有6种,分别是:
float:单精度,32位
unsigned float:单精度无符号,32位
double:双精度,64位
unsigned double:双精度无符号,64位
long double:高双精度,80位
unsigned long double:高双精度无符号,80位(嚯,应该是C++中最长的内置类型了吧!)然而不同的编译器对它们的支持也略有不同,据我所知,很多编译器都没有按照IEEE规定的标准80位支持后两种浮点数的,大多数编译器将它们视为double,或许还有极个别的编译器将它们视为128位?!对于128位的long double我也仅是听说过,没有求证,哪位高人知道这一细节烦劳告知。下面我仅以float(带符号,单精度,32位)类型的浮点数说明C++中的浮点数是如何在内存中表示的。先讲一下基础知识,纯小数的二进制表示。(纯小数就是没有整数部分的小数,讲给小学没好好学的人)
纯小数要想用二进制表示,必须先进行规格化,即化为 1.xxxxx * ( 2 ^ n ) 的形式(“^”代表乘方,2 ^ n表示2的n次方)。对于一个纯小数D,求n的公式如下:
n = 1 + log2(D);// 纯小数求得的n必为负数
再用 D / ( 2 ^ n ) 就可以得到规格化后的小数了。接下来就是十进制到二进制的转化问题,为了更好的理解,先来看一下10进制的纯小数是怎么表示的,假设有纯小数D,它小数点后的每一位数字按顺序形成一个集合:
{k1, k2, k3, ... , kn}
那么D又可以这样表示:
D = k1 / (10 ^ 1 ) + k2 / (10 ^ 2 ) + k3 / (10 ^ 3 ) + ... + kn / (10 ^ n )
推广到二进制中,纯小数的表示法即为:
D = b1 / (2 ^ 1 ) + b2 / (2 ^ 2 ) + b3 / (2 ^ 3 ) + ... + bn / (2 ^ n )
现在问题就是怎样求得b1, b2, b3,……,bn。算法描述起来比较复杂,还是用数字来说话吧。声明一下,1 / ( 2 ^ n )这个数比较特殊,我称之为位阶值。
例如0.456,第1位,0.456小于位阶值0.5故为0;第2位,0.456大于位阶值0.25,该位为1,并将0.45减去0.25得0.206进下一位;第3位,0.206大于位阶值0.125,该位为1,并将0.206减去0.125得0.081进下一位;第4位,0.081大于0.0625,为1,并将0.081减去0.0625得0.0185进下一位;第5位0.0185小于0.03125……
最后把计算得到的足够多的1和0按位顺序组合起来,就得到了一个比较精确的用二进制表示的纯小数了,同时精度问题也就由此产生,许多数都是无法在有限的n内完全精确的表示出来的,我们只能利用更大的n值来更精确的表示这个数,这就是为什么在许多领域,程序员都更喜欢用double而不是float。
float的内存结构,我用一个带位域的结构体描述如下:
struct MYFLOAT
{
bool bSign : 1; // 符号,表示正负,1位
char cExponent : 8; // 指数,8位
unsigned long ulMantissa : 23; // 尾数,23位
};
符号就不用多说了,1表示负,0表示正
指数是以2为底的,范围是 -128 到 127,实际数据中的指数是原始指数加上127得到的,如果超过了127,则从-128开始计,其行为和X86架构的CPU处理加减法的溢出是一样的。比如:127 + 2 = -127;127 - 2 = 127
尾数都省去了第1位的1,所以在还原时要先在第一位加上1。它可能包含整数和纯小数两部分,也可能
只包含其中一部分,视数字大小而定。对于带有整数部分的浮点数,其整数的表示法有两种,当整数大于十进制的16777215时使用的是科学计数法,如果小于或等于则直接采用一般的二进制表示法。科学计数法和小数的表示法是一样的。
小数部分则是直接使用科学计数法,但形式不是X * ( 10 ^ n ),而是X * ( 2 ^ n )。拆开来看。
0000000000000000000000000000000
符号位指数位尾数位
双精度浮点数和单精度浮点数
这两者主要在精度上有区别。
双精度浮点数能精确表示 1.79769313486231570E+308 到 -4.94065645841246544E-324 范围的负数和从 4.94065645841246544E-324 到 1.79769313486231570E+308 范围的正数。
单精度浮点数能够精确表示从 -3.4028235E+38 到 -1.401298E-45 的负数和从 1.401298E-45 到 3.4028235E+38 的正数。
单精度浮点数的精度没有双精度那么高,但是所需内存少,运算速度快。
提示
如果对精度要求不高,则应该尽量避免使用双精度浮点数,而应该使用单精度浮点数。这一点在一
些大型应用程序中非常重要。如果在定义变量时,单精度浮点数就足够了,但是却使用了双精度浮点数,会大大减慢程序的运行。
如果某个变量只需要整数类型就足够了,应避免用浮点数。因为整数的运算速度更快。
浮点数转换成十进制数的步骤
该步骤与前面“十进制数转换成浮点数”的步骤是互逆的,其具体步骤如下:
1、分割数字的符号、阶码和有效数字;
2、将偏移阶码减去偏移,得到真正的阶码;
3、把数字写成规格化的二进制数形式;
4、把规格化的二进制数改变成非规格化的二进制数;
5、把非规格化的二进制数转换成十进制数。
例11.2 把协处理器中的浮点数1100000111001001000000000000转换成十进制数
解
1、把浮点数1100000111001001000000000000分割成三部分,可得:
符号位是1,阶码是10000011,尾数是1001001000000000000
2、还原阶码:10000011 – 01111111=100
3、该浮点数的规格化形式:1.1001001×24 (其中前面的“1.”从隐含位而来)
4、该浮点数的非规格化形式:11001.001
5、该浮点数的十进制数为-25.125 (因为符号位为1,所以,该数是负数)
下面是学习和掌握十进制数转化为浮点数的控件,它可按步骤演示整个转换过程。
三、浮点数说明形式
在汇编语言中,可用DD、DQ和DT来分别说明单精度、双精度和扩展精度的浮点数。
在MASM 6.0系统中,正浮点数前面不能书写‘+’,但MASM 6.11系统更正了这种错误,并提供了新的浮点数说明方法,即:可用REAL4、REAL8和REAL10来分别代替DD、DQ和DT。
在定义浮点数时,要使用伪指令.8087、.287或.387等。
例如:
.387
data1DD123, -543;定义单精度浮点数浮点数的基数什么意思
data2REAL43.345E+3;定义单精度浮点数
data3REAL8321.545;定义双精度浮点数
data4REAL10254.555;定义扩展精度浮点数
浮点数转换到16进制字符串
这几天一直在弄postgre的数据写入,特别是几何数据的写入。在几何数据的写入过程中,可以有多种
通过WKB,TEXT都是可以的。先觉得,通过Text建立会比较慢,因为要用到geometryfromtext,与把数据转换成文本再让数据库进行转换,不如自己进行转换成 WKB形式的
第一段的难点就是将double类型转换成十六进制字符串,就是将64bit转换成16进制字符串表示。首先学习了IEEE754标准,了解浮点函数的编码方式。
void TestDouble(double value)
...{
int count=0;
string x;
if (value>0)
...{
x+="0"; //判断符号
}
else
...{
x+="1";
value=-value;
}
while (2<=value) //获得小数点后值
...{
value=value/2.0;
count++;
}
count=count+1023;
/
/将阶码变成二进制表示
bitset<11>code(count);
x+=_string(); //前半部分二进制表示
int digit=-1;
value-=1.0;
//////////////////////////////////////////////////////////////////////////将数值用二进制表示/////
double posval=0.0;
double tempval=0.0;
while (value!=0&&digit>-54)
...{
posval=Power(2,digit);
tempval=value-posval;
if(tempval>0)
...{
x+="1";
value=tempval;
}
else if (tempval==0)
...{
x+="1";
break;
}
else
x+="0";
--digit;
}
int size=64-x.size();
if (size>0)
...{
char* temp=new char[size];
memset(temp,'0',size);
x.append(temp,size);
delete temp;
}
cout<<binTohexstr(x)<<endl;
}
static string binTohexstr(string temp)
...{
string value="";
if (temp.size()%4!=0)
...{
return NULL;
}
while ((temp.size()-4)>0)
.
..{
value+=binTohex(temp.substr(0,4));
temp=temp.substr(4,temp.size()-4);
}
value+=binTohex(temp);
return value;
}
static char binTohex(string temp)
...{
if("0000"==temp)
return '0';
else if("0001"==temp)
return '1';
else if("0010"==temp)
return '2';
else if ("0011"==temp)
return '3';
else if("0100"==temp)
return '4';
else if("0101"==temp)
return '5';
else if("0110"==temp)
return '6';
else if("0111"==temp)
return '7';
else if("1000"==temp)
return '8';
else if("1001"==temp)
return '9';
else if("1010"==temp)
return 'A';
else if("1011"==temp)
return 'B';
else if("1100"==temp)
return 'C';
else if("1101"==temp)
return 'D';
else if("1110"==temp)
return 'E';
else if("1111"==temp)
return 'F';
else
return 'G';
}
上面是整个转换到流程,先转换成二进制,难点在于理解double值得表示方式为value=(1+m)*2n其中2n表示2的n次方。首先求出2的阶码,double的阶吗有12位,就是2048次方,但是double还有表示小数后的值,所以要表示-1023~1024的值,就要进行转换。得到的值都是需要进行移位,3.5=(1+0.75)×2;所以阶吗就是1+1023=1024,就是10000000。另外double 的第一位是符号位,0是正,1是负。(1+m)中的M是大于0小于1的。这个M是value不断被2除得到大于1小于2的数字,又因为double里面的数都是默认加个1,所有得到m。
m再用小数表示,得到结果
请教一个浮点数转换成定点数的问题!
输入是一个24位的ieee754标准的浮点数,格式是1_8_15,已经直接去掉了最后8位, 如何把它转换
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论