C++ 任意精度定点类型 - 2023.2 简体中文

Vitis 高层次综合用户指南 (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 简体中文
重要: 任意精度定点类型要求代码中包含 ap_fixed.h 头文件。

C++ 函数可利用 Vitis HLS 所含的任意精度定点类型。下图汇总了这些定点类型的基本功能:

  • 字型可采用有符号 (ap_fixed) 或无符号 (ap_ufixed) 类型。
  • 可定义任意大小 W 的字。
  • 小数点 I 前的位数还可定义代码字的小数位数 W-I(在下图中以 B 来表示)。
  • 可选择舍入或量化 (Q) 类型。
  • 可选择上溢行为(ON)。
图 1. 任意精度定点类型
提示: 在上图中,整数值 (I) 指定了二进制小数点左侧的整数位数(包括符号位)。

在使用 ap_[u]fixed 类型的超大阵列时以及在 C 语言仿真期间,任意精度定点类型会占用更多存储器。

使用定点类型的优势包括:

  • 支持轻松显示小数。
  • 当变量包含的整数位数和小数位数不同时,可处理小数点的对齐。
  • 当小数位数太少无法准确表示结果精度时,有多个选项可用于处理舍入方式。
  • 当结果大于可显示的整数位数时,有多个选项可用于处理变量上溢方式。

请查看如下示例中的代码,其中汇总了各项属性。首先,包含 ap_fixed.h 头文件。随后使用 typedef 语句定义 ap_fixed 类型:

  • 10 位输入:8 位整数值和 2 个小数位。
  • 6 位输入:3 位整数值和 3 个小数位。
  • 用于累加的 22 位变量:17 位整数值和 5 个小数位。
  • 用于表示结果的 36 位变量:30 位整数值和 6 个小数位。

函数不含用于管理执行运算后的小数点对齐的代码。对齐自动执行。

以下代码样本显示的类型为 ap_fixed

#include "ap_fixed.h"

typedef ap_ufixed<10,8, AP_RND, AP_SAT> din1_t;
typedef ap_fixed<6,3, AP_RND, AP_WRAP> din2_t;
typedef ap_fixed<22,17, AP_TRN, AP_SAT> dint_t;
typedef ap_fixed<36,30> dout_t;

dout_t cpp_ap_fixed(din1_t d_in1, din2_t d_in2) {

 static dint_t sum;
 sum += d_in1; 
 return sum * d_in2;
}

通过使用 ap_(u)fixed 类型,C++ 仿真可保证位精度。快速仿真可确认算法及其准确性。综合后,RTL 会显示完全相同的位精确行为。

在此代码中可为任意精度定点类型自由赋予字面值。如以上示例中使用的测试激励文件中所示(请参阅以下示例),其中已声明 in1in2 的值,并对其赋予常量值。

赋予含运算符的字面值时,字面值必须首先强制转换为 ap_(u)fixed 类型。否则,C 语言编译器和 Vitis HLS 会将字面值解释为整数或 float/double 类型,并且可能无法找到合适的运算符。如以下示例所示,在 in1 = in1 + din1_t(0.25) 的赋值中,字面值 0.25 强制转换为 ap_fixed 类型。

#include <cmath>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <cstdlib>
using namespace std;
#include "ap_fixed.h"

typedef ap_ufixed<10,8, AP_RND, AP_SAT> din1_t;
typedef ap_fixed<6,3, AP_RND, AP_WRAP> din2_t;
typedef ap_fixed<22,17, AP_TRN, AP_SAT> dint_t;
typedef ap_fixed<36,30> dout_t;

dout_t cpp_ap_fixed(din1_t d_in1, din2_t d_in2);
int main()
 {
 ofstream result;
 din1_t in1 = 0.25;
 din2_t in2 = 2.125;
 dout_t output;
 int retval=0;


 result.open(result.dat);
 // Persistent manipulators
 result << right << fixed << setbase(10) << setprecision(15);

 for (int i = 0; i <= 250; i++)
 {
 output = cpp_ap_fixed(in1,in2);

 result << setw(10) << i;
 result << setw(20) << in1;
 result << setw(20) << in2;
 result << setw(20) << output;
 result << endl;

 in1 = in1 + din1_t(0.25);
 in2 = in2 - din2_t(0.125);
 }
 result.close();

 // Compare the results file with the golden results
 retval = system(diff --brief -w result.dat result.golden.dat);
 if (retval != 0) {
 printf(Test failed  !!!\n); 
 retval=1;
 } else {
 printf(Test passed !\n);
 }

 // Return 0 if the test passes
 return retval;
}