Это общий вопрос о том, что именно происходит, когда я накладываю очень большое/маленькое значение SIGNED в плавающую точку с использованием gcc 4.4.Что произойдет, если вы нажмете большой int на float
Я вижу какое-то странное поведение при выполнении заклинания. Вот некоторые примеры:
MUSTBE будет получено с помощью этого метода:
float f = (float)x;
unsigned int r;
memcpy(&r, &f, sizeof(unsigned int));
./btest -f float_i2f -1 0x80800001
input: 10000000100000000000000000000001
absolute value: 01111111011111111111111111111111
exponent: 10011101
mantissa: 00000000011111101111111111111111 (right shifted absolute value)
EXPECT: 11001110111111101111111111111111 (sign|exponent|mantissa)
MUST BE: 11001110111111110000000000000000 (sign ok, exponent ok,
mantissa???)
./btest -f float_i2f -1 0x3f7fffe0
EXPECT: 01001110011111011111111111111111
MUST BE: 01001110011111100000000000000000
./btest -f float_i2f -1 0x80004999
EXPECT: 11001110111111111111111101101100
MUST BE: 11001110111111111111111101101101 (<- 1 added at the end)
Так что меня беспокоит, что мантисса в обоих примерах различных затем, если я просто переместить мое целое значение вправо. Например, нули в конце. Откуда они?
Я вижу это поведение только для больших/малых значений. Значения в диапазоне -2^24, 2^24 работают нормально.
Интересно, может ли кто-нибудь просветить меня, что здесь происходит. Каковы шаги, которые также принимают очень большие/маленькие значения.
Это вопрос о добавлении к вопросу: function to convert float to int (huge integers), который не является таким общим, как этот здесь.
EDIT Код:
unsigned float_i2f(int x) {
if (x == 0) return 0;
/* get sign of x */
int sign = (x>>31) & 0x1;
/* absolute value of x */
int a = sign ? ~x + 1 : x;
/* calculate exponent */
int e = 158;
int t = a;
while (!(t >> 31) & 0x1) {
t <<= 1;
e--;
};
/* calculate mantissa */
int m = (t >> 8) & ~(((0x1 << 31) >> 8 << 1));
m &= 0x7fffff;
int res = sign << 31;
res |= (e << 23);
res |= m;
return res;
}
EDIT 2:
После Адамса замечания и ссылки на книги Напишите Великий код, я обновил свою рутину с округлением. Тем не менее, я получаю некоторые ошибки округления (теперь, к счастью, только 1 бит).
Теперь, если я делаю пробный запуск, я получаю в основном хорошие результаты, но несколько ошибок округления, как это:
input: 0xfefffff5
result: 11001011100000000000000000000101
GOAL: 11001011100000000000000000000110 (1 too low)
input: 0x7fffff
result: 01001010111111111111111111111111
GOAL: 01001010111111111111111111111110 (1 too high)
unsigned float_i2f(int x) {
if (x == 0) return 0;
/* get sign of x */
int sign = (x>>31) & 0x1;
/* absolute value of x */
int a = sign ? ~x + 1 : x;
/* calculate exponent */
int e = 158;
int t = a;
while (!(t >> 31) & 0x1) {
t <<= 1;
e--;
};
/* mask to check which bits get shifted out when rounding */
static unsigned masks[24] = {
0, 1, 3, 7,
0xf, 0x1f,
0x3f, 0x7f,
0xff, 0x1ff,
0x3ff, 0x7ff,
0xfff, 0x1fff,
0x3fff, 0x7fff,
0xffff, 0x1ffff,
0x3ffff, 0x7ffff,
0xfffff, 0x1fffff,
0x3fffff, 0x7fffff
};
/* mask to check wether round up, or down */
static unsigned HOmasks[24] = {
0,
1, 2, 4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000
};
int S = a & masks[8];
int m = (t >> 8) & ~(((0x1 << 31) >> 8 << 1));
m &= 0x7fffff;
if (S > HOmasks[8]) {
/* round up */
m += 1;
} else if (S == HOmasks[8]) {
/* round down */
m = m + (m & 1);
}
/* special case where last bit of exponent is also set in mantissa
* and mantissa itself is 0 */
if (m & (0x1 << 23)) {
e += 1;
m = 0;
}
int res = sign << 31;
res |= (e << 23);
res |= m;
return res;
}
ли кто-то есть идеи, где проблема лежит?
Я не очень понимаю, что вы просите, но 32-бит с плавающей точкой имеет меньшую точность, чем 32-битный int, поэтому вы получите некоторые неточности. – interjay
Я добавил еще 2 значения к моим примерам. –
Вы должны подумать о том, чтобы показать свой код. Кроме того, что вы получаете против того, что вы ожидаете от небольших значений, таких как 0, 1, 2, 4 и т. Д.? –