最近要写段数字运算的程序,因为从FPGA获取到的是定点数,15位数,最高位bit14是符号位,bit13是整数位,后面13位是小数位; 而我的运算过程都是用的浮点数,通过一系列计算后,还需要将计算的结果以定点数的形式写入寄存器,所以首先需要写一个定点数和浮点数相互转换的函数。
首先明确一下定点数和浮点数的概念:
定点数
定点数是小数点固定的数。在计算机中没有专门表示小数点的位,小数点的位置是约定默认的。一般固定在机器数的最低位之后,或是固定在符号位之后。前者称为定点纯整数,后者称为定点纯小数。
例题:用8位原码表示定点整数(100)10
(100)10 = (1100100)2
定点整数表示为
例题:用8位原码表示定点纯小数(-0.6875)10
(-0.6875)10 = (-0.1011)2
定点纯小数表示为
定点数表示法简单直观,但是数值表示的范围太小,运算时容易产生 溢出。
浮点数
浮点数是小数点的位置可以变动的数。为增大数值表示范围,防止溢出,采用浮点数表示法。浮点表示法类似于十进制中的科学计数法。
在计算机中通常把浮点数分成阶码和尾数两部分来表示,其中阶码一般用补码定点整数表示,尾数一般用补码或原码定点小数表示。为保证不损失有效数字,对尾数进行规格化处理,也就是平时所说的科学记数法,即保证尾数的最高位为1,实际数值通过阶码进行调整。
一般浮点数在机器中的格式为:
阶符表示指数的符号位、阶码表示幂次、数符表示尾数的符号位、尾数表示规格化后的小数值。
N = 尾数×基数阶码(指数)
例题:二进制数-110101101.01101可以写成:-0.11010110101101×21001
这个数在机器中的格式为(阶码用8为表示,尾数用24位表示)
C语言代码实现如下:
* 函数名称: BspFixToDou
* 功能描述: 将指定的定点数 转化为 浮点数
* 算法描述: 无
* 输入参数: ucType 0表示无符号 1表示有符号
* ucInteger 表示整数占几个bit
* ucdecimal 表示小数占几个bit
* llfix 为待转化的定点数
* 输出参数: 无
* 返 回 值: 无
************************************************************************/
VOID BspFixToDou(UCHAR ucType, UCHAR ucInteger, UCHAR ucdecimal, UINT64 llfix, DOUBLE *pdbRet)
{
UINT64 lltemp = llfix & ((((UINT64)(1)<<(ucType + ucInteger + ucdecimal))-1));
if(0 == llfix)
{
*pdbRet = 0.0;
}
if(lltemp & (((UINT64)(1)<<(ucInteger + ucdecimal)))) /* 有符号数并且是负数 */
{
*pdbRet = -(DOUBLE)(((UINT64)(1)<<(ucType + ucInteger + ucdecimal)) - lltemp)/(DOUBLE)((UINT64)(1)<<ucdecimal);
}
else /* 无符号数或者有符号数的正数*/
{
*pdbRet = (DOUBLE)((DOUBLE)lltemp/(DOUBLE)((UINT64)1<<ucdecimal));
}
}
/*<FUNC>***********************************************************************
* 函数名称: BspDouToFix
* 功能描述: 将指定的浮点数 转化为 定点数
* 算法描述: 无
* 输入参数: ucType 0表示无符号 1表示有符号
* ucInteger 表示整数占几个bit
* ucdecimal 表示小数占几个bit
* dbDou 为待转化的浮点数
* 输出参数: 无
* 返 回 值: 转化后的定点数
************************************************************************/
VOID BspDouToFix(UCHAR ucType, UCHAR ucInteger, UCHAR ucdecimal, DOUBLE dbDou, UINT64 *pllfix)
{
UINT64 lltemp = 0;
DOUBLE dbtemp = 0;
dbtemp = dbDou;
if(dbtemp < 0) /* 有符号正数 或者 无符号数 */
{
lltemp = (UINT64)(-dbDou*(1<<ucdecimal));
*pllfix = (UINT64)((UINT64)(1)<<(ucType + ucInteger + ucdecimal)) - lltemp;
}
else if(dbtemp > 0) /* 有符号负数 */
{
*pllfix = (UINT64)(dbDou * (1<<ucdecimal));
}
else
{
*pllfix = 0;
}
}