Can someone look over my program and tell me if i am doing it correctly?
I am accepting user input in the form of 8 hexadecimal digits. I want to interpret those 8 digits as an IEEE 754 32-bit floating point number and will print out information about that number.
here is my output:
IEEE 754 32-bit floating point
byte order: little-endian
>7fffffff
0x7FFFFFFF
signBit 0, expbits 255, fractbits 0x007FFFFF
normalized: exp = 128
SNaN
>40000000
0x40000000
signBit 0, expbits 128, fractbits 0x00000000
normalized: exp = 1
>0
0x00000000
signBit 0, expbits 0, fractbits 0x00000000
+zero
here is the code..
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int HexNumber;
int tru_exp =0;
int stored_exp;
int negative;
int exponent;
int mantissa;
printf("IEEE 754 32-bit floating point");
int a = 0x12345678;
unsigned char *c = (unsigned char*)(&a);
if (*c == 0x78)
{
printf("\nbyte order: little-endian\n");
}
else
{
printf("\nbyte order: big-endian\n");
}
do{
printf("\n>");
scanf("%x", &HexNumber);
printf("\n0x%08X",HexNumber);
negative = !!(HexNumber & 0x80000000);
exponent = (HexNumber & 0x7f800000) >> 23;
mantissa = (HexNumber & 0x007FFFFF);
printf("\nsignBit %d, ", negative);
printf("expbits %d, ", exponent);
printf("fractbits 0x%08X", mantissa);
// "%#010x, ", mantissa);
if(exponent == 0)
{
if(mantissa != 0)
{
printf("\ndenormalized ");
}
}
else{
printf("\nnormalized: ");
tru_exp = exponent - 127;
printf("exp = %d", tru_exp);
}
if(exponent == 0 && mantissa == 0 && negative == 1)
{
printf("\n-zero");
}
if(exponent ==0 && mantissa == 0 && negative == 0)
{
printf("\n+zero");
}
if(exponent == 255 && mantissa != 0 && negative == 1)
{
printf("\nQNaN");
}
if(exponent == 255 && mantissa != 0 && negative == 0)
{
printf("\nSNaN");
}
if(exponent == 0xff && mantissa == 0 && negative == 1)
{
printf("\n-infinity");
}
if(exponent == 0xff && mantissa == 0 && negative == 0)
{
printf("\n+infinity");
}
printf("\n");
}while(HexNumber != 0);
return 0;
}
I dont think the de normalized is right?
Generally, you're pretty close. Some comments:
0x7fffffff is a quiet NaN, not a signaling NaN. The signbit does not determine whether or not a NaN is quiet; rather it is the leading bit of the significand (the preferred term for what you call "mantissa") field. 0xffbfffff is a signaling NaN, for example.
Edit: interjay correctly points out that this encoding isn't actually required by IEEE-754; a platform is free to use a different encoding for differentiating quiet and signaling NaNs. However, it is recommended by the standard:
A quiet NaN bit string should be
encoded with the first bit of the
trailing significand field T being 1.
A signaling NaN bit string should be
encoded with the first bit of the
trailing significand field being 0.
Infinities and NaNs usually aren't called "normal numbers" in the IEEE-754 terminology.
Your condition for calling a number "denormal" is correct.
For normal numbers, it would be nice to add the implicit leading bit when you report the significand. I personally would probably print them out in the C99 hex notation: 0x40000000 has a significand (once you add the implicit bit) of 0x800000 and an exponent of 1, so becomes 0x1.000000p1.
I'm sure some aging PDP-11 hacker will give you a hard time about "big endian" and "little endian" not being the only two possibilities.
Edit Ok, example of checking for qNaN on platforms that use IEEE-754's recommended encoding:
if (exponent == 0xff && mantissa & 0x00400000) printf("\nqNaN");
Related
How can i calculate in C power of 2, without pow function?
For example, after keyboard input 4, the result to be 16?
I know that, for example, 2^5 can be typing similar like 2^1*2^5 (I don't know if this idea can help)
To calculate 2N in C, use 1 << N.
If this may exceed the value representable in an int, use (Type) 1 << N, where Type is the integer type you want to use, such as unsigned long or uint64_t.
<< is the left-shift operator. It moves bits “left” in the bits that represent a number. Since numbers are represented in binary, moving bits left increases the powers of 2 they represent. Thus, 12 represents 1, 102 represents 2, 1002 represents 4, and so on, so 1 shifted left N positions represents 2N.
Numbers can be represented in binary form. For example, if integers are stored using 32 bits, 1 is stored like this:
00000000 00000000 00000000 00000001
And the value is the result of 1 x (20)
If you do a left-shift operation your value will be stored as this:
00000000 00000000 00000000 00000010
That means that now the result is result of 1 x (21)
Bit used to store a type is sizeof(type)x8, because a byte is 8 bit.
So best method is to use shift:
The left-shift of 1 by exp is equivalent to 2 raised to exp.
Shift operators must not be used for negative exponents in case of pow. The result is an undefined behaviour.
Another case of undefined behavior is the one of shifting the number equal to or more than N, in case of that number is stored in N bits.
#include <stdio.h>
#include <stdlib.h>
int main() {
int exp;
printf("Please, insert exponent:\n");
if (scanf("%d", &exp) != 1) {
printf("ERROR: scanf\n");
exit(EXIT_FAILURE);
}
if (exp < 0) {
printf("ERROR: exponent must be >= 0\n");
exit(EXIT_FAILURE);
}
printf("2^(%d) = %d\n", exp, 1 << exp);
exit(EXIT_SUCCESS);
}
You can also do it creating a ricorsive function (int) -> int:
int my_pow(int exp) {
If (exp < 0 ) {
return -1;
}
if (exp == 0) {
return 1;
}
if (exp > 0) {
return 2 * my_pow(exp-1);
}
}
Using it as main:
int main() {
int exp;
scanf("%d" &exp);
int res = my_pow(exp);
if (res == -1) {
printf("ERROR: Exponent must be equal or bigger than 0\n");
exit(EXIT_FAILURE);
}
printf("2^(%d) = %d", exp, res);
return 0;
}
So have a signed decimal number that can be represented with 16 bits, in a char*. I want to have a char* of that number in 2s compliment binary. So I want to go from "-42" to "1111111111010110" (note all 16 bits are shown) in C. Is there a quick and dirty way to do this? Some library function perhaps? Or do I have to crank out a large-ish function myself to do this?
I'm aware that strtol() may be of some use.
There isn't a standard library function that can generate binary strings as you describe.
However it is not particularly difficult to do.
#include <stdio.h>
#include <stdint.h>
#include <ctype.h>
int main(int argc, char ** argv)
{
while(--argc >= 0 && ++argv && *argv){
char const * input = *argv;
if(! input)
continue;
uint32_t value = 0;
char negative = 0;
for(; *input; input++){
if (isdigit(*input))
value = value * 10 + (*input -'0');
else if (*input == '-' && value == 0)
negative = 1;
else {
printf("Error: unexpected character: %c at %d\n", *input, (int)(input - *argv));
continue; // this function doesn't handle floats, or hex
}
}
if (value > 0x7fff + negative){
printf("Error: value too large for 16bit integer: %d %x\n", value, value);
continue; // can't be represented in 16 bits
}
int16_t result = value;
if (negative)
result = -value;
for (int i=1; i <= 16; i++)
printf("%d", 0 != (result & 1 << (16-i)) );
printf("\n");
}
}
That function handles all valid 16 bit values and leverages the fact that the architecture stores integers as two's complement values. I'm not aware of an architecture that doesn't, so it's a fairly reasonable assumption.
Note that two's complement INT_MIN != -1 * INT_MAX.
This is handled by adding the negative flag to the validity check before conversion from unsigned 32bit to signed 16bit.
./foo 1 -1 2 -2 42 -42 32767 -32767 32768 -32768
0000000000000001
1111111111111111
0000000000000010
1111111111111110
0000000000101010
1111111111010110
0111111111111111
1000000000000001
Error: value too large for 16bit integer: 32768 8000
1000000000000000
I am having issues finding the biased exponent from a floating point number. I do not understand why I return a 0 from any number that I enter for the parameter. Here is my code:
iFloat_t floatGetExp(iFloat_t x)
{
return ((x >> 23) & 0x7f800000);
}
The exponent of a float is from bits to 23-30, so that is why I am shifting to the right by 23 and have a mask of 0x7f800000.
For example, if I passed it a float of 248.875, the exponent should be 22.
((x >> 23) & 0x7f800000); is shift and masking in the wrong order.
The math library, C has a function that retrieves the exponent. This is the portable way.
int floatGetExp(float x) {
int expo;
frexpf(x, &expo); // fetch exponent (0.5 <= significand < 1.0) * 2^expo
if (x) expo -= 1;
return expo;
}
Assuming binary32 format for iFloat_t x there are 4 cases to consider:
Infinity/NaN, normal numbers, sub-normals, zero.
iFloat_t floatGetExp(iFloat_t x) {
uint32_t u = (uint32_t) x; // move into known type
// mask off the biased exponent
int bias_expo = (u & 0x7F800000) >> 23;
if (bias_exp == 0xFF) return TBD; // inf or NaN
if (bias_exp > 0) return bias_exp - 127; // the usual
// handle sub-normal numbers
if (u & 0x7FFFFFFF == 0) return 0; // zero
bias_exp -= 126;
while (u & 0x00400000 == 0) {
u <<= 1;
bias_exp--;
}
return bias_exp;
}
I'm working on an assignment but I'm stuck. For some reason I can't get this outcome:
byte order: little-endian
> FFFFFFFF
0xFFFFFFFF
signBit 1, expBits 255, fractBits 0x007FFFFF
QNaN
> 3
0x00000003
signBit 0, expBits 0, fractBits 0x00000003
denormalized: exp = -126
> DEADBEEF
0xDEADBEEF
signBit 1, expBits 189, fractBits 0x002DBEEF
normalized: exp = 62
> deadbeef
0xDEADBEEF
signBit 1, expBits 189, fractBits 0x002DBEEF
normalized: exp = 62
> 0
0x00000000
signBit 0, expBits 0, fractBits 0x00000000
+zero
I have tried to solve this problem but I can't figure out where I went wrong. The following code is my attempt for this project. I feel that I'm nearing the end but I can't finish..
Here is my code:
#include <stdio.h>
#include <stdlib.h>
static char *studentName = "name";
// report whether machine is big or small endian
void bigOrSmallEndian()
{
int num = 1;
if(*(char *)&num == 1)
{
printf("\nbyte order: little-endian\n\n");
}
else
{
printf("\nbyte order: big-endian\n\n");
}
}
// get next int (entered in hex) using scanf()
// returns 1 (success) or 0 (failure)
// if call succeeded, return int value via i pointer
int getNextHexInt(int *i)
{
// replace this code with the call to scanf()
//*i = 0;
//return 1;
scanf ("%x", i);
return 1;
}
// print requested data for the given number
void printNumberData(int i)
{
//printf("%x %0#10x\n",i,*(int *)&i);
int tru_exp =0;
//int stored_exp;
int negative;
int exponent;
int mantissa;
printf("\n>");
printf("\n0x%08X",i);
negative = !!(i & 0x80000000);
exponent = (i & 0x7f800000) >> 23;
mantissa = (i & 0x007FFFFF);
printf("\nsignBit %d, ", negative);
printf("expbits %d, ", exponent);
printf("fractbits 0x%08X", mantissa);
// "%#010x, ", mantissa);
if(exponent == 0)
{
if(mantissa != 0)
{
printf("\ndenormalized ");
}
}
else{
printf("\nnormalized: ");
tru_exp = exponent - 127;
printf("exp = %d", tru_exp);
}
if(exponent == 0 && mantissa == 0 && negative == 1)
{
printf("\n-zero");
}
if(exponent ==0 && mantissa == 0 && negative == 0)
{
printf("\n+zero");
}
if(exponent == 255 && mantissa != 0 && negative == 1)
{
printf("\nQNaN");
}
if(exponent == 255 && mantissa != 0 && negative == 0)
{
printf("\nSNaN");
}
if(exponent == 0xff && mantissa == 0 && negative == 1)
{
printf("\n-infinity");
}
if(exponent == 0xff && mantissa == 0 && negative == 0)
{
printf("\n+infinity");
}
printf("\n");
while(i != 0)
break;
}
// do not change this function in any way
int main(int argc, char **argv)
{
int i; // number currently being analyzed
int nValues; // number of values successfully parsed by scanf
printf("CS201 - A01p - %s\n\n", studentName);
bigOrSmallEndian();
for (;;) {
if (argc == 1) // allow grading script to control ...
printf("> "); // ... whether prompt character is printed
nValues = getNextHexInt(&i);
printf("0x%08X\n", i);
if (! nValues) { // encountered bad input
printf("bad input\n");
while (getchar() != '\n') ; // flush bad line from input buffer
continue;
}
printNumberData(i);
if (i == 0)
break;
}
printf("\n");
return 0;
}
My outcome for this code is:
byte order: little-endian
> FFFFFFFF
0xFFFFFFFF
>
0xFFFFFFFF
signBit 1, expbits 255, fractbits 0x007FFFFF
normalized: exp = 128
QNaN
> 3
0x00000003
>
0x00000003
signBit 0, expbits 0, fractbits 0x00000003
denormalized
> DEADBEEF
0xDEADBEEF
>
0xDEADBEEF
signBit 1, expbits 189, fractbits 0x002DBEEF
normalized: exp = 62
> deadbeef
0xDEADBEEF
>
0xDEADBEEF
signBit 1, expbits 189, fractbits 0x002DBEEF
normalized: exp = 62
> 0
0x00000000
>
0x00000000
signBit 0, expbits 0, fractbits 0x00000000
+zero
I believe the problem lies in printNumberData() but I can't point where.
I hope someone can pitch in because any help is greatly appreciated.
So, the only problem, as far as I see, is that your exponent isn't signed. You can fix that by changing tru_exp into a int8_t (or signed char). Or by simply sign-extending the number manually, e.g. if (tru_exp > 128) tru_exp -= 256;
You have a series of if statements which identify special cases (zeroes, infinities, NaNs), but you identify those after you've done some processing of 'normal' values. You should use an if / else if / else if chain instead, and deal with the special cases first, with the final else handling all the regular (normalized) numbers.
Here's some code based on what you provided, but the formatting and coding is considerably condensed. The main program here avoids input, and covers the gamut of values, I believe. When this is producing the correct data, you can futz with the formatting to suit the teacher's testing harness.
#include <stdio.h>
extern void printNumberData(int i);
void printNumberData(int i)
{
int negative = (i & 0x80000000U) >> 31;
int exponent = (i & 0x7F800000U) >> 23;
int mantissa = (i & 0x007FFFFFU) >> 0;;
printf("0x%08X sign %d, exponent %3d, fraction 0x%08X: ",
i, negative, exponent, mantissa);
if (exponent == 0x00 && mantissa == 0 && negative == 1)
printf("-zero\n");
else if (exponent == 0x00 && mantissa == 0 && negative == 0)
printf("+zero\n");
else if (exponent == 0xFF && mantissa != 0 && negative == 1)
printf("QNaN\n");
else if (exponent == 0xFF && mantissa != 0 && negative == 0)
printf("SNaN\n");
else if (exponent == 0xFF && mantissa == 0 && negative == 1)
printf("-infinity\n");
else if (exponent == 0xFF && mantissa == 0 && negative == 0)
printf("+infinity\n");
else if (exponent == 0)
printf("denormalized: exp = -126\n");
else
printf("normalized: exp = %4d\n", exponent - 127);
}
int main(void)
{
printNumberData(0xFFFFFFFF); /* QNan */
printNumberData(0x00000003); /* Denorm */
printNumberData(0x00800003); /* Normal */
printNumberData(0xDEADBEEF); /* Normal */
printNumberData(0x00000000); /* +0 */
printNumberData(0x80000000); /* -0 */
printNumberData(0xFF800000); /* +Inf */
printNumberData(0x7F800000); /* -Inf */
printNumberData(0xFF800001); /* QNan */
printNumberData(0x7F800001); /* SNan */
return(0);
}
It produces one line of output per number:
0xFFFFFFFF sign 1, exponent 255, fraction 0x007FFFFF: QNaN
0x00000003 sign 0, exponent 0, fraction 0x00000003: denormalized: exp = -126
0x00800003 sign 0, exponent 1, fraction 0x00000003: normalized: exp = -126
0xDEADBEEF sign 1, exponent 189, fraction 0x002DBEEF: normalized: exp = 62
0x00000000 sign 0, exponent 0, fraction 0x00000000: +zero
0x80000000 sign 1, exponent 0, fraction 0x00000000: -zero
0xFF800000 sign 1, exponent 255, fraction 0x00000000: -infinity
0x7F800000 sign 0, exponent 255, fraction 0x00000000: +infinity
0xFF800001 sign 1, exponent 255, fraction 0x00000001: QNaN
0x7F800001 sign 0, exponent 255, fraction 0x00000001: SNaN
If you read the Wikipedia page on Single-precision floating point format, you get an explanation of sorts about denormalized numbers having an adjusted exponent of -126 even though the value of the exponent bits is 0 and 0-127 is normally -127. Basically, it is simply stated by fiat that the exponent is -126 and underflow is occurring.
Other related pages do mention it, but somewhat more 'in passing':
IEEE 754:1985
IEEE 754 revision
Double-precision floating pointformat
Half-precision floating point format
Now, here is the function header of the function I'm supposed to implement:
/*
* 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) {
...
}
We aren't allowed to do float operations, or any kind of casting.
Now I tried to implement the first algorithm given at this site: http://locklessinc.com/articles/i2f/
Here's my code:
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;
}
But it didn't work (see test error below):
ERROR: Test float_from_int(8388608[0x800000]) failed...
...Gives 0[0x0]. Should be 1258291200[0x4b000000]
I don't know where to go from here. How should I go about parsing the float from this int?
EDIT #1:
You might be able to see from my code that I also started working on this algorithm (see this site):
I assumed 10-bit, 2’s complement, integers since the mantissa is only
9 bits, but the process generalizes to more bits.
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.
But, that doesn't seem right. How could I convert 0x80000000? Doesn't make sense.
EDIT #2:
I think it's because I say max bits is 15... hmmm...
EDIT #3: Screw that old algorithm, I'm starting over:
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;
Here's the error I get on this one (I think I got past the last error):
ERROR: Test float_from_int(-2139095040[0x80800000]) failed...
...Gives -889192448[0xcb000000]. Should be -822149120[0xceff0000]
May be helpful to know that:
absValOfX = 7f800000
(using printf)
EDIT #4: Ah, I'm finding the exponent wrong, need to count from the left, then subtract from 32 I believe.
EDIT #5: I started over, now trying to deal with weird rounding problems...
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]
EDIT #6
Did it again, still, the rounding doesn't work properly. I've tried to hack together some rounding, but it just won't work...
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;
The problem is that the lowest int is -2147483648, but the highest is 2147483647, so there is no absolute value of -2147483648. While you could work around it, I would just make a special case for that one bit pattern (like you do for 0):
if (x == 0)
return 0;
if (x == -2147483648)
return 0xcf000000;
The other problem is that you copied an algorithm that only works for numbers from 0 to 32767. Further down in the article they explain how to expand it to all ints, but it uses operations that you're likely not allowed to use.
I would recommend writing it from scratch based on the algorithm mentioned in your edit. Here's a version in C# that rounds towards 0:
uint float_from_int(int x)
{
if (x == 0)
return 0; // 0 is a special case because it has no 1 bits
// Save the sign bit of the input and take the absolute value of the input.
uint signBit = 0;
uint absX = (uint)x;
if (x < 0)
{
signBit = 0x80000000u;
absX = (uint)-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.
uint exponent = 158;
while ((absX & 0x80000000) == 0)
{
exponent--;
absX <<= 1;
}
// compute mantissa
uint mantissa = absX >> 8;
// Assemble the float from the sign, mantissa, and exponent.
return signBit | (exponent << 23) | (mantissa & 0x7fffff);
}
The basic formulation of the algorithm is to determine the sign, exponent and mantissa bits, then pack the result into an integer. Breaking it down this way makes it easy to clearly separate the tasks in code and makes solving the problem (and testing your algorithm) much easier.
The sign bit is the easiest, and getting rid of it makes finding the exponent easier. You can distinguish four cases: 0, 0x80000000, [-0x7ffffff, -1], and [1, 0x7fffffff]. The first two are special cases, and you can trivially get the sign bit in the last two cases (and the absolute value of the input). If you're going to cast to unsigned, you can get away with not special-casing 0x80000000 as I mentioned in a comment.
Next up, find the exponent -- there's an easy (and costly) looping way, and a trickier but faster way to do this. My absolute favourite page for this is Sean Anderson's bit hacks page. One of the algorithms shows a very quick loop-less way to find the log2 of an integer in only seven operations.
Once you know the exponent, then finding the mantissa is easy. You just drop the leading one bit, then shift the result either left or right depending on the exponent's value.
If you use the fast log2 algorithm, you can probably end up with an algorithm which uses no more than 20 operations.
Dealing with 0x80000000 is pretty easy:
int xIsNegative = 0;
unsigned int absValOfX = x;
if (x < 0)
{
xIsNegative = 1;
absValOfX = -(unsigned int)x;
}
It gets rid of special casing -2147483648 since that value is representable as an unsigned value, and absValOfX should always be positive.