1

我知道,关于浮点运算的另一个话题!

我一直试图解决这个问题,但似乎无法想出为什么添加负浮点值对我不起作用。

如果它们都是正值,那么一切都按预期工作(返回的数字并没有超出预期,因为这毕竟是浮点数)。

我使用的是 32 位版本,以防不明显;)

我已经通读了这个:http ://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html 并且在网上找到了各种很好的浮点运算解释——但是,我仍然似乎无法弄清楚如何添加混合的正负值(或下面代码中的情况 2、3 和 4)。

到目前为止,这是我的代码:

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;
}

旁白:这只是我在思考所有这些时所做的观察;理解浮点似乎很棒,甚至是必要的——但几乎我遇到的每一篇文章,甚至教科书,都说尽可能避免使用它!:)

4

1 回答 1

2

案例 2 的注意事项

之后 sum = x + flt32_negate(y_val),应该sum < 0x800000,你需要标准化答案:左移直到不是这样,随你去递减指数。首先注意sum == 0并返回特殊形成的 0。修复后,在减少偏差指数时将不会检查下溢flt32_get_val()

进一步的差异问题:必须进行减法(+ case 2),以便由于问题而将作为一部分移出的任何位shift带回sum < 0x800000。如果任何位仍然移出,则必须评估和处理舍入。

考虑通过常见的例程处理 + 和 - 并将矢量转移到加/减量级。+ 案例 1,2,3,4 类似于 - 案例 1,4,3,2。+ case 1,4 相同,只是符号不同。+ case 2,3 一旦你首先发现哪个幅度更大,就会相互否定。

首先考虑将 +0、-0 作为特殊情况处理。

你对 INF 和 NAN 什么也没做。建议保存以备后用,现在放入存根中。


案例 1 的注意事项

如果sum > 0xFFFFFF,您需要对指数进行右筛选和递增,测试指数溢出和返回的 INF。

如果您右移,OP 需要决定舍入模式并可能增加答案,再次测试递增指数,测试指数溢出和返回 INF。


制作后sum,答案重构必须小心处理隐藏的MSBit。

OP 正在混淆使用 | 与^。

OP 还有很长的路要走,我估计 OP 用 add case 完成了 10%。

于 2013-09-26T03:20:30.210 回答