如何对任意精度类型的变量初始化
对于ap_int类型
在C/C++里,是通过变量类型+变量名+数值,来对一个变量初始化,同样,对于任意精度的数据类型,我们也可以采用这种方式来进行变量初始化。在Vivado Hls里是支持copy initialization(Y)和direct initialization(Y)这两种方式来进行初始化,但不支持uniform initialization,同时,对于任意精度的数据类型,还可以采用基数符号+数值+基数,例如:
int data_i = 5;
ap_int<8> a_8bit_data_c = 18;
ap_int<8> a_8bit_data_d (18);
ap_int<8> a_8bit_data_r2("0b010010",2);
ap_int<8> a_8bit_data_r8("0o22",8);
ap_int<8> a_8bit_data_r10("18",10);
ap_int<8> a_8bit_data_r16("0x12",16);
注意:上面的基数符号是可以去掉的,在初始化的时候,尽可能每一行只初始化一个变量,避免在一行初始化多个变量
对于ap_fixed类型
前面我们提到ap_fixed< W,I,Q,O>,这里W代表整个数据的字长,I代表整数部分的字长,那么小数部分被的字长就是W-I,Q表示量化模式(针对低位部分),O表示溢出模式,针对高位部分,例如:
ap_fixed<3,2> data1 = 1.25;
ap_fixed<3,2,AP_RND> data1 = 1.25
此时的结果分别为1(等价于01.0)和1.5(等价于01.1)
ap_fixed<4,4> data3 = 20
ap_fixed<3,2,AP_RND,AP_SAT> data1 = 20
此时的结果分别为4(等价于0100)和7(等价于0111)
对于浮点类型
对于单精度类型浮点需要有后缀f,对于双精度则可以省略,例如:
double data1(2.0)
flout data2(2.0f)
Vivado Hls对这些数据类型都是支持的,并且还提供一个数学库hls_math.h,它对C语言(math.h)和C++(cmath.h)都是支持的,这种支持包括单精度,双精度浮点的一些函数,还包括对数据类型本身的支持。
数据类型的转换
隐式数据类型转换
隐式数据类型转换包括Numeric promotion 和 Numeric conversion。
Numeric promotion是一种安全模式,它把数据类型从小类型向大类型的数据转换,对于有符号数据类型,就是进行数据位的扩展,对于无符号数据类型来说,就是进行高位0扩展,例如:
ap_uint<8> data;
ap_int<4> x1 = -4;
ap_uint<4> x2 = 4;
data1 = x1;
data2 = x2;
这里得到的data1为252(0b11111100),由于x1为有符号,所以进行符号位的扩展,而data2为4(0b00000100),由于x2为无符号,所以进行高位0的扩展。
Numeric conversion是把大类型向小类型的数据转换,这种转换可能导致数据的损失或者结果的错误,例如:
ap_int<2> data;
ap_int<4> x3 = -3;
ap_uint<4> x4= 3;
data3 = x3;
data4 = x4;
这里得到的data3为-1(0b11),data4为-1(0b11),这是由于data为有符号数据类型,导致结果错误。
ap_fixed<4,2> data5 = 1.25;
ap_fixed<3,2,AP_RND> data6 = data5
这里得到的data6为1.5(0b01.1),导致数据精度的损失。
显式数据类型的转换
显式数据类型的转换有两种方式,一种是通过“( )”操作,另一种是在C++中通过类似调用函数的方式进行转换,例如:
`ap_uint<3> i1 = 2;
ap_uint<4> i2= 7;
ap_ufixed<6,4> i3 = i2 / i1;
cout << “The result of i3 :\t” << i3 <<’\n’;
ap_ufixed<6,4> i4 =(ap_ufixed<6,4>) i2 / i1;
cout << “The result of i4 :\t” << i4 <<’\n’;
ap_ufixed<6,4> i5 = ap_ufixed<6,4> (i2 )/ i1;
cout << “The result of i5 :\t” << i5 <<’\n’;`
这里得到的i3为3,而i4和i5为3.5,3.5才是我们要的结果,因此对于显式数据类型的转换,可以(括号数据类型类型)+变量名 和 数据类型+(变量名)来完成转换。
注意:在Vivado Hls 中常用的二进制运算有+,-,*,/ , %这五种。两个数相加,为防止溢出,位宽会增加一位。两个数相乘,最终位宽为两个数位宽之和。我们的原则是,大数据不溢出(否则导致结果错误),小数据不损失(否则导致精度损失)。当我们想要获取变量的数据类型,我们可以使用typeid(变量名),相应的我们需要声明typeinfo.h这个头文件。
总结
本文介绍了数据类型的转化,在Vivado Hls中,我们要根据算法的类型来确定合理的位宽,这对运算的结果至关重要,此外,我们在完成数据转换时,可以采用显式数据转换的两种方式。