开发者

Going crazy, why are my variables changing on me?

Okay I've had this happen to me before where variables randomly change numbers because of memory allocation issues or wrong addressing etc, such as when you go out of bounds with an array. However, I'm not using arrays, or pointers or addresses so I have no idea why after executing this loop it suddenly decides that "exponent" after being set to 0 is equal to 288 inside the loop:

EDIT: It decides to break on specifically: 0x80800000.

This does not break in one test, we have a "testing" client which iterates through several test cases, each time it calls this again, each time the function is called again the values should be set equal to their original values.

/* 
 * float_i2f - Return bit-level equivalent of expression (float) x
 *   Result is returned as unsigned int, but
 *   it i开发者_高级运维s to be interpreted as the bit-level representation of a
 *   single-precision floating point values.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned float_i2f(int x) { 
    int sign= 0;
    int a=0;
    int exponent=0;
    int crash_test=0;
    int exp=0;
    int fraction=0;
    int counter=0;

    if (x == 0) return 0;
    if (!(x ^ (0x01 << 31)))
    {
        return 0xCF << 24;
    }
    if (x>>31)
    {
        sign = 0xFF << 31;
        x = (~x) + 1;
    }
    else
    {
        sign = 0x00;
    }
    //printf(" After : %x  ", x);

    a = 1;
    exponent = 0;
    crash_test = 0;
    while ((a*2) <= x)
    {
        if (a == 0) a =1;
        if (a == 1) crash_test = exponent;
        /*
        if(exponent == 288) 
        {exponent =0;
            counter ++;
            if(counter <=2)
            printf("WENT OVERBOARD WTF %d  ORIGINAL %d", a, crash_test);
        }
        */
        if (exponent > 300) break;

        exponent ++;
        a *= 2;
    }

    exp = (exponent + 0x7F) << 23;
    fraction = (~(((0x01)<< 31) >> 7)) & (x << (25 - (exponent + 1)));
    return sign | exp | fraction;
}


Use a debugger or IDE, set a watch/breakpoint/assert on the value of exponent (e.g. (exponent > 100).

What was the offending value of x that float_i2f() was called with? Did exponent blow up for all x, or some range?

(Did you just say when x = 0x80800000 ? Did you set a watch on exponent and step that in a debugger for that value? Should answer your question. Did you check that 0x807FFFFF works, for example?)


I tried it myself with Visual Studio, and an input of "10", and it seemed to work OK.

Q: Can you give me an input value of "x" where it fails?

Q: What compiler are you using? What platform are you running on?


You have line that increments exponent at the end of your while loop.

while((a*2) <= x)
{
    if(a == 0) a =1;
    if(a == 1) crash_test = exponent;
    /* 

    if(exponent == 288) 
    {
        exponent =0;
        counter ++;
        if(counter <=2)
        printf("WENT OVERBOARD WTF %d  ORIGINAL %d", a, crash_test);
    }
    */

    if(exponent > 300) break;

    exponent ++;
    a *= 2;

}


The variable exponent isn't doing anything mysterious. You are incrementing exponent each time through the loop, so it eventually hits any number you like. The real question is why doesn't your loop exit when you think it should?

Your loop condition depends on a. Try printing out the successive values of a as your loop repeats. Do you notice anything funny happening after a reaches 1073741824? Have you heard about integer overflow in your classes yet?


Just handle the case where "a" goes negative (or better, validate your input so it never goes negative int he first place), and you should be fine :)


There were many useless attempts at optimization in there, I've removed them so the code is easier to read. Also I used <stdint.h> types as appropriate.

There was signed integer overflow in a *= 2 in the loop, but the main problem was lack of constants and weird computation of magic numbers.

This still isn't exemplary because the constants should all be named, but this seems to work reliably.

#include <stdio.h>
#include <stdint.h>

uint32_t float_i2f(int32_t x) { 
    uint32_t sign= 0;
    uint32_t exponent=0;
    uint32_t fraction=0;

    if (x == 0) return 0;
    if ( x == 0x80000000 )
    {
        return 0xCF000000u;
    }
    if ( x < 0 )
    {
        sign = 0x80000000u;
        x = - x;
    }
    else
    {
        sign = 0;
    }

    /* Count order of magnitude, this will be excessive by 1. */
    for ( exponent = 1; ( 1u << exponent ) <= x; ++ exponent ) ;

    if ( exponent < 24 ) {
        fraction = 0x007FFFFF & ( x << 24 - exponent ); /* strip leading 1-bit */
    } else {
        fraction = 0x007FFFFF & ( x >> exponent - 24 );
    }
    exponent = (exponent + 0x7E) << 23;
    return sign | exponent | fraction;
}


a overflows. a*2==0 when a==1<<31, so every time exponent%32==0, a==0 and you loop until exponent==300.

There are a few other issues as well:

Your fraction calculation is off when exponent>=24. Negative left shifts do not automatically turn into positive right shifts.

The mask to generate the fraction is also slightly wrong. The leading bit is always assumed to be 1, and the mantissa is only 23 bits, so fraction for x<2^23 should be:

    fraction = (~(((0x01)<< 31) >> 8)) & (x << (24 - (exponent + 1)));

The loop to calculate the exponent fails when abs(x)>=1<<31 (and incidentally results in precision loss if you don't round appropriately); a loop that takes the implicit 1 into account would be better here.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