bambooflow Note

固定小数点

最終更新:

bambooflow

- view
メンバー限定 登録/ログイン

SytemCで固定小数点

固定小数点の使い方についてメモしておく。
忘れっぽいので。。。

IEEE1666のLRMを見るとグラフつきでわかりやすいかも。



種類


  • 符号付固定小数点
  • 符号なし固定小数点

よく使うのは、sc_fixed、sc_ufixedの2つだけ。
他はあまり使わない。。。

  • 高速版、符号付固定小数点
  • 高速版、符号なし固定小数点

高速版は、32ビットOSにおいて、途中の計算を53ビットに制限して(double)高速化を実現しているらしい。
精度は落ちるかもしれないので、よく検討するべし。


  • 動的サイズ:符号付固定小数点
  • 動的サイズ:符号なし固定小数点

  • 動的サイズ、高速版:符号付固定小数点
  • 動的サイズ、高速版:符号なし固定小数点

sc_fixed(テンプレート型)とsc_fix(テンプレート型)の違いがある。


テンプレート・パラメータ


パラメータ 値の型 説明
W int(正の値) 全体のビット幅(ワード長)
I int 整数部のビット幅、正負の値が指定できる
Q sc_q_mode 量子化モード(省略可)
O sc_o_mode オーバーフローモード(省略可)
N int オーバーフロー用ビット数(省略可、Oのためのオプション)


量子化モード(誤差)

第3番目のパラメータで丸め方向を決めることができる。

SC_RND 正の無限方向への丸め
SC_RND_ZERO ゼロ方向への丸め
SC_RND_MIN_INF 負の無限方向への丸め
SC_RND_INF 無限方向への丸め
SC_RND_CONV 収束丸め
SC_TRN(デフォルト) 切捨て
SC_TRN_ZERO ゼロ方向へ切捨て

SC_RND

  • 正の方向への丸め (rounding to plus infinity)

例)
y = sc_fixed<3,2,SC_RND>(x); 
代入前[ x ] 代入後[ y ]
-側 0b10.11 (-1.25) 0b11.0 (-1.0)
+側 0b01.01 ( 1.25) 0b01.1 ( 1.5)

LSB-1番目のビットが、1ならば上へ、0ならば下へ。

SC_RND_ZERO

  • ゼロ方向への丸め (rounding to zero)

例)
y = sc_fixed<3,2,SC_RND_ZERO>(x); 
代入前[ x ] 代入後[ y ]
-側 0b10.11 (-1.25) 0b11.0 (-1.0)
+側 0b01.01 ( 1.25) 0b01.0 ( 1.0)

SC_RND_MIN_INF

  • マイナス方向への丸め (rounding to minus infinity)

例)
y = sc_fixed<3,2,SC_RND_MIN_ZERO>(x); 
代入前[ x ] 代入後[ y ]
-側 0b10.11 (-1.25) 0b10.1 (-1.5)
+側 0b01.01 ( 1.25) 0b01.0 ( 1.0)

SC_RND_INF

  • 無限方向への丸め (rounding to infinity)

例)
y = sc_fixed<3,2,SC_RND_ZERO>(x); 
代入前[ x ] 代入後[ y ]
-側 0b10.11 (-1.25) 0b10.1 (-1.5)
+側 0b01.01 ( 1.25) 0b01.1 ( 1.5)

SC_RND_CONV

  • 収束丸め (convergent rounding)

例)
y = sc_fixed<3,2,SC_RND_CONV>(x); 
代入前[ x ] 代入後[ y ]
-側 0b10.11 (-1.25) 0b11.0 (-1.0)
+側 0b01.01 ( 1.25) 0b01.0 ( 1.0)

0b10.11(-1.25) <= x <= 0b11.01(-0.75) y = 0b11.0(-1.0)
0b11.10(-0.75) < x < 0b11.11(-0.25) y = 0b11.1(-0.5)
0b11.10(-0.25) <= x <= 0b00.01( 0.25) y = 0b00.0( 0.0)
0b00.01( 0.25) < x < 0b00.11( 0.75) y = 0b00.0( 0.5)
0b00.11( 0.75) <= x <= 0b01.01( 1.25) y = 0b01.0( 1.0)

(<=,<=)と(<,<)とが交互。奇数と偶数とで異なる。
Convergent Roundingは特定の用途に用いられるらしい。

SC_TRN (デフォルト)

  • 切捨て (truncation)

例)
y = sc_fixed<3,2,SC_TRN>(x); 
代入前[ x ] 代入後[ y ]
-側 0b10.11 (-1.25) 0b10.1 (-1.5)
+側 0b01.01 ( 1.25) 0b01.0 ( 1.0)

これは、デフォルト。
計算は切捨てなので高速だが、精度が出ない。
精度をあげるならば、SC_RNDを使う。

SC_TRN_ZERO

  • ゼロ方向へ切捨て (truncation to zero)

