【发布时间】:2013-08-31 19:24:05
【问题描述】:
我正在做一个小项目,我需要浮点乘法与 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;
}
顺便说一句:我将浮点数存储在整数中,因为稍后我会尝试将此代码移植到某种无浮点操作的汇编程序中。
问题
为什么代码只对某些值有效?我是否忘记了一些标准化或类似的事情?还是它只是偶然起作用?
免责声明:我不是 CompSci 学生,这是一个休闲项目;)
更新 #1
感谢Eric Postpischil 的评论,我注意到代码存在一个问题:hidden_bit 标志被关闭了一个(应该是1 << 10)。随着这一变化,我不再有小数位,但仍然有一些计算是关闭的(例如3•3=20)。我假设,这是答案中描述的res_frac 班次。
更新 #2
代码的第二个问题确实是res_frac 移位。更新 #1 后,当我得到 frac1 * frac2 的 22 位结果时,我得到了错误的结果。我已经用更正的 shift 语句更新了上面的代码。感谢大家的每一个评论和回答! :)
【问题讨论】:
-
我建议您使用调试器(或添加打印语句)来跟踪 all 中间变量的值,以查找无法按预期工作的输入之一。跨度>
-
你有没有在没有至少一个输入的情况下得到正确的答案?错误总是丢失结果中最不重要的 1 吗?
-
好的,那么哪个中间变量不符合您的预期?
-
我在how to debug 上有网页。这不是关于放入打印语句的机制,而是关于如何选择打印/调试操作并使用它们来找出问题所在。
-
@m--s:您如何计算 3•5 的有效位数应为 1001000000?整数三为 11,其归一化有效数为 11000000000(带前导位)。整数 5 是 101,它的归一化有效数字是 10100000000。将它们相乘产生 111100000000000000000。归一化产生 11110000000.0000000000(移位 10 位)。舍入产生 11110000000。删除前导位产生 1110000000。
标签: c algorithm floating-point computer-science