Main Content

固定小数点演算の実行

固定小数点演算

加算と減算

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 の組み込み整数データ型のように動作します。

fidouble の間で加算を行うと、double は fi の入力と同じ数値型をもつ fi にキャストされます。演算の結果は fi になります。fidouble の間で乗算を行うと、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
aProductMode プロパティは KeepMSB に設定されていますが、残りの fimath プロパティには既定値が使用されます。

メモ

fimath オブジェクト、そのプロパティおよびこれらの既定値の詳細は、fimath オブジェクト プロパティを参照してください。

ビット成長率

次の表に、fi オブジェクト ABSumMode および ProductMode プロパティに既定の fimathFullPrecision が使用されている場合の、これらのオブジェクトのビット成長率を示します。

 ABSum = A+BProd = A*B
形式fi(vA,s1,w1,f1)fi(vB,s2,w2,f2)
符号s1s2Ssum = (s1||s2)Sproduct = (s1||s2)
整数ビットI1 = w1-f1-s1I2= w2-f2-s2Isum = max(w1-f1, w2-f2) + 1 - SsumIproduct = (w1 + w2) - (f1 + f2)
小数部ビットf1f2Fsum = max(f1, f2) Fproduct = f1 + f2
合計ビットw1w2Ssum + Isum + Fsumw1 + 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) = bb の値を添字ベクトル I で指定された a の要素に代入する一方で、anumerictype を維持します。

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) は、添字ベクトル (:) の値の変更を指示します。しかし、出力 accnumerictype はそのまま維持されます。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

accnumerictypefor ループを反復しても変化しません。

添字を使用した代入は、関数内でビット成長率を抑制する場合にも役立ちます。関数 cumulative_sum では、ynumerictype は変化しませんが、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 種類の方法でオーバーフローを処理できます。OverflowActionsaturate に設定すると、オーバーフローは範囲の最大値または最小値に飽和されます。OverflowActionwrap に設定すると、オーバーフローは、符号なしの場合はモジュロ演算、符号付きの場合は 2 の補数を使用してラップします。

オーバーフローの検出方法の詳細は、fipref を使用したアンダーフローとオーバーフローのログ作成を参照してください。

丸め

丸め手法を選択する場合は、コスト、バイアス、オーバーフローの可能性の有無など、さまざまな要因を考慮する必要があります。Fixed-Point Designer™ ソフトウェアは、設計の要件を満たすさまざまな丸め関数を提供します。

丸め手法 説明コストバイアスオーバーフローの可能性
ceil 正の無限大方向の最も近い表現可能な数値に丸めます。大きい正の数値あり
convergent最も近い表現可能な数値に丸めます。等距離の場合、convergent は最も近い偶数に丸めます。このアプローチはツールボックスで提供される最もバイアスの小さい丸め手法です。バイアスなしあり
floor2 の補数切り捨てに等しく、負の無限大方向の最も近い表現可能な数値に丸めます。大きい負の数値なし
nearest最も近い表現可能な数値に丸めます。等距離の場合、nearest は、正の無限大方向の最も近い表現可能な数値に丸めます。これは fi オブジェクトの作成と fi 算術で既定の丸め手法です。小さい正の数値あり
round

最も近い表現可能な数値に丸めます。等距離の場合、round メソッドは次のように丸めます。

  • 正の数値は、正の無限大方向の最も近い表現可能な数値に丸めます。

  • 負の数値は、負の無限大方向の最も近い表現可能な数値に丸めます。

  • 負のサンプルでは小さい負の数値

  • 正の数値と負の数値が均等に分布するサンプルではバイアスなし

  • 正のサンプルでは小さい正の数値

あり
fixゼロ方向の最も近い表現可能な数値に丸めます。
  • 負のサンプルでは大きい正の数値

  • 正の数値と負の数値が均等に分布するサンプルではバイアスなし

  • 正のサンプルでは大きい負の数値

なし