Схожу с ума, почему меняются мои переменные? - PullRequest
0 голосов
/ 15 сентября 2011

Хорошо, у меня раньше такое случалось, когда переменные случайным образом меняли числа из-за проблем с выделением памяти или неправильной адресации и т. Д., Например, когда вы выходили за пределы массива. Однако я не использую массивы, указатели или адреса, поэтому не знаю, почему после выполнения этого цикла он вдруг решает, что «показатель степени» после установки в 0 равен 288 внутри цикла:

РЕДАКТИРОВАТЬ: Он решает разбить конкретно: 0x80800000.

Это не прерывается в одном тесте , у нас есть «тестирующий» клиент, который повторяет несколько тестовых случаев, каждый раз, когда он вызывает его снова, каждый раз, когда функция вызывается снова, значения должны быть установлены равны их исходным значениям.

/* 
 * float_i2f - Return bit-level equivalent of expression (float) x
 *   Result is returned as unsigned int, but
 *   it is 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;
}

Ответы [ 7 ]

2 голосов
/ 15 сентября 2011

Используйте отладчик или IDE, установите watch / breakpoint / assert на значение показателя степени (например, (exponent > 100).

Что было оскорбительным значением x, которое float_i2f() был вызван с помощью? Экспонента взорвалась для всех x или некоторого диапазона?

(Вы только что сказали, когда x = 0x80800000? Вы установили часы на экспоненте и сделали шаг вотладчик для этого значения? Должен ответить на ваш вопрос. Вы проверили, например, что 0x807FFFFF работает?)

0 голосов
/ 15 сентября 2011

a переполнение.a*2==0 когда a==1<<31, поэтому каждый раз exponent%32==0, a==0 и вы зацикливаетесь до exponent==300.

Также есть несколько других проблем:

Ваш fraction расчет отключен, когда exponent>=24.Отрицательные сдвиги влево автоматически не превращаются в положительные сдвиги вправо.

Маска для генерации дроби также немного ошибочна.Предполагается, что ведущий бит всегда равен 1, а мантисса - только 23 бита, поэтому дробь для x <2 ^ 23 должна быть: </p>

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

Цикл для вычисления exponent не выполняется,abs(x)>=1<<31 (и случайно приводит к потере точности при неправильном округлении);цикл, который учитывает неявный 1, был бы лучше здесь.

0 голосов
/ 15 сентября 2011

Просто обработайте случай, когда «а» становится отрицательным (или лучше, проверьте ваш ввод, чтобы он никогда не становился отрицательным на первом месте), и у вас все будет хорошо:)

0 голосов
/ 15 сентября 2011

Переменная exponent не делает ничего загадочного. Вы увеличиваете exponent каждый раз в цикле, так что в конечном итоге он достигает любого числа, которое вам нравится. Реальный вопрос в том, почему ваш цикл не завершается, когда вы думаете, что он должен?

Ваше состояние цикла зависит от a. Попробуйте распечатать последовательные значения a, когда ваш цикл повторяется. Вы замечаете что-нибудь смешное, когда a достигает 1073741824? Вы уже слышали о целочисленном переполнении в ваших классах?

0 голосов
/ 15 сентября 2011

Там было много бесполезных попыток оптимизации, я удалил их, чтобы код был проще для чтения.Также я использовал соответственно <stdint.h> типы.

В цикле a *= 2 было переполнение целых чисел со знаком, но главной проблемой было отсутствие констант и странное вычисление магических чисел.Это все еще не является образцовым, потому что все константы должны быть названы, но это, кажется, работает надежно.

#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;
}
0 голосов
/ 15 сентября 2011

У вас есть строка, которая увеличивает экспоненту в конце цикла while.

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;

}
0 голосов
/ 15 сентября 2011

Я попробовал это сам с Visual Studio и с вводом «10», и, похоже, он работал нормально.

В: Можете ли вы дать мне значение ввода «x» там, где он не работает?1003 *

Q: Какой компилятор вы используете?На какой платформе вы работаете?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...