Main Content

固定小数点数学属性の設定

この例では、MATLAB® コードで固定小数点数学属性を設定する方法を説明します。

fimathオブジェクトを使用して、代入、加算、減算、乗算の固定小数点数学属性を制御します。関数setfimathを使用して、fimath オブジェクトをfiオブジェクトに付加します。関数removefimathを使用して、fimath オブジェクトを fi オブジェクトから削除します。

MATLAB Coder™ ソフトウェアを使用して、以下の例から C コードを生成できます。

固定小数点数学属性の設定と削除

関数 user_written_sum は、関数 setfimath および関数 removefimath を使用して固定小数点演算がグローバルおよびローカル fimath 設定の影響を受けないようにする方法の例を示しています。出力変数に fimath が付加されていない関数から返すこともできます。これにより、他の関数の設定に影響を与えずに、固定小数点の数学設定をローカル制御できるようになります。

function y = user_written_sum(u)
    % Setup
    F = fimath('RoundingMethod','Floor',...
        'OverflowAction','Wrap',...
        'SumMode','KeepLSB',...
        'SumWordLength',32);
    u = setfimath(u,F);
    y = fi(0,true,32,get(u,'FractionLength'),F);
    % Algorithm
    for i=1:length(u)
        y(:) = y + u(i);
    end
    % Cleanup
    y = removefimath(y);
end

fimath は関数内の演算を制御しますが、戻り値には fimath が付加されません。これは、関数 user_written_sum 内で setfimathremovefimath を使用するためです。

u = fi(1:10,true,16,11);
y = user_written_sum(u)
y = 
    55

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 11

C コードの生成

MATLAB Coder ライセンスがある場合は、次のコマンドを実行して C コードを生成できます。

u = fi(1:10,true,16,11);
codegen user_written_sum -args {u} -config:lib -launchreport

関数 fimathsetfimath および removefimath は固定小数点演算を制御しますが、変数に格納されている元のデータは変わらないため、生成 C コードではデータのコピーが生成されません。

int user_written_sum(const short u[10])
{
  int i;
  int y;
  y = 0;
  /*  Algorithm */
  for (i = 0; i < 10; i++) {
    y += u[i];
  }
  /*  Cleanup */
  return y;
}

fimath の不一致

複数の fi オブジェクトに対して演算を行う場合、これらの fimath プロパティは等しくなければなりません。そうでないとエラーが発生します。

A = fi(pi,'ProductMode','KeepLSB');
B = fi(2,'ProductMode','SpecifyPrecision');
try
    C = A*B
catch me
    disp(me.message)
end
The embedded.fimath of both operands must be equal.

このエラーが発生しないようにするには、fimath を式の変数のいずれかで削除します。次の例では、fimathB 自体を変更せずに式のコンテキストで B から削除されています。A に付加されている fimath を使って積が計算されています。

C = A * removefimath(B)
C = 
    6.2832

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 26

        RoundingMethod: Nearest
        OverflowAction: Saturate
           ProductMode: KeepLSB
     ProductWordLength: 32
               SumMode: FullPrecision

一時変数での fimath の変更

fimath が付加されていない変数があり、特定の演算を制御する場合、変数を変更せずに式のコンテキストで fimath を付加することができます。

たとえば、F で定義された fimath を使用して積を計算します。

F = fimath('ProductMode','KeepLSB',...
    'OverflowAction','Wrap',...
    'RoundingMethod','Floor');
A = fi(pi);
B = fi(2);
C = A * setfimath(B,F)
C = 
    6.2832

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 26

        RoundingMethod: Floor
        OverflowAction: Wrap
           ProductMode: KeepLSB
     ProductWordLength: 32
               SumMode: FullPrecision

変数 B は変更されていません。

B
B = 
     2

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 13

ループで競合する fimath の削除

負方向の丸めとオーバーフローのラップのある DSP アキュムレータに一致するように積と和を計算し、最も近い正の整数方向への丸めと飽和オーバーフローを出力で使用することができます。fimath の不一致エラーの発生を回避するには、他の変数と計算する場合に fimath を出力変数から削除します。

関数 setfimath_removefimath_in_a_loop では、積は 32 ビット、アキュムレータは 40 ビットであり、C のネイティブな整数ルールと同様に、最下位のビットに負方向への丸めとオーバーフローのラップが維持されています。出力は、最も近い正の整数方向への丸めと飽和オーバーフローを使用します。

