Skip to content

Instantly share code, notes, and snippets.

@nolash
Created June 3, 2017 14:10
Show Gist options
  • Save nolash/bea7c1eceefe3d7f5163a4a9bcd33fc0 to your computer and use it in GitHub Desktop.
Save nolash/bea7c1eceefe3d7f5163a4a9bcd33fc0 to your computer and use it in GitHub Desktop.
Deconstructing and reconstructing a IEEE 754 float
#include <stdio.h>
#include <limits.h>
#include <math.h>
float simple(float n, int ii) {
printf("simple original float: %f %x\n", n, *((unsigned int*)&n));
float a = (float)(int)n;
float b = n - a;
float c = (float)ii + b;
printf("simple generated float: %f %x\n", c, *((unsigned int*)&n));
return c;
}
float handmade(float n, int ii) {
int i;
int ee;
char s;
int intbytes = (sizeof(int) * 8);
// cast to access using bitwise operations
unsigned int *c = (unsigned int *)&n;
unsigned int e;
printf("handmade original float: %f %x\n", n, *c);
// first bit is sign of float
s = *c & 0x80;
// byte-align exponent and mantissa
*c <<= 1;
// extract and unbias exponent value
e = *c >> (intbytes - 8);
e -= 127;
// align mantissa to byte int start
*c <<= 8;
// adjust mask to significand's exponent boundary and invert
i = *c & ~(INT_MAX >> (e - 1));
i >>= intbytes - e;
i |= 1 << e;
// now align fractional part
*c <<= e;
// get the logarithm of the replacement int
ee = (int)log2(ii);
// shift to align the significand to its place in the float
*c >>= ee;
ii <<= intbytes - ee;
*c |= ii;
// add the bias
ee += 127;
// align float to exponent int
*c >>= 8;
ee <<= intbytes - 8;
*c |= ee;
// shift to add the sign
*c >>= 1;
// todo: handle sign
printf("handmade generated float: %f %x\n", *(float*)c, *c);
return i;
}
int main() {
float n = 21.9375;
simple(n, 32);
handmade(n, 32);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment