糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > 浮点数和定点数

浮点数和定点数

时间:2019-06-24 12:17:25

相关推荐

浮点数和定点数

最近在研究CNN的硬件实现,其中涉及到特征图像、权重和偏移文件的量化,需要研究浮点数、定点数之间的转化,如果权重浮点数转化为标准的定点数,则需要自己写定点数的乘法和加法运算,因为在C中,int,short等整形是用补码进行运算的,但是定点数(负数)和补码形式不一样,如果直接用加法,设计到负数运算时,出错。

一.浮点数

C语言中有3种浮点数,float型、double型和long double型,其中float型占4个字节,double型占8个字节,longdouble型长度要大于等于double型,本文档将以float型为例进行介绍,double型和long double型只是比float型位数长,原理都是一样的。

float型可以表示的范围是-3.402823466e38-3.402823466e38,而作为同为4个字节的定点数却只能表示-2147483648~2147483647的范围,使用同样的内存空间,浮点数却能比定点数表示大得多的范围,这是不是太神奇了?既然浮点数能表示这么大的范围,那么我们为何不使用浮点数来代替定点数呢?

先不说浮点数实现起来比较复杂,有些处理器还专门配置了硬件浮点运算单元用于浮点运算,主要原因是浮点数根本就无法取代定点数,因为精度问题。鱼和熊掌不可兼得,浮点数表示了非常大的范围,但它失去了非常准的精度。在说明精度问题前,我们先了解一下浮点数的格式。

ANSI/IEEEStd 754-1985标准

IEEE 754是最广泛使用的二进制浮点数算术标准,被许多CPU与浮点运算器所采用。IEEE754规定了多种表示浮点数值的方式,在本文档里只介绍32bits的float浮点类型。它被分为3个部分,分别是符号位S(sign bit)、指数偏差E(exponent bias)和尾数位F(fraction)。

单精度浮点数数据位宽共有 32 位,可以分为三个部分,其中符号位 S 只有 1 位,指数位E 为 8 位,尾数位 F 为 23 位,其代数形式为:

若一个浮点数为0x41040000,在计算机中存储的形式为0100 0001 0000 0100 0000 0000 0000 0000b,

符号位为:0

指数位为:1000 0010b = 130 130-127=3

尾数位为:000 0100 0000 0000 0000 0000

1.000 0100 0000 0000 0000 0000 = 1+(1/2^5) = 1.03125

1.03125*2^2 = 8.25

因此,该数据表示的浮点数为:8.25

二、定点数

参与数值运算的数为16位的整型数。但在许多情况下,数学运算过程中的数不一定都是整数。

应该说,运算芯片本身无法处理小数。关键就是由程序员来确定一个数的小数点处于16位中的哪一位。这就是数的定标。

{通过设定小数点在16位数中的不同位置,就可以表示不同大小和不同精度的小数}

数的定标有Q表示法和S表示法两种。下面列出了一个16位数的16种Q表示、S表示及它们所能表示的十进制数值范围:

Q表示 S表示 十进制数表示范围

Q15 S0.15 -1≤x≤0.9999695

Q14 S1.14 -2≤x≤1.9999390

Q13 S2.13 -4≤x≤3.9998779

Q12 S3.12 -8≤x≤7.9997559

Q11 S4.11 -16≤x≤15.9995117

Q10 S5.10 -32≤x≤31.9990234

Q9 S6.9 -64≤x≤63.9980469

Q8 S7.8 -128≤x≤127.9960938

Q7 S8.7 -256≤x≤255.9921875

Q6 S9.6 -512≤x≤511.9804375

Q5 S10.5 -1024≤x≤1023.96875

Q4 S11.4 -2048≤x≤2047.9375

Q3 S12.3 -4096≤x≤4095.875

Q2 S13.2 -8192≤x≤8191.75

Q1 S14.1 -16384≤x≤16383.5

Q0 S15.0 -32768≤x≤32767

2.1 定点表示示例:

同样一个16位数,若小数点设定的位置不同,它所表示的数也不同(首位为符号位):

16进制数2000 H= 二进制数0 010 0000 0000 0000 B= 十进制数8192, Q0表示法

