固定小数点演算の実行
固定小数点演算
加算と減算
2 つの固定小数点数を加算するときは、結果を正確に表すためにキャリー ビットが必要となる場合があります。このため、2 つの B ビット数 (同じスケーリングをもつ) を加算すると、結果の値は、使用される 2 つのオペランドと比べてビットが多くなります。
a = fi(0.234375,0,4,6); c = a+a
c =
0.4688
DataTypeMode: Fixed-point: binary point scaling
Signedness: Unsigned
WordLength: 5
FractionLength: 6a.bin
ans = 1111
c.bin
ans = 11110
精度が異なる 2 つの数値を加算または減算する場合は、最初に基数点を揃えてから演算を行う必要があります。その結果、演算結果とオペランドではビット数が 2 以上異なることになります。
a = fi(pi,1,16,13); b = fi(0.1,1,12,14); c = a + b
c =
3.2416
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 18
FractionLength: 14乗算
一般に、完全精度の積には、オペランドの語長の合計と同じ語長が必要です。以下の例では、積 c の語長は、a の語長に b の語長を加算した長さと等しいことに注意してください。c の小数部の長さも、a の小数部の長さに b の小数部の長さを加算した長さと等しくなります。
a = fi(pi,1,20), b = fi(exp(1),1,16)
a =
3.1416
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 20
FractionLength: 17
b =
2.7183
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 16
FractionLength: 13c = a*b
c =
8.5397
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 36
FractionLength: 30他の組み込みデータ型を使用した計算
C では、整数データ型と double データ型の間での演算の結果は double に変換されることに注意してください。ただし、MATLAB® では、組み込み整数データ型と double データ型の間の演算の結果は、整数になります。この点で、fi オブジェクトは MATLAB の組み込み整数データ型のように動作します。
fi と double の間で加算を行うと、double は fi の入力と同じ数値型をもつ fi にキャストされます。演算の結果は fi になります。fi と double の間で乗算を行うと、double は、fi と同じ語長と符号属性および最高精度の小数部の長さをもつ fi にキャストされます。演算の結果は fi になります。
a = fi(pi);
a =
3.1416
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 16
FractionLength: 13b = 0.5 * a
b =
1.5708
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 32
FractionLength: 28fi と組み込み整数データ型 [u]int[8, 16, 32] のうちの 1 つとの間で演算を行うと、整数の語長と符号属性が保持されます。演算の結果は fi になります。
a = fi(pi); b = int8(2) * a
b =
6.2832
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 24
FractionLength: 13fi と論理データ型の間で演算を行うと、論理値は値が 0 または 1 で語長 1 の符号なし fi オブジェクトとして処理されます。演算の結果は fi オブジェクトになります。
a = fi(pi); b = logical(1); c = a*b
c =
3.1416
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 17
FractionLength: 13fimath オブジェクト
fimath プロパティは、fi オブジェクトに数式、丸めおよびオーバーフロー プロパティを含む算術演算を実行するためのルールを定義します。fi オブジェクトはローカルな fimath オブジェクトをもつことも、既定の fimath プロパティを使用することもあります。setfimath を使用すると、fimath オブジェクトを fi オブジェクトに添付できます。また、作成時に fi コンストラクターで fimath プロパティを指定できます。fi オブジェクトがローカルな fimath をもち、既定のプロパティを使用しない場合は、fi オブジェクトの画面に fimath プロパティが表示されます。この例では、a に、コンストラクターで指定された ProductMode プロパティがあります。
a = fi(5,1,16,4,'ProductMode','KeepMSB')
a =
5
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 16
FractionLength: 4
RoundingMethod: Nearest
OverflowAction: Saturate
ProductMode: KeepMSB
ProductWordLength: 32
SumMode: FullPrecisiona の ProductMode プロパティは KeepMSB に設定されていますが、残りの fimath プロパティには既定値が使用されます。メモ
fimath オブジェクト、そのプロパティおよびこれらの既定値の詳細は、fimath オブジェクト プロパティを参照してください。
ビット成長率
次の表に、fi オブジェクト A とB の SumMode および ProductMode プロパティに既定の fimath 値 FullPrecision が使用されている場合の、これらのオブジェクトのビット成長率を示します。
| A | B | Sum = A+B | Prod = A*B | |
|---|---|---|---|---|
| 形式 | fi(vA,s1,w1,f1) | fi(vB,s2,w2,f2) | — | — |
| 符号 | s1 | s2 | Ssum = (s1||s2) | Sproduct = (s1||s2) |
| 整数ビット | I1 = w1-f1-s1 | I2= w2-f2-s2 | Isum = max(w1-f1, w2-f2) + 1 - Ssum | Iproduct = (w1 + w2) - (f1 + f2) |
| 小数部ビット | f1 | f2 | Fsum = max(f1, f2) | Fproduct = f1 + f2 |
| 合計ビット | w1 | w2 | Ssum + Isum + Fsum | w1 + w2 |
次の例では、for ループでビット成長が発生する仕組みを示します。
T.acc = fi([],1,32,0); T.x = fi([],1,16,0); x = cast(1:3,'like',T.x); acc = zeros(1,1,'like',T.acc); for n = 1:length(x) acc = acc + x(n) end
acc =
1
s33,0
acc =
3
s34,0
acc =
6
s35,0acc の語長が増加します。この増加によって、2 つの問題が生じます。1 つは、コード生成ではループ内のデータ型を変更できないことです。もう 1 つは、ループが長い場合に MATLAB がメモリ不足になることです。この問題を回避する手法については、ビット成長率の抑制を参照してください。ビット成長率の抑制
fimath の使用
fi オブジェクトの fimath プロパティを指定することで、このオブジェクトにおける演算実行時のビット成長率を抑制できます。
F = fimath('SumMode', 'SpecifyPrecision', 'SumWordLength', 8,... 'SumFractionLength', 0); a = fi(8,1,8,0, F); b = fi(3, 1, 8, 0); c = a+b
c =
11
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 8
FractionLength: 0
RoundingMethod: Nearest
OverflowAction: Saturate
ProductMode: FullPrecision
SumMode: SpecifyPrecision
SumWordLength: 8
SumFractionLength: 0
CastBeforeSum: truefi オブジェクトの a はローカルな fimath オブジェクト F をもっています。F は合計の語長と小数部の長さを指定します。既定の fimath 設定では、出力 c は一般に語長が 9、小数部の長さが 0 になります。ただし、a はローカルな fimath オブジェクトをもつため、作成される fi オブジェクトは語長が 8、小数部の長さが 0 になります。
fimath プロパティを使用しても、for ループのビット成長率を抑制できます。
F = fimath('SumMode', 'SpecifyPrecision','SumWordLength',32,... 'SumFractionLength',0); T.acc = fi([],1,32,0,F); T.x = fi([],1,16,0); x = cast(1:3,'like',T.x); acc = zeros(1,1,'like',T.acc); for n = 1:length(x) acc = acc + x(n) end
acc =
1
s32,0
acc =
3
s32,0
acc =
6
s32,0T.acc が既定の fimath プロパティを使用していた場合と異なり、acc のビット成長率は制限されるようになります。そのため、acc の語長は 32 のままです。
添字を使用した代入
ビット成長率を制御するもう 1 つの方法は、添字を使用した代入を使用することです。a(I) = b は b の値を添字ベクトル I で指定された a の要素に代入する一方で、a の numerictype を維持します。
T.acc = fi([],1,32,0); T.x = fi([],1,16,0); x = cast(1:3,'like',T.x); acc = zeros(1,1,'like',T.acc); % Assign in to acc without changing its type for n = 1:length(x) acc(:) = acc + x(n) end
acc (:) = acc + x(n) は、添字ベクトル (:) の値の変更を指示します。しかし、出力 acc の numerictype はそのまま維持されます。acc はスカラーであるため、添字ベクトルとして (1) を使用している場合も受け取る出力は同じです。
for n = 1:numel(x) acc(1) = acc + x(n); end
acc =
1
s32,0
acc =
3
s32,0
acc =
6
s32,0acc の numerictype は for ループを反復しても変化しません。
添字を使用した代入は、関数内でビット成長率を抑制する場合にも役立ちます。関数 cumulative_sum では、y の numerictype は変化しませんが、n で指定された要素の値は変化します。
function y = cumulative_sum(x) % CUMULATIVE_SUM Cumulative sum of elements % of a vector. % % For vectors, Y = cumulative_sum(X) is a % vector containing the cumulative sum of % the elements of X. The type of Y is the type of X. y = zeros(size(x),'like',x); y(1) = x(1); for n = 2:length(x) y(n) = y(n-1) + x(n); end end
y = cumulative_sum(fi([1:10],1,8,0))
y =
1 3 6 10 15 21 28 36 45 55
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 8
FractionLength: 0メモ
添字を使用した代入の詳細は、関数 subsasgn の説明を参照してください。
accumpos および accumneg
ビット成長率を抑制するもう 1 つの方法は、関数 accumpos および accumneg による加算および減算演算の実行です。添字を使用した代入と同様に、accumpos および accumneg では入力した fi オブジェクトの 1 つのデータ型を維持すると同時に、入力値の丸め手法とオーバーフロー アクションを指定できます。
accumpos および accumneg の実装方法の詳細は、生成コードでのマルチワード処理の回避を参照してください。
オーバーフローと丸め
固定小数点の算術演算を実行する場合は、オーバーフローの可能性と影響について検討してください。fimath オブジェクトは、算術演算処理を実行するときに使用されるオーバーフロー モードおよび丸めモードを指定します。
オーバーフロー
演算結果が表現可能な最小値または最大値を超えると、オーバーフローが発生することがあります。fimath オブジェクトには OverflowAction プロパティがあり、飽和とラップという 2 種類の方法でオーバーフローを処理できます。OverflowAction を saturate に設定すると、オーバーフローは範囲の最大値または最小値に飽和されます。OverflowAction を wrap に設定すると、オーバーフローは、符号なしの場合はモジュロ演算、符号付きの場合は 2 の補数を使用してラップします。
オーバーフローの検出方法の詳細は、fipref を使用したアンダーフローとオーバーフローのログ作成を参照してください。
丸め
丸め手法を選択する場合は、コスト、バイアス、オーバーフローの可能性の有無など、さまざまな要因を考慮する必要があります。Fixed-Point Designer™ ソフトウェアは、設計の要件を満たすさまざまな丸め関数を提供します。
| 丸め手法 | 説明 | コスト | バイアス | オーバーフローの可能性 |
|---|---|---|---|---|
ceil | 正の無限大方向の最も近い表現可能な数値に丸めます。 | 低 | 大きい正の数値 | あり |
convergent | 最も近い表現可能な数値に丸めます。等距離の場合、convergent は最も近い偶数に丸めます。このアプローチはツールボックスで提供される最もバイアスの小さい丸め手法です。 | 高 | バイアスなし | あり |
floor | 2 の補数切り捨てに等しく、負の無限大方向の最も近い表現可能な数値に丸めます。 | 低 | 大きい負の数値 | なし |
nearest | 最も近い表現可能な数値に丸めます。等距離の場合、nearest は、正の無限大方向の最も近い表現可能な数値に丸めます。これは fi オブジェクトの作成と fi 算術で既定の丸め手法です。 | 中 | 小さい正の数値 | あり |
round | 最も近い表現可能な数値に丸めます。等距離の場合、
| 高 |
| あり |
fix | ゼロ方向の最も近い表現可能な数値に丸めます。 | 低 |
| なし |