固定小数点演算の実行
固定小数点演算
加算と減算
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: 6
a.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: 13
c = 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: 13
b = 0.5 * a
b = 1.5708 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 28
fi
と組み込み整数データ型 [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: 13
fi
と論理データ型の間で演算を行うと、論理値は値が 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: 13
fimath オブジェクト
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: FullPrecision
a
の 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,0
acc
の語長が増加します。この増加によって、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: true
fi
オブジェクトの 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,0
T.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,0
acc
の 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 | ゼロ方向の最も近い表現可能な数値に丸めます。 | 低 |
| なし |