我知道,关于浮点运算的另一个主题!
我一直试图绕过这个,似乎无法想出为什么添加负浮点值对我不起作用。
如果它们都是正值,则一切都按预期工作(返回的数字并非远远超出预期,因为这毕竟是浮点数。)
我正在使用32位版本,因为它不明显;)
我已经读完了这个:http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html 并且已经在线发现了浮点运算的各种各样的,很好的解释 - 但是,我似乎还无法弄清楚如何添加混合的正负值(或下面的代码中的情况2,3和4)。 / p>
到目前为止,这是我的代码:
int flt32_get_sign (flt32 x) {
/** shift sign bit right; 0 = pos, 1 = neg */
return ((x & 0x80000000) >> 31);
}
int flt32_get_exp (flt32 x) {
/** get biaseed exponent value */
return ((x & 0x7F800000) >> 23);
}
int flt32_get_val (flt32 x) {
/** mask off mantissa
* make sure implicit one set
*/
return ((x & 0x7FFFFF) ^ 0x800000);
}
int flt32_left_most_1 (int bits) {
int position = -1;
/** make sure working with abs value */
if (flt32_get_sign(bits) != 0){
bits = flt32_negate(bits);
}
while(bits != 0){
position++, bits >>=1;
}
return position;
}
int flt32_right_most_1 (int bits) {
int position = -1;
/** make sure working with abs value */
if (flt32_get_sign(bits) != 0){
bits = flt32_negate(bits);
}
while (!(bits & 1)){
position++, bits >>=1;
}
return position;
}
flt32 flt32_abs (flt32 x) {
return (x & 0x7FFFFFFF);
}
flt32 flt32_negate (flt32 x) {
if (flt32_get_sign(x) == 0){
/** is possitive */
return (x ^ 0x80000000);
}
/** else is negative */
return (x & 0x7FFFFFFF);
}
flt32 flt32_add (flt32 x, flt32 y) {
/**
* Possible casses:
* 1: +x +y; 2: +x -y; 3: -x +y; 4: -x -y
*/
flt32 sum, x_val, y_val;
int shift;
/** Case 1 */
if (flt32_get_sign(x) == 0 && flt32_get_sign(y) == 0){
if (flt32_get_exp(x) == flt32_get_exp(y)){
/** no shifting neccesary
* add mantissa's then mask to make sure
* we don't get overflow into the exponent bits
* then add exponent back to new value
*/
sum = (x & 0x7F800000) + ((flt32_get_val(x) + flt32_get_val(y)) & 0x7FFFFF);
} else if (flt32_get_exp(x) > flt32_get_exp(y)){
/** exponent of x is larger than y
* need to right shift y and set its exponent = exponent of x
*/
shift = (flt32_get_exp(x) - flt32_get_exp(y));
y_val = flt32_get_exp(x) + (flt32_get_val(y) >> shift);
sum = x + y_val;
} else {
/** exponent x is smaller than y
* need to right shift x and set its exponent = exponent of y
*/
shift = (flt32_get_exp(y) - flt32_get_exp(x));
x_val = flt32_get_exp(y) + (flt32_get_val(x) >> shift);
sum = x_val + y;
}
}
/** Case 2 */
if (flt32_get_sign(x) == 0 && flt32_get_sign(y) == 1){
if (flt32_get_exp(x) == flt32_get_exp(y)){
/** no shifting neccesary
* add mantissa's then mask to make sure
* we don't get overflow into the exponent bits
* then add exponent back to new value
*/
x_val = ((x & 0xFF800000) + flt32_get_val(x));
y_val = ((y & 0xFF800000) + flt32_get_val(y));
sum = x_val + flt32_negate(y_val);
} else if (flt32_get_exp(x) > flt32_get_exp(y)){
/** exponent of x is larger than y
* need to right shift y and set its exponent = exponent of x
*/
shift = (flt32_get_exp(x) - flt32_get_exp(y));
y_val = flt32_get_exp(x) + (flt32_get_val(y) >> shift);
sum = x + flt32_negate(y_val);
} else {
/** exponent x is smaller than y
* need to right shift x and set its exponent = exponent of y
*/
shift = (flt32_get_exp(y) - flt32_get_exp(x));
x_val = flt32_get_exp(y) + (flt32_get_val(x) >> shift);
sum = x_val + flt32_negate(y);
}
}
return sum;
}
除了:只是我在绕着这一切缠绕着我做的一个观察;理解浮点似乎很好,甚至是必要的 - 但几乎每一篇我遇到过的文章,甚至是教科书,都说尽可能避免它! :)
答案 0 :(得分:2)
案例2注意事项
在sum = x + flt32_negate(y_val)
后{@ 1}},你需要规范化答案:左移直到不是这样,随着时间的推移递减指数。首先注意sum < 0x800000
并返回特殊形式的0.修复sum == 0
后减去偏差指数时,不会检查下溢。
进一步的差异问题:必须进行减法(+情况2),以便由于flt32_get_val()
问题而将shift
的一部分移出的任何位重新输入。如果任何位仍然移出,则必须评估和处理舍入。
考虑递交+和 - 虽然常见的例程和矢量关闭加上/减去幅度。 + 1,2,3,4例如 - 案例1,4,3,2。 +案例1,4是相同的,只是不同的标志。一旦你发现第一种情况的幅度更大,情况2,3就会相互抵消。
首先考虑将+ 0,-0视为特殊情况。
你对INF和NAN一无所知。建议保存以备日后使用。
案例1注意事项
如果sum < 0x800000
,则需要右移筛选并递增指数,测试指数溢出和返回INF。
如果你右移,OP需要决定舍入模式并可能增加答案,再次测试增量指数,测试指数溢出和返回INF。
制作sum > 0xFFFFFF
后,回答重建必须小心处理隐藏的MSBit。