1

私は小さなプロジェクトに取り組んでおり、16 ビット浮動小数点数 (半精度) を使用した浮動小数点乗算が必要です。残念ながら、私はアルゴリズムでいくつかの問題に直面しています:

出力例

1 * 5 = 5
2 * 5 = 10
3 * 5 = 14.5
4 * 5 = 20
5 * 5 = 24.5

100 * 4 = 100
100 * 5 = 482

ソースコード

const int bits = 16;
const int exponent_length = 5;
const int fraction_length = 10;

const int bias = pow(2, exponent_length - 1) - 1;
const int exponent_mask = ((1 << 5) - 1) << fraction_length;
const int fraction_mask = (1 << fraction_length) - 1;
const int hidden_bit = (1 << 10);  // Was 1 << 11 before update 1

int float_mul(int f1, int f2) {
    int res_exp = 0;
    int res_frac = 0;
    int result = 0;

    int exp1 = (f1 & exponent_mask) >> fraction_length;
    int exp2 = (f2 & exponent_mask) >> fraction_length;
    int frac1 = (f1 & fraction_mask) | hidden_bit;
    int frac2 = (f2 & fraction_mask) | hidden_bit;

    // Add exponents
    res_exp = exp1 + exp2 - bias;  // Remove double bias

    // Multiply significants
    res_frac = frac1 * frac2;   // 11 bit * 11 bit → 22 bit!
    // Shift 22bit int right to fit into 10 bit
    if (highest_bit_pos(res_mant) == 21) {
        res_mant >>= 11;
        res_exp += 1;
    } else {
        res_mant >>= 10;
    }
    res_frac &= ~hidden_bit;    // Remove hidden bit

    // Construct float
    return (res_exp << bits - exponent_length - 1) | res_frac;
}

ところで、私は浮動小数点数を int で格納しています。これは、後でこのコードを浮動小数点操作のない何らかのアセンブラーに移植しようとするからです。

質問

コードが一部の値に対してのみ機能するのはなぜですか? 正規化などを忘れましたか?それとも偶然にしか機能しませんか?

免責事項: 私は CompSci の学生ではありません。余暇のプロジェクトです ;)

更新 #1

Eric Postpischilのコメントのおかげで、コードに 1 つの問題があることに気付きましhidden_bit1 << 10。その変更により、小数点以下の桁数は取得できなくなりましたが、まだ一部の計算がオフになっています (例: 3•3=20)。答えで説明されているように、それはres_fracシフトだと思います。

アップデート #2

コードの 2 番目の問題は、実際にはres_fracシフトでした。更新 #1 の後、 の 22 ビットの結果があるときに間違った結果が得られましたfrac1 * frac2。上記のコードを、修正されたシフト ステートメントで更新しました。すべてのコメントと回答に感謝します!:)

4

3 に答える 3

1

1 つの問題は、丸めではなく切り捨てていることです。

res_frac >>= 11;            // Shift 22bit int right to fit into 10 bit

res_frac & 0x7ff最初に、アルゴリズムが破棄しようとしている 22 ビットの結果の部分を計算し、それと比較する必要があり0x400ます。以下の場合は、切り捨てます。それを超える場合は、ゼロから四捨五入します。に等しい場合は0x400、偶数の選択肢に丸めます。

于 2013-08-28T16:10:53.190 に答える
1

これは、既存のコードの何が問題なのかを分析するというよりも、コードを正しくするのを容易にするための提案です。

浮動小数点算術演算の一部またはすべてに共通するステップがいくつかあります。それぞれを 1 つの問題に焦点を当てて記述できる関数に抽出し、個別にテストすることをお勧めします。次に、乗算などを書くようになると、その操作の詳細を処理するだけで済みます。

すべての操作は、実際の符号付き指数と、より広い符号なし整数フィールドに完全な仮数を持つ構造体を使用する方が簡単です。符号付きの数値を扱っている場合は、符号ビットのブール値もあります。

少なくとも機能するまでは、別の関数にすることができるいくつかのサンプル操作を次に示します。

unpack: 16 ビットの float を取り、指数と仮数を構造体に抽出します。

pack: Undo unpack - 隠しビットの削除、バイアス指数の適用、それらを float に結合する処理を行います。

正規化: 仮数をシフトし、指数を調整して、最上位の 1 ビットを指定されたビット位置に移動します。

round: 丸めルールを適用して、重要度の低いビットを削除します。IEEE 754 スタイルの四捨五入を行う場合は、ドロップされる最上位ビットであるガード ディジットと、ガード ビットよりも重要度の低いビットが 1 つあるかどうかを示す追加のビットが必要です。

于 2013-08-28T18:44:39.497 に答える