私は小さなプロジェクトに取り組んでおり、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_bit
た1 << 10
。その変更により、小数点以下の桁数は取得できなくなりましたが、まだ一部の計算がオフになっています (例: 3•3=20
)。答えで説明されているように、それはres_frac
シフトだと思います。
アップデート #2
コードの 2 番目の問題は、実際にはres_frac
シフトでした。更新 #1 の後、 の 22 ビットの結果があるときに間違った結果が得られましたfrac1 * frac2
。上記のコードを、修正されたシフト ステートメントで更新しました。すべてのコメントと回答に感謝します!:)