function [y,z] = setfimath_removefimath_in_a_loop(b,a,x,zi)
    % Setup
    F_floor = fimath('RoundingMethod','Floor',...
           'OverflowAction','Wrap',...
           'ProductMode','KeepLSB',...
           'ProductWordLength',32,...
           'SumMode','KeepLSB',...
           'SumWordLength',40);
    F_nearest = fimath('RoundingMethod','Nearest',...
        'OverflowAction','Wrap');
    % Set fimaths that are local to this function
    b = setfimath(b,F_floor);
    a = setfimath(a,F_floor);
    x = setfimath(x,F_floor);
    z = setfimath(zi,F_floor);
    % Create y with nearest rounding
    y = setfimath(zeros(size(x),'like',zi),F_nearest);
    % Algorithm
    for j=1:length(x)
        % Nearest assignment into y
        y(j) =  b(1)*x(j) + z(1);
        % Remove y's fimath conflict with other fimaths
        z(1) = (b(2)*x(j) + z(2)) - a(2) * removefimath(y(j));
        z(2) =  b(3)*x(j)         - a(3) * removefimath(y(j));
    end
    % Cleanup: Remove fimath from outputs
    y = removefimath(y);
    z = removefimath(z);
end

C コードの生成

MATLAB Coder ライセンスがある場合は、次のコマンドを実行して、指定のハードウェアの特性を使用して C コードを生成できます。

N = 256;
t = 1:N;
xstep = [ones(N/2,1);-ones(N/2,1)];
num = [0.0299545822080925  0.0599091644161849  0.0299545822080925];
den = [1                  -1.4542435862515900  0.5740619150839550];
b = fi(num,true,16);
a = fi(den,true,16);
x = fi(xstep,true,16,15);
zi = fi(zeros(2,1),true,16,14);
B = coder.Constant(b);
A = coder.Constant(a);
config_obj = coder.config('lib');
config_obj.GenerateReport = true;
config_obj.LaunchReport = true;
config_obj.TargetLang = 'C';
config_obj.DataTypeReplacement = 'CoderTypedefs';
config_obj.GenerateComments = true;
config_obj.GenCodeOnly = true;
config_obj.HardwareImplementation.ProdBitPerChar=8;
config_obj.HardwareImplementation.ProdBitPerShort=16;
config_obj.HardwareImplementation.ProdBitPerInt=32;
config_obj.HardwareImplementation.ProdBitPerLong=40;
codegen -config config_obj setfimath_removefimath_in_a_loop -args {B,A,x,zi}

関数 fimathsetfimath および removefimath は固定小数点演算を制御しますが、変数に格納されている元のデータは変わらないため、生成 C コードではデータのコピーが生成されません。

void setfimath_removefimath_in_a_loop(const int16_T x[256], const int16_T zi[2],
                                      int16_T y[256], int16_T z[2])
{
  int32_T j;
  int16_T i;
  int16_T i1;
  /*  Set fimaths that are local to this function */
  /*  Create y with nearest rounding */
  /*  Algorithm */
  i = zi[0];
  i1 = zi[1];
  for (j = 0; j < 256; j++) {
    int64_T i3;
    int32_T y_tmp;
    int16_T i2;
    int16_T i4;
    /*  Nearest assignment into y */
    i2 = x[j];
    y_tmp = 15705 * i2;
    i3 = y_tmp + ((int64_T)i << 20);
    i4 = (int16_T)((i3 >> 20) + ((i3 & 524288L) != 0L));
    y[j] = i4;
    /*  Remove y's fimath conflict with other fimaths */
    i = (int16_T)(((31410 * i2 + ((int64_T)i1 << 20)) -
                   ((int64_T)(-23826 * i4) << 6)) >>
                  20);
    i1 = (int16_T)((y_tmp - ((int64_T)(9405 * i4) << 6)) >> 20);
  }
  z[1] = i1;
  z[0] = i;
  /*  Cleanup: Remove fimath from outputs */
}

ポリモーフィック コード

関数 setfimath と関数 removefimath を使って、浮動小数点と固定小数点の両方の型で使用できる MATLAB コードを記述できます。

