我必须遵循将浮点值(打包在int中)转换为int值的按位代码。
问题:存在舍入问题,因此在输入为0x80000001的情况下失败。我该如何处理?
以下是代码:
if(x == 0) return x;
unsigned int signBit = 0;
unsigned int absX = (unsigned int)x;
if (x < 0)
{
signBit = 0x80000000u;
absX = (unsigned int)-x;
}
unsigned int exponent = 158;
while ((absX & 0x80000000) == 0)
{
exponent--;
absX <<= 1;
}
unsigned int mantissa = absX >> 8;
unsigned int result = signBit | (exponent << 23) | (mantissa & 0x7fffff);
printf("\nfor x: %x, result: %x",x,result);
return result;
答案 0 :(得分:1)
那是因为0x80000001
的精确度超过that of a float
。阅读链接文章,浮点数的精度为24位,因此根本无法检测到差异(x - y
)小于两个>> 24
的最高位的任何一对浮点数。
gdb
同意你的演员:
main.c中:
#include <stdio.h>
int main() {
float x = 0x80000001;
printf("%f\n",x);
return 0;
}
GDB:
Breakpoint 1, main () at test.c:4
4 float x = 0x80000001;
(gdb) n
5 printf("%f\n",x);
(gdb) p x
$1 = 2.14748365e+09
(gdb) p (int)x
$2 = -2147483648
(gdb) p/x (int)x
$3 = 0x80000000
(gdb)
这种不精确的极限:
(gdb) p 0x80000000 == (float)0x80000080
$21 = 1
(gdb) p 0x80000000 == (float)0x80000081
$20 = 0
实际按位表示:
(gdb) p/x (int)(void*)(float)0x80000000
$27 = 0x4f000000
(gdb) p/x (int)(void*)(float)0x80000080
$28 = 0x4f000000
(gdb) p/x (int)(void*)(float)0x80000081
$29 = 0x4f000001
double
确实有足够的精确度来区分:
(gdb) p 0x80000000 == (float)0x80000001
$1 = 1
(gdb) p 0x80000000 == (double)0x80000001
$2 = 0