首页 > 编程知识 正文

为什么定点数精度高于浮点数,定点数和浮点数哪个范围大

时间:2023-05-05 15:39:41 阅读:151095 作者:333

最近正在研究CNN的硬件实现。 其中,关于特征图像、权重和偏移文件的量化,需要研究浮点数、固定点数之间的转换。 权重浮点数转换为标准固定点数时,必须自己编写固定点数的乘法和加法运算。 在c中,int、short等整形通过补数进行运算,但由于固定点数(负数)和补数的形式不同,如果使用直接加法的话,设计会变得困难

一.浮点数c语言有float型、double型、long double型三种浮点数,其中float型为4字节,double型为8字节,long double型的长度为double型以上。 本书以float型为例进行说明。 对双精型和长精型进行说明

float型可以表达的范围为-3.402823466e38-3.402823466e38,而作为同一个4字节的常量点,只能表达-2147483648~2147483647的范围,这不是很奇怪吗? 即使使用同一个存储器空间,也能表现浮点数远远大于定数的范围,这不是很奇怪吗? 既然浮点数可以表示这么大的范围,为什么不用浮点数代替固定点数呢?

浮点数的实现是复杂的暂且不论,有些处理器专门配置了硬件浮点运算单元进行浮点运算。 主要原因是浮点数因为精度问题,不能代替固定点数。 鱼和熊掌不能兼得。 浮点数显示了非常大的范围,但失去了非常准确的精度。 在说明精度问题之前,先了解一下浮点数的格式吧。

ANSI/IEEEStd 754-1985标准

IEEE 754是应用最广泛的二进制浮点运算标准,被许多CPU和浮点运算器所采用。 IEEE754规定了几种表示浮点数的方法,但本书仅介绍32bits的浮点型。 它分为符号位S(sign bit、指数偏差E(exponent bias、尾数位F(fraction ) ) 3个部分。

单精度浮点数数据的位宽为32位,可以分为3个部分。 其中,符号位s为1位,指数位e为8位,尾数位f为23位,其代数形式如下。

浮点数为0x41040000时,存储在计算机中的格式为0100000100000100000100000000000 b。

符号是0

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

小数位数为00001000000000000000000

1.00001000000000000000000=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 -1x0.9999695

Q14 S1.14 -2x1.9999390

Q13 S2.13 -4x3.9998779

Q12 S3.12 -8x7.9997559

Q11 S4.11 -16x15.9995117

Q10 S5.10 -32x31.9990234

QS6.9-64x63.9980469

QS7.8-128x127.9960938

7s8.7-256x255.9921875

6s9.6-512x511.9804375

5s10.5-1024x1023.96875

QS11.4-2048x2047.9375

QS12.3-4096x4095.875

2s13.2-8192x8191.75

1s14.1-16384x16383.5

QS15.0-32768x32767

2.1定点示例:

即使是相同的16位,小数点设定的位置不同,显示的数量也不同。 开头是符号位数。

十六进制2000 H=进制0 010 0000 0000 b=进制8192,Q0表示

十六进制2000 H=进制0 010 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("%xn", *((int*)var));//%x 16进制输出整数printf("%xn", *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语言zlddp,从研究浮点数定点数到写好程序用了四天,发现网上的介绍很多,但是开源的代码不多,就把自己写的开源吧,包括浮点定点转换,定点乘法、加法运算等。供参考。
github源码地址:https://github.com/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));

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。