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) のタイプを選択できます。
  • オーバーフロー動作 (O および N) を選択できます。
図 1. 任意精度固定小数点型
ヒント: 前の図では、整数値 (I) は、符号ビットを含む 2 進数の左側の整数ビット数を示しています。

任意精度の固定小数点型は、C 言語のシミュレーション時や、ap_[u]fixed 型の非常に大きな配列を使用する場合に、より多くのメモリを使用します。

固定小数点型を使用すると、次のような利点があります。

  • 小数を簡単に記述できます。
  • 整数部および小数部のビット数が異なる変数の場合、小数点のアライメントが処理されます。
  • 結果を精度を示すのに小数部ビットが足らない場合など、多くの丸めの実行を処理するオプションがあります。
  • 結果が整数部ビットよりも大きい場合のため、多くの変数のオーバーフローを処理するオプションもあります。

これらの属性は、次のコード例に含まれています。まず、ヘッダー ファイル ap_fixed.h が含まれ、ap_fixed 型が typedef 文により定義されます。

  • 10 ビット入力: 8 ビット整数値 + 2 小数部。
  • 6 ビット入力: 3 ビット整数値 + 3 小数部。
  • 累算用の 22 ビット変数: 22 ビット入力: 17 ビット整数値 + 5 小数部。
  • 結果用の 36 ビット変数: 22 ビット入力: 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 では同じビット精度の動作になります。

任意精度の固定小数点型を使用すると、コードにリテラル値を自由に代入できます。上記の例で使用されたテストベンチに示すように、in1 および in2 の値は宣言済みで、定数値が代入されます (次の例を参照)。

演算子が関係するリテラル値を代入する際は、まずリテラル値を 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;
}