function y = user_written_function(u)
    % Setup
    F = fimath('RoundingMethod','Floor',...
        'OverflowAction','Wrap',...
        'SumMode','KeepLSB',...
        'SumWordLength',32);
    u = setfimath(u,F);
    % Algorithm
    y = u + u;
    % Cleanup
    y = removefimath(y);
end

固定小数点入力

関数が固定小数点入力で呼び出されて fimath F が演算に使用される場合、出力には fimath が付加されません。

u = fi(pi/8,true,16,15,'RoundingMethod','Convergent');
y = user_written_function(u)
y = 
    0.7854

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 15

MATLAB Coder ライセンスがある場合は、次のコマンドを実行して C コードを生成できます。

u = fi(pi/8,true,16,15,'RoundingMethod','Convergent');
codegen user_written_function -args {u} -config:lib -launchreport

関数 fimathsetfimath および removefimath は固定小数点演算を制御しますが、変数に格納されている元のデータは変わらないため、生成 C コードではデータのコピーが生成されません。

int user_written_function(short u)
{
  /*  Algorithm */
  return u + u;
  /*  Cleanup */
}

浮動小数点 double 入力

関数 setfimath と関数 removefimath は浮動小数点型にはパススルーであるため、user_written_function の例は浮動小数点型で機能します。

u = double(pi/8);
codegen user_written_function -args {0} -config:lib -launchreport

浮動小数点入力でコンパイルするとき、次の C コードが生成されます。

double user_written_function(double u)
{
  /*  Algorithm */
  return u + u;
  /*  Cleanup */
}

ポリモーフィック コードの詳細

関数 user_written_sum_polymorphic は、出力が入力と同じ型で作成されるように記述されています。関数 user_written_sum_polymorphic では浮動小数点と固定小数点の両方の入力を使用できます。

function y = user_written_sum_polymorphic(u)
    % Setup
    F = fimath('RoundingMethod','Floor',...
        'OverflowAction','Wrap',...
        'SumMode','KeepLSB',...
        'SumWordLength',32);
     u = setfimath(u,F);
     if isfi(u)
         y = fi(0,true,32,get(u,'FractionLength'),F);
     else
         y = zeros(1,1,class(u));
     end
     % Algorithm
     for i=1:length(u)
         y(:) = y + u(i);
     end
     % Cleanup
     y = removefimath(y);
end

固定小数点 C コードの生成

MATLAB Coder ライセンスがある場合は、次のコマンドを実行して C コードを生成できます。

u = fi(1:10,true,16,11);
codegen user_written_sum_polymorphic -args {u} -config:lib -launchreport

関数 fimathsetfimath および removefimath は固定小数点演算を制御しますが、変数に格納されている元のデータは変わらないため、生成 C コードではデータのコピーが生成されません。

int user_written_sum_polymorphic(const short u[10])
{
  int i;
  int y;
  y = 0;
  /*  Algorithm */
  for (i = 0; i < 10; i++) {
    y += u[i];
  }
  /*  Cleanup */
  return y;
}

浮動小数点 C コードの生成

MATLAB Coder ライセンスがある場合は、次のコマンドを実行して C コードを生成できます。

u = 1:10;
codegen user_written_sum_polymorphic -args {u} -config:lib -launchreport
double user_written_sum_polymorphic(const double u[10])
{
  double y;
  int i;
  y = 0.0;
  /*  Algorithm */
  for (i = 0; i < 10; i++) {
    y += u[i];
  }
  /*  Cleanup */
  return y;
}

整数型の setfimath

fi オブジェクトのような組み込み整数の確立した処理パターンに従って、setfimathfimath が付加された同等の fi に整数入力を変換します。

function y = user_written_u_plus_u(u)
    % Setup
    F = fimath('RoundingMethod','Floor',...
        'OverflowAction','Wrap',...
        'SumMode','KeepLSB',...
        'SumWordLength',32);
    u = setfimath(u,F);
    % Algorithm
    y = u + u;
    % Cleanup
    y = removefimath(y);
end

MATLAB Coder ライセンスがある場合は、次のコマンドを実行して C コードを生成できます。

u = int8(5);
codegen user_written_u_plus_u -args {u} -config:lib -launchreport

出力型は、fimath で 32 ビットと指定されています。

int user_written_u_plus_u(signed char u)
{
  /*  Algorithm */
  return u + u;
  /*  Cleanup */
}

エディターの警告を無効にします。

 %#ok<*NASGU>

参考

| | |

関連するトピック