float および double 型 - 2023.2 日本語

Vitis 高位合成ユーザー ガイド (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 日本語

Vitis HLS では、合成で float 型および double 型がサポートされます。どちらのデータ型も IEEE-754 規格に部分的に準拠して合成されます ( 『Floating-Point Operator LogiCORE IP 製品ガイド』 (PG060) を参照)。

  • 単精度 32 ビット
    • 仮数部 24 ビット
    • 指数部 8 ビット
  • 倍精度 64 ビット
    • 仮数部 53 ビット
    • 指数部 11 ビット

float 型および double 型は、標準演算 (+、-、* など) だけでなく、math.h (C++ の場合は cmath.h) にもよく使用されます。このセクションでは、標準演算のサポートについて説明されます。

次に、標準データ型 で使用されたヘッダー ファイルに double 型および float 型を定義したコード例を示します。

#include <stdio.h>
#include <stdint.h>
#include <math.h>

#define N 9

typedef double din_A;
typedef double din_B;
typedef double din_C;
typedef float din_D;

typedef double dout_1;
typedef double dout_2;
typedef double dout_3;
typedef float dout_4;

void types_float_double(din_A inA,din_B inB,din_C inC,din_D inD,dout_1 
*out1,dout_2 *out2,dout_3 *out3,dout_4 *out4);

このアップデートされたヘッダー ファイルは、sqrtf() 関数が使用される次のコード例で使用します。

#include "types_float_double.h"

void types_float_double(
 din_A  inA,
 din_B  inB,
 din_C  inC,
 din_D  inD,
 dout_1 *out1,
 dout_2 *out2,
 dout_3 *out3,
 dout_4 *out4
 ) {

 // Basic arithmetic & math.h sqrtf() 
 *out1 = inA * inB;
 *out2 = inB + inA;
 *out3 = inC / inA;
 *out4 = sqrtf(inD);

}

上記の例を合成すると、64 ビットの倍精度乗算、加算、除算演算子が作成前述の例されます。これらの演算子は、適切な浮動小数点のAMD IP カタログ コアでインプリメントされます。

sqrtf() を使用する平方根は、32 ビットの単精度浮動小数点コアを使用してインプリメントされます。

倍精度の平方根関数 sqrt() が使用されると、inD で使用される 32 ビットの単精度浮動単型の型変換のためにロジックが追加されます。sqrtf() は単精度 (float) 関数ですが、out4: sqrt() は倍精度 (double) 関数です。

C 関数では、float-to-double および double-to-float 変換ユニットがハードウェアで推論されるので、float 型と double 型を混合する場合には注意が必要です。

float foo_f    = 3.1459;
float var_f = sqrt(foo_f); 

上記のコードは、次のようなハードウェアになります。

wire(foo_t)
-> Float-to-Double Converter unit
-> Double-Precision Square Root unit
-> Double-to-Float Converter unit
-> wire (var_f)

sqrtf() 関数を使用すると、次のようになります。

  • ハードウェアで型コンバーターが不要になる。
  • エリアが節約される。
  • タイミングが改善される。

float および double 型を合成する際には、Vitis HLS が C コードで実行される演算順序を維持して、C シミュレーションと結果が同じになるようにします。飽和および切り捨てのため、次は単精度および倍精度演算で必ずしも同じになるわけではありません。

       A=B*C; A=B*F;
       D=E*F; D=E*C;
       O1=A*D O2=A*D;

float および double 型を使用する場合、O1O2 は必ずしも同じになるわけではありません。

ヒント: Vitis HLS では float 型および double 型を合成する際に演算順序が厳しく守られるため、デザインによってはループの展開や部分展開などの最適化による並列計算の利点を活かすことができない場合もあります。この制限は、config_compile -unsafe_math_optimizations を使用して無効にできます。

C++ デザインの場合は、Vitis HLS の最もよく使用される数学関数のビットを概算する機能を使用できます。

浮動小数点アキュムレータおよび MAC

浮動小数点アキュムレータ (facc)、積和 (fmacc)、および乗加算 (fmadd) は、次のように syn.op コンフィギュレーション コマンドを使用してイネーブルにできます (演算子のコンフィギュレーション を参照)。次に例を示します。

syn.op=op:mul impl:dsp
syn.op=op:add impl:fabric latency:6
syn.op=op:fmacc precision:high
syn.op=op:hdiv latency:5

ツールでは、これらの演算に対して、Versal デバイスと Versal 以外のデバイスの両方でパフォーマンス、エリア、精度をトレードオフするさまざまな精度レベルがサポートされています。

  • low 精度の累積は、高スループットの低精度浮動小数点の累積および積和に適しており、Versal 以外のデバイスでのみ使用できます。
    • プリスケーラとポストスケーラを備えた整数アキュムレータを使用します (入力と出力を単精度または倍精度浮動小数点に変換します)。
      • これは、単精度入力と倍精度入力にそれぞれ 60 ビットおよび 100 ビット アキュムレータを使用します。
      • C++ シミュレーションの精度が不十分なため、協調シミュレーションと一致しないことがあります。
    • ソース コードを変更せずに、常に II=1 でパイプライン処理できます。
    • standard 精度の浮動小数点の累積の約 3 倍のリソースを使用し、クロック周波数とターゲット デバイスによって、通常 3 ~ 5 の II を達成します。
    low 精度を使用した場合、float 型および double 型の累積は、すべてのデバイスで開始間隔 (II) 1 でサポートされます。これは、次のコードに記述を追加しなくても、II は 1 でパイプライン処理できるということです。
    float foo(float A[10], float B[10]) {
     float sum = 0.0;
     for (int i = 0; i < 10; i++) {
     sum += A[i] * B[i];
     }
     return sum;
    }
  • standard 精度の累積と積和は、ほとんどの浮動小数点演算に適しており、Versal でも Versal 以外のデバイスでも使用できます。
    • 常に真の浮動小数点アキュムレータを使用します。
    • Versal デバイスの場合は、II =1 のパイプライン処理ができます。
    • Versal 以外のデバイスでは、通常 3 ~ 5 (クロック周波数とターゲット デバイスによって異なる) の II でパイプライン処理できます。standard 精度モードは、Versal 以外のデバイスよりも Versal デバイス上での方が効率的です。
  • high 精度の融合型積和は、高精度のアプリケーションに適しており、Versal デバイスで使用できます。
    • 1 ビット余分な精度を使用します。
    • 常に単一の融合型積和を使用し、最後に 1 つの丸めを実行しますが、非融合型の積和よりも多くのリソースを使用します。
    • C++ シミュレーションの精度が余分なため、協調シミュレーションと一致しないことがあります。