2017-02-03 5 views
1

Без использования бросков или функциональности библиотек я должен отличать целое число с поплавком с манипуляциями с битами. Ниже приведен код, над которым я сейчас работаю. Он основан на коде, который я нашел в Cast Integer to Float using Bit Manipulation breaks on some integers in C. Проблема, с которой я столкнулся, включает стандарты округления в IEEE 754. В частности, мой код округляется до нуля, но он должен округлять до четных чисел. Какие изменения мне нужно сделать?IEEE 754 Бит-манипуляция Ошибка округления

unsigned inttofloat(int x) { 
    int bias = 127; 
    int man; 
    int exp = bias + 31; //8-bit exp 
    int count = 0; 
    int tmin = 1 << 31; 
    int manpattern = 0x7FFFFF; 

    int sign = 0; 

    if (x == 0){ 
     return 0; 
    } 
    else if (x == tmin){ 
     return 0xcf << 24; 
    } 

    if (x < 0) { 
     sign = tmin; 
     x = ~x + 1; // makes x negative so that we can accurately represent it later on. 
    } 

    while((x & tmin) == 0){ 
     exp--; 
     x <<= 1; 
     count++; 
    } 

    exp <<= 23; 
    man = (x >> 8) & manpattern; 

    return (sign | exp | man); 
} 
+1

'int tmin = 1 << 31;' неопределенное поведение в реализации, где 'int' имеет менее 33 бит. – EOF

+0

Как это? В C99 говорится, что сдвиг размера слова минус 1 разрешен там, где это именно так. У меня есть 32 бита в моем целочисленном числе, поэтому 31 сдвиг влево все еще четко определен. –

+0

Вот статья, которая объясняет именно это @EOF http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html –

ответ

3

Для круглый в сторону ближайших - связей даже заменить (x >> 8) с:

unsigned u = x; // avoid any potential signed shifting issues 
unsigned lease_significant_bit = (u >> 8) & 1; 
unsigned round_bit = (u >> 7) & 1; // Most significant bit shifted out 
unsigned sticky_bit_flag = !!(u & 0x7F); // All other bits shifts out 

// OP's shifted answer. 
u = (u >> 8): 

// round away if more than half-way or 
// if at half-way and number is odd 
u += (round_bit & sticky_bit_flag) | (round_bit & lease_significant_bit); 

Оставьте его для ОП упростить


Обратите внимание, что u += 1 может распространяться весь путь и потребовать увеличение экспоненты.

+0

Большое вам спасибо за ответ. Я немного смущен, но о том, где это реализовать. вы только сказали заменить (x >> 8). Должен ли я заменить эту целую строку или сохранить & manpattern? –

+0

Окончательный 'u' можно использовать как' man = u & manpattern; ', но _take time_, чтобы понять код, а не просто вырезать/вставить. В частности, если 'x & manpattern == manpattern', то' u' будет распространять перенос из-за 'u + = ...', и экспоненту нужно будет увеличить. – chux

Смежные вопросы