背景
我正在玩比特级编码(这不是功课 - 只是好奇)。我在网上和一本名为Hacker's Delight的书中找到了很多很好的资料,但是我遇到了一个在线问题。
它要求将整数转换为float。我使用以下链接作为参考来解决问题:
How to manually (bitwise) perform (float)x?
How to convert an unsigned int to a float?
http://locklessinc.com/articles/i2f/
问题和疑问:
我认为我对这个过程的理解很充分(我试图在评论中记录这个过程),但是当我测试它时,我不理解输出。
测试案例:
float_i2f(2)返回1073741824
float_i2f(3)返回1077936128
我希望看到像2.0000和3.0000这样的东西。
我把转换搞砸了吗?我想也许这是一个内存地址,所以我想也许我错过了访问实际数字所需的转换步骤?或者我打印错误?我正在打印我的输出:
printf("Float_i2f ( %d ): ", 3);
printf("%u", float_i2f(3));
printf("\n");
但我认为打印方法适用于C中的无符号值(我习惯用Java编程)。
感谢您的任何建议。
代码:
/*
* 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) {
if (x == 0){
return 0;
}
//save the sign bit for later and get the asolute value of x
//the absolute value is needed to shift bits to put them
//into the appropriate position for the float
unsigned int signBit = 0;
unsigned int absVal = (unsigned int)x;
if (x < 0){
signBit = 0x80000000;
absVal = (unsigned int)-x;
}
//Calculate the exponent
// Shift the input left until the high order bit is set to form the mantissa.
// Form the floating exponent by subtracting the number of shifts from 158.
unsigned int exponent = 158; //158 possibly because of place in byte range
while ((absVal & 0x80000000) == 0){//this checks for 0 or 1. when it reaches 1, the loop breaks
exponent--;
absVal <<= 1;
}
//find the mantissa (bit shift to the right)
unsigned int mantissa = absVal >> 8;
//place the exponent bits in the right place
exponent = exponent << 23;
//get the mantissa
mantissa = mantissa & 0x7fffff;
//return the reconstructed float
return signBit | exponent | mantissa;
}
答案 0 :(得分:3)
继续发表评论。您的代码是正确的,您只需查看由IEEE-754单精度浮点数中的位组成的等效 HasPtr a;
HasPtr b(string("123456789...123456789"));
a=b;
。 IEEE-754单精度数字格式(由符号,扩展指数和尾数组成)可以解释为unsigned integer
,或者那些相同的位可以解释为float
(只是由32位组成的数字)。您正在为浮点数输出无符号等效项。
您可以通过简单的联合确认。例如:
unsigned integer
使用/输出示例
#include <stdio.h>
#include <stdint.h>
typedef union {
uint32_t u;
float f;
} u2f;
int main (void) {
u2f tmp = { .f = 2.0 };
printf ("\n u : %u\n f : %f\n", tmp.u, tmp.f);
return 0;
}
如果您有任何其他问题,请与我们联系。很高兴看到您的研究产生了正确的浮点转换。 (还要注意关于截断/舍入的第二条评论)
答案 1 :(得分:0)
我只是在这里说,因为没有具体关于字节序的问题已得到解决。我们来谈谈它。
原始问题中值的构造与字节序无关,使用移位和其他按位操作。这意味着无论您的系统是大端还是小端,实际值都是相同的。不同之处在于它在内存中的字节顺序。
IEEE-754普遍接受的惯例是字节顺序是big-endian(虽然我认为没有正式的规范,因此没有要求实现遵循它)。这意味着如果要将整数值直接解释为float,则需要以big-endian字节顺序排列。
所以,你可以使用这种方法结合使用if ,只有当知道系统中浮点数和整数的字节顺序相同时。
在基于英特尔的常见架构上,这是不行的。在这些架构上,整数是小端的,浮点数是大端的。您需要将您的值转换为big-endian。一个简单的方法是重新打包它的字节,即使它们已经是big-endian :
uint32_t n = float_i2f( input_val );
uint8_t char bytes[4] = {
(uint8_t)((n >> 24) & 0xff),
(uint8_t)((n >> 16) & 0xff),
(uint8_t)((n >> 8) & 0xff),
(uint8_t)(n & 0xff)
};
float fval;
memcpy( &fval, bytes, sizeof(float) );
我要强调,如果你试图将整数表示重新解释为float
或反过来,你只需要担心这一点。
如果您只想输出表示的位数,那么您不必担心。您只需以有用的形式显示整数,例如hex:
printf( "0x%08x\n", n );