现在,这是我应该实现的函数的函数头:
/*
* float_from_int - 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_from_int(int x) {
...
}
我们不允许进行浮动操作或任何类型的强制转换。
现在我尝试实现该站点给出的第一个算法:http: //locklessinc.com/articles/i2f/
这是我的代码:
unsigned float_from_int(int x) {
// grab sign bit
int xIsNegative = 0;
int absValOfX = x;
if(x < 0){
xIsNegative = 1;
absValOfX = -x;
}
// zero case
if(x == 0){
return 0;
}
if(x == 0x80000000){ //Updated to add this
return 0xcf000000;
}
//int shiftsNeeded = 0;
/*while(){
shiftsNeeded++;
}*/
unsigned I2F_MAX_BITS = 15;
unsigned I2F_MAX_INPUT = ((1 << I2F_MAX_BITS) - 1);
unsigned I2F_SHIFT = (24 - I2F_MAX_BITS);
unsigned result, i, exponent, fraction;
if ((absValOfX & I2F_MAX_INPUT) == 0)
result = 0;
else {
exponent = 126 + I2F_MAX_BITS;
fraction = (absValOfX & I2F_MAX_INPUT) << I2F_SHIFT;
i = 0;
while(i < I2F_MAX_BITS) {
if (fraction & 0x800000)
break;
else {
fraction = fraction << 1;
exponent = exponent - 1;
}
i++;
}
result = (xIsNegative << 31) | exponent << 23 | (fraction & 0x7fffff);
}
return result;
}
但它没有用(见下面的测试错误):
ERROR: Test float_from_int(8388608[0x800000]) failed...
...Gives 0[0x0]. Should be 1258291200[0x4b000000]
我不知道从这里去哪里。我应该如何从这个 int 解析浮点数?
编辑#1:您可能可以从我的代码中看到我也开始研究此算法(请参阅此站点):
我假设是 10 位 2 的补码整数,因为尾数只有 9 位,但这个过程可以推广到更多位。
Save the sign bit of the input and take the absolute value of the input. Shift the input left until the high order bit is set and count the number of shifts required. This forms the floating mantissa. Form the floating exponent by subtracting the number of shifts from step 2 from the constant 137 or (0h89-(#of shifts)). Assemble the float from the sign, mantissa, and exponent.
但是,这似乎不对。如何转换 0x80000000?没有意义。
编辑#2:我认为这是因为我说最大位数是 15 ......嗯......
编辑#3:搞砸旧算法,我重新开始:
unsigned float_from_int(int x) {
// grab sign bit
int xIsNegative = 0;
int absValOfX = x;
if(x < 0){
xIsNegative = 1;
absValOfX = -x;
}
// zero case
if(x == 0){
return 0;
}
if (x == 0x80000000){
return 0xcf000000;
}
int shiftsNeeded = 0;
int counter = 0;
while(((absValOfX >> counter) & 1) != 1 && shiftsNeeded < 32){
counter++;
shiftsNeeded++;
}
unsigned exponent = shiftsNeeded + 127;
unsigned result = (xIsNegative << 31) | (exponent << 23);
return result;
这是我在这个错误上遇到的错误(我想我已经克服了最后一个错误):
ERROR: Test float_from_int(-2139095040[0x80800000]) failed...
...Gives -889192448[0xcb000000]. Should be -822149120[0xceff0000]
知道这一点可能会有所帮助:absValOfX = 7f800000(使用 printf)
编辑#4:啊,我发现指数错误,需要从左边数,然后从 32 中减去我相信。
编辑#5:我重新开始,现在试图处理奇怪的舍入问题......
if (x == 0){
return 0; // 0 is a special case because it has no 1 bits
}
if (x >= 0x80000000 && x <= 0x80000040){
return 0xcf000000;
}
// Save the sign bit of the input and take the absolute value of the input.
unsigned signBit = 0;
unsigned absX = (unsigned)x;
if (x < 0)
{
signBit = 0x80000000u;
absX = (unsigned)-x;
}
// 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 exponent = 158;
while ((absX & 0x80000000) == 0)
{
exponent--;
absX <<= 1;
}
unsigned negativeRoundUp = (absX >> 7) & 1 & (absX >> 8);
// compute mantissa
unsigned mantissa = (absX >> 8) + ((negativeRoundUp) || (!signBit & (absX >> 7) & (exponent < 156)));
printf("absX = %x, absX >> 8 = %x, exponent = %i, mantissa = %x\n", absX, (absX >> 8), exponent, mantissa);
// Assemble the float from the sign, mantissa, and exponent.
return signBit | ((exponent << 23) + (signBit & negativeRoundUp)) | ( (mantissa) & 0x7fffff);
-
absX = fe000084, absX >> 8 = fe0000, exponent = 156, mantissa = fe0000
ERROR: Test float_from_int(1065353249[0x3f800021]) failed...
...Gives 1316880384[0x4e7e0000]. Should be 1316880385[0x4e7e0001]
编辑#6
又做了一次,仍然,四舍五入不能正常工作。我试图凑齐一些四舍五入,但它只是行不通......
unsigned float_from_int(int x) {
/*
If N is negative, negate it in two's complement. Set the high bit (2^31) of the result.
If N < 2^23, left shift it (multiply by 2) until it is greater or equal to.
If N ≥ 2^24, right shift it (unsigned divide by 2) until it is less.
Bitwise AND with ~2^23 (one's complement).
If it was less, subtract the number of left shifts from 150 (127+23).
If it was more, add the number of right shifts to 150.
This new number is the exponent. Left shift it by 23 and add it to the number from step 3.
*/
printf("---------------\n");
//printf("x = %i (%x), -x = %i, (%x)\n", x, x, -x, -x);
if(x == 0){
return 0;
}
if(x == 0x80000000){
return 0xcf000000;
}
// If N is negative, negate it in two's complement. Set the high bit of the result
unsigned signBit = 0;
if (x < 0){
signBit = 0x80000000;
x = -x;
}
printf("abs val of x = %i (%x)\n", x, x);
int roundTowardsZero = 0;
int lastDigitLeaving = 0;
int shiftAmount = 0;
int originalAbsX = x;
// If N < 2^23, left shift it (multiply it by 2) until it is great or equal to.
if(x < (8388608)){
while(x < (8388608)){
//printf(" minus shift and x = %i", x );
x = x << 1;
shiftAmount--;
}
} // If N >= 2^24, right shfit it (unsigned divide by 2) until it is less.
else if(x >= (16777215)){
while(x >= (16777215)){
/*if(x & 1){
roundTowardsZero = 1;
printf("zzz Got here ---");
}*/
lastDigitLeaving = (x >> 1) & 1;
//printf(" plus shift and x = %i", x);
x = x >> 1;
shiftAmount++;
}
//Round towards zero
x = (x + (lastDigitLeaving && (!(originalAbsX > 16777216) || signBit)));
printf("x = %i\n", x);
//shiftAmount = shiftAmount + roundTowardsZero;
}
printf("roundTowardsZero = %i, shiftAmount = %i (%x)\n", roundTowardsZero, shiftAmount, shiftAmount);
// Bitwise AND with 0x7fffff
x = x & 0x7fffff;
unsigned exponent = 150 + shiftAmount;
unsigned rightPlaceExponent = exponent << 23;
printf("exponent = %i, rightPlaceExponent = %x\n", exponent, rightPlaceExponent);
unsigned result = signBit | rightPlaceExponent | x;
return result;