16进制数 2000 H= 二进制数0 010 0000 0000 0000 B= 十进制数0.25 , Q15表示法

三、 浮点定点转换:

不同的Q所表示的数不仅范围不同,而且精度也不相同。

Q越大,数值范围越小,但精度越高;相反,Q越小,数值范围越大,但精度就越低。

E.g.

Q0 的数值范围是-32768到+32767,其精度为1;而Q15的数值范围为-1到0.9999695,精度为1/32768=0.00003051。

因此,对定点数而言,数值范围与精度是一对矛盾。

一个变量要想能够表示比较大的数值范围,必须以牺牲精度为代价;而想精度提高,则数的表示范围就相应地减小。

在实际的定点算法中,为了达到最佳的性能,必须充分考虑到这一点。

3.2 转换关系:

浮点数与定点数的转换关系可表示为:

浮点数(Fx)转换为定点数(Ix):Ix = (int)x* 2^Q

定点数(Ix)转换为浮点数(Fx):Fx= (float)Ix*2^(-Q)

3.3 转换示例:

浮点数 Fx = 0.5,定标 Q = 15,则定点数:

Ix = floor(0.5*32768) = 16384

反之,一个用 Q = 15 表示的定点数Ix = 16384,其浮点数为:

Fx = 16384 * 2^(-15) = 16384 / 32768 = 0.5

浮点数转换为定点数时,为了降低截尾误差,可以在取整前可以先加上0.5,视情况而定。

四、程序验证

#define _CRT_NONSTDC_NO_DEPRECATE#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>int main(){float value;float *var = &value;int value_int;int *var_int = &value_int;scanf("%f", var);scanf("%d", var_int);printf("%x\n", *((int*)var));//%x 16进制输出整数printf("%x\n", *var_int);return 0;}

结果如下:

可见,浮点数在计算机中的保存、数据处理是按照浮点数标准进行的,int,short等整形数据类型是按照二进制补码来表示的。

浮点数转定点数的程序如下:

Qn为浮点数定标;

short float2fixed_fun(float fdata, int Qn){short sdata;int temp;int integer = 2 << (Qn - 1);if (fdata > 0){temp = int((fdata * integer));sdata = (temp == short(temp)) ? temp : (temp >> 31) ^ 0x7fff;}else if (fdata < 0){fdata = -fdata;temp = int((fdata * integer));sdata = (temp == short(temp)) ? temp : (temp >> 31) ^ 0x7fff;sdata = sdata ^ SIGN_BIT;}elsesdata = 0;return sdata;}

定点数转浮点数程序如下:

float fixed2float_fun(short sdata, int Qn){int sign_flag = sdata & SIGN_BIT;//1->负数 0->正数float fdata,temp;short temp1;int integer = 2 << (Qn - 1);if(sign_flag == 0){ //该定点数为正fdata = float(sdata)/integer;}else{temp1 = sdata ^ SIGN_BIT;//temp = float(sdata ^ SIGN_BIT);直接使用此语句,结果不正确,不知为何temp = float(temp1);fdata = temp / integer;fdata = -fdata;}return fdata;}

C语言小白,从研究浮点数定点数到写好程序用了四天,发现网上的介绍很多,但是开源的代码不多,就把自己写的开源吧,包括浮点定点转换,定点乘法、加法运算等。供参考。

github源码地址:/alangaixiaoxiao/CNN-float-fixed-translation-

四、浮点定点转换(补码表示)

负数在计算机中是用补码的形式存储的,正数在计算机中是用原码的形式存储的。

正数求原码直接将十进制转二进制即可,负数的补码是在原码的基础上除符号位外其余位取反后+1。

之前是将数据用标准的定点数表示方法来进行表示和运算的,这样有一个问题,那就是运算的时候,还需要自己针对定点数的标准写乘法器和加法器,尤其是在硬件运算时,需要去优化。因此,也可以用补码的形式了表示负数定点数。转换代码如下:

//浮点数转定点数short fixed_data = (short)(float_data*pow(2.0,Qn));//定点数转浮点数float float_data = (float)(fixed_data*pow(2.0,-Qn));

如果觉得《浮点数和定点数》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。