浮点数和定点数

最近在研究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;
	}
	else
		sdata = 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源码地址: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));
FFT(快速傅里叶变换)算法是一种将离散傅里叶变换(DFT)计算效率由O(n^2)降低到O(nlogn)的算法,用于对信号进行频域分析。FFT算法可以同时适用于浮点数定点数浮点数是在计算机中表示实数的一种形式,可以包含小数部分。FFT算法在处理浮点数时,使用浮点数乘法和加法运算作为基础操作。由于浮点数表示实数的范围和精度有限,因此在进行FFT计算时可能会存在舍入误差或精度损失的问题。为了提高计算精度,可以采用双精度浮点数进行计算,但会增加计算复杂度。 定点数是通过固定小数点位置来表示实数的一种形式,可以看作是浮点数的一种特殊情况。在FFT算法中,可以使用定点数表示实数,并采用整数运算作为基础操作。定点数运算具有相对较低的计算复杂度和更高的计算精度,但需要注意定点数表示实数的范围和精度有限性。 在使用FFT算法时,选择使用浮点数还是定点数取决于具体的应用需求。对于一些对精度要求较高的应用,如音频处理或图像处理,浮点数的精度可能更适合。而对于一些计算资源受限的应用,如无线通信中的频谱分析,定点数的计算效率可能更为重要。 总而言之,FFT算法可以适用于浮点数定点数。在使用时需要根据具体的应用需求和计算资源限制,权衡使用浮点数还是定点数,并考虑计算精度和计算效率的平衡。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值