Main Content

ルックアップ テーブルのデータの正規化

この例では、ルックアップ テーブルで使用されるデータを正規化する方法を説明します。

ルックアップ テーブルを使用すると、固定小数点の組み込みデバイス向けに大規模な計算を行う関数を、非常に効率よく作成できます。たとえば、ルックアップ テーブルを使用して、対数、正弦、余弦、正接、平方根を効率的に実装できます。入力をこれらの関数に正規化して小さいルックアップ テーブルを生成してから、出力を正規化係数でスケーリングします。この例では、ルックアップ テーブルを使用した固定小数点平方根の実装ルックアップ テーブルを使用した固定小数点 Log2 の実装の例で使用される正規化関数を実装する方法を説明します。

設定

この例で基本設定または設定が変更されないように、次のコードで元の状態を保存します。

originalFormat = get(0,'format'); format long g
originalWarningState = warning('off','fixed:fi:underflow');
originalFiprefState = get(fipref); reset(fipref)

例の最後で、この状態に戻します。

以下に定義する正規化関数 fi_normalize_unsigned_8_bit_byte を使用して、u のデータを正規化します。

u = fi(0.3,1,16,8);

2 進数では、u = 00000000.01001101_2 = 0.30078125 となります (8 ビットに丸められたため、固定小数点値は厳密には 0.3 ではありません)。ここでの目的は、次のように正規化することです。

u = 1.001101000000000_2 * 2^(-2) = x * 2^n.

符号なし整数を表す u で開始します。

High byte Low byte

00000000 01001101 開始: u は符号なし整数。

上位バイトは 0 = 00000000_2 です。1 を追加して、index = 0 + 1 = 1 のようにインデックスを作成します。最上位ビットから 0 が連続する数のルックアップ テーブルのインデックス 1 では、NLZLUT(1) = 8 のように、最上位ビットから連続する 0 が 8 つあることが示されます。このビットの数だけ左にシフトします。

High byte Low byte

01001101 00000000 8 ビット左にシフトする。

再度反復を行い、最上位ビットから連続する 0 をその次のバイトから削除します。

上位バイトは 77 = 01001101_2 です。1 を追加して、index = 77 + 1 = 78 のようにインデックスを作成します。最上位ビットから 0 が連続する数のルックアップ テーブルのインデックス 78 では、NLZLUT(78) = 1 のように、最上位ビットから連続する 0 が 1 つあることが示されます。このビットの数だけ左にシフトします。

High byte Low byte

100110100 0000000 もう 1 ビット左にシフト (合計 9 ビット)。

これらのビットを小数部が 15 ビットの符号なしの固定小数点として再解釈します。

x = 1.001101000000000_2 = 1.203125

n の値は、u の語長から u の小数部の長さと左シフトの数と 1 を差し引きます。

n = 16-8-9-1 = -2

最終的な結果は、次のようになります。

[x,n] = fi_normalize_unsigned_8_bit_byte(u)
x = 
                  1.203125

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Unsigned
            WordLength: 16
        FractionLength: 15
n = int8
   -2

2 進数の値を比較してみると、x には u と同じ数のビットがあり、9 ビットだけ左にシフトされていることがわかります。

binary_representation_of_u = bin(u)
binary_representation_of_u = 
'0000000001001101'
binary_representation_of_x = bin(x)
binary_representation_of_x = 
'1001101000000000'

クリーンアップ

元の状態に戻します。

set(0,'format',originalFormat);
warning(originalWarningState);
fipref(originalFiprefState);
%#ok<*NOPTS>

符号なしのデータを正規化する関数

このアルゴリズムは、8 ビット バイトの符号なしのデータを正規化します。入力が u > 0 の場合、出力 x は次のように正規化されます。

u = x*2^n

ここで、1 <= x < 2n は整数です。n には、正負の値またはゼロを指定できることに注意してください。

関数 fi_normalize_unsigned_8_bit_byte は入力の最上位 8 ビットを一度に確認し、最上位ビットが 1 になるまでこれらのビットを左にシフトします。各 8 ビット バイトでシフトするビット数は、最上位ビットから 0 が連続する数のルックアップ テーブル NLZLUT から読み取られます。

