在c中添加正负浮点值

时间:2013-09-26 02:51:24

标签: c floating-point

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

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

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

我正在使用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;
}

除了:只是我在绕着这一切缠绕着我做的一个观察;理解浮点似乎很好,甚至是必要的 - 但几乎每一篇我遇到过的文章,甚至是教科书,都说尽可能避免它! :)

1 个答案:

答案 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。

OP正在混淆使用|与^。

OP还有很长的路要走,我估计使用添加案例可以完成10%的OP。