例)
y = sc_fixed<3,2,SC_TRN_ZERO>(x); 
代入前[ x ] 代入後[ y ]
-側 0b10.11 (-1.25) 0b11.0 (-1.0)
+側 0b01.01 ( 1.25) 0b01.0 ( 1.0)


オーバーフローモード

オーバーフローを起こした場合、4番目と5番目のパラメータにより調整することができる。
種類は、飽和もしくは折り返しがある。

SC_SAT 単純飽和
SC_SAT_SYM 対称飽和
SC_SAT_ZERO ゼロ飽和
SC_WRAP(デフォルト) 折り返し
SC_WRAP_SM sign magnitude折り返し


単純飽和は、最大値を超えたら最大値まで減少、最小値を下回ったら最小値まで増加させる。
対称飽和は、最大値側は単純飽和とおなじ。最小値を下回ったら"-最大値"まで増加させる。
ゼロ飽和は、オーバーフローを起こしたら、値をゼロにする。

折り返しは、収まらない上位ビットを削除。
パラメータNでを使用する。


SC_SAT

  • 単純飽和

例)
y = sc_fixed<3,3,SC_SAT>(x)
代入前[ x ] 代入後[ y ] 備考
-側 -6 -4 オーバーフロー
-5 -4 オーバーフロー
-4 -4
-3 -3
-2 -2
-1 -1
0 0
1 1
2 2
3 3
4 3 オーバーフロー
+側 5 3 オーバーフロー

上限よりも下限の飽和する絶対値は異なることに注意。


SC_SAT_ZERO

  • ゼロ飽和

例)
y = sc_fixed<3,3,SC_SAT_ZERO>(x)
代入前[ x ] 代入後[ y ] 備考
-側 -6 0 オーバーフロー
-5 0 オーバーフロー
-4 -4
-3 -3
-2 -2
-1 -1
0 0
1 1
2 2
3 3
4 0 オーバーフロー
+側 5 0 オーバーフロー

オーバーフローすると、ゼロ値となる。


SC_SAT_SYM

  • 対称飽和

例)
y = sc_fixed<3,3,SC_SAT_SYM>(x)
代入前[ x ] 代入後[ y ] 備考
-側 -6 -3 オーバーフロー
-5 -3 オーバーフロー
-4 -3 オーバーフロー
-3 -3
-2 -2
-1 -1
0 0
1 1
2 2
3 3
4 3 オーバーフロー
+側 5 3 オーバーフロー

-側のオーバーフロー値は、+側の絶対値と同じとなる。


SC_WRAP (デフォルト)

ラップアラウンド。~

  • n_bit=0
  • n_bit>0


SC_WRAP_SM

符号つき絶対値ラップアラウンド

  • n_bits=0
  • n_bits>0


固定小数点のコンパイル


SC_INCLUDE_FXをsystemc.hをインクルードする前に定義する必要がある。
これがないと、コンパイルが通らずエラーとなる。

#define SC_INCLUDE_FX
#include "systemc.h"

もしくは、コンパイル時に"-D"で指定する。

-DSC_INCLUDE_FX

関連
SC_FX_EXCLUDE_OTHER


使い方例


オーバーフロー有無の確認



sc_fixed<4,4>  a(1.0); // ワード長4ビット,整数4ビット
 sc_fixed<4,4>  b(1.0);
 sc_fixed<4,4>  c(8.0);
 sc_fixed<4,4>  d(8.0);
 sc_fixed<4,4>  z;
 
 cout << "o_flag = " << z.overflow_flag() << endl;
 
 z = a * b;  // 1.0 x 1.0 => 1.0 : オーバーフローなし
 
 cout << "z = " << z << endl;
 cout << "o_flag = " << z.overflow_flag() << endl;
 
 z = c * d;  // 8.0 x 8.0 => 64.0 : オーバーフロー発生
 
 cout << "z = " << z << endl;
 cout << "o_flag = " << z.overflow_flag() << endl;
 

  • 結果
o_flag = 0
z = 1
o_flag = 0
z = 0
o_flag = 1                <= オーバーフロー発生を確認


固定小数点<==>sc_uint変換


よさそうな方法が思いつかないので、とりあえず。

  • sc_fixed<> ==> sc_uint<>変換
sc_fixed<4,2>  1(1.25);     // 1.25 (0b01.01)
sc_uint<4>     x, y;
 
x = a;                      // 1.00 (0b00001), 整数部のみを代入
 
y = a.range( a.wl()-1, 0 ); // 5 (0b00101), ビット列を単純代入
 

  • sc_uint<> ==> sc_fixed<>変換
sc_uint<4>     a(5);        // 5 (0b00101)
sc_fixed<6,4>  x;
sc_fixed<4,2>  y;
 
x = a;                      // 5.00 (0b0101.00), 整数として代入
 
y.range( y.wl()-1, 0 ) = a; // 1.25 (0b01.01), ビット列を単純代入
 
記事メニュー
目安箱バナー