function [x,n] = fi_normalize_unsigned_8_bit_byte(u)
    assert(isscalar(u),'Input must be scalar');
    assert(all(u>0),'Input must be positive.');
    assert(isfi(u) && isfixed(u),'Input must be a fi object with fixed-point data type.');
    u = removefimath(u);
    NLZLUT = number_of_leading_zeros_look_up_table();
    word_length = u.WordLength;
    u_fraction_length = u.FractionLength;
    B = 8;
    leftshifts=int8(0);
    % Reinterpret the input as an unsigned integer.
    T_unsigned_integer = numerictype(0, word_length, 0);
    v = reinterpretcast(u,T_unsigned_integer);
    F = fimath('OverflowAction','Wrap',...
               'RoundingMethod','Floor',...
               'SumMode','KeepLSB',...
               'SumWordLength',v.WordLength);
    v = setfimath(v,F);
    % Unroll the loop in generated code so there will be no branching.
    for k = coder.unroll(1:ceil(word_length/B))
        % For each iteration, see how many leading zeros are in the high
        % byte of V, and shift them out to the left. Continue with the
        % shifted V for as many bytes as it has.
        %
        % The index is the high byte of the input plus 1 to make it a
        % one-based index.
        index = int32(bitsra(v,word_length-B) + uint8(1));
        % Index into the number-of-leading-zeros lookup table.  This lookup
        % table takes in a byte and returns the number of leading zeros in the
        % binary representation.
        shiftamount = NLZLUT(index);
        % Left-shift out all the leading zeros in the high byte.
        v = bitsll(v,shiftamount);
        % Update the total number of left-shifts
        leftshifts = leftshifts+shiftamount;
    end
    % The input has been left-shifted so the most-significant-bit is a 1.
    % Reinterpret the output as unsigned with one integer bit, so
    % that 1 <= x < 2.
    T_x = numerictype(0,word_length,word_length-1);
    x = reinterpretcast(v,T_x);
    x = removefimath(x);
    % Let Q = int(u).  Then u = Q*2^(-u_fraction_length),
    % and x = Q*2^leftshifts * 2^(1-word_length).  Therefore,
    % u = x*2^n, where n is defined as:
    n = word_length -  u_fraction_length - leftshifts - 1;
end

最上位ビットから 0 が連続する数のルックアップ テーブル

関数 number_of_leading_zeros_look_up_tablefi_normalize_unsigned_8_bit_byte によって使用され、8 ビット ワードで最上位ビットから 0 が連続する数の table を返します。

NLZLUT の最初の要素は 8 で、u=0 に対応します。8 ビット値 u = 00000000_2 (ここで添字 2 は基数 2 を示す) では、最上位ビットから連続する 0 の数が 8 となります。

NLZLUT の 2 番目の要素は 7 で、u=1 に対応します。8 ビット値 u = 00000001_2 の最上位ビットから連続する 0 の数は 7 になります。

以降同様に続き、NLZLUT の最後の要素は 0 となります。これは u=255 に対応します。8 ビット値 u=11111111_2 の最上位ビットから連続する 0 の数は 0 になります。

NLZLUT テーブルは次のように生成されます。

>> B = 8; % Number of bits in a byte

>> NLZLUT = int8(B-ceil(log2((1:2^B))))

function NLZLUT = number_of_leading_zeros_look_up_table()
%   B = 8;  % Number of bits in a byte
%   NLZLUT = int8(B-ceil(log2((1:2^B))))
    NLZLUT = int8([8    7    6    6    5    5    5    5 ...
                   4    4    4    4    4    4    4    4 ...
                   3    3    3    3    3    3    3    3 ...
                   3    3    3    3    3    3    3    3 ...
                   2    2    2    2    2    2    2    2 ...
                   2    2    2    2    2    2    2    2 ...
                   2    2    2    2    2    2    2    2 ...
                   2    2    2    2    2    2    2    2 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0]);
end