Home | History | Annotate | Download | only in lib
      1 /*
      2  * Shamelessly lifted from Beej's Guide to Network Programming, found here:
      3  *
      4  * http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#serialization
      5  *
      6  * Below code was granted to the public domain.
      7  */
      8 #include <inttypes.h>
      9 #include "ieee754.h"
     10 
     11 uint64_t pack754(long double f, unsigned bits, unsigned expbits)
     12 {
     13 	long double fnorm;
     14 	int shift;
     15 	long long sign, exp, significand;
     16 	unsigned significandbits = bits - expbits - 1; // -1 for sign bit
     17 
     18 	// get this special case out of the way
     19 	if (f == 0.0)
     20 		return 0;
     21 
     22 	// check sign and begin normalization
     23 	if (f < 0) {
     24 		sign = 1;
     25 		fnorm = -f;
     26 	} else {
     27 		sign = 0;
     28 		fnorm = f;
     29 	}
     30 
     31 	// get the normalized form of f and track the exponent
     32 	shift = 0;
     33 	while (fnorm >= 2.0) {
     34 		fnorm /= 2.0;
     35 		shift++;
     36 	}
     37 	while (fnorm < 1.0) {
     38 		fnorm *= 2.0;
     39 		shift--;
     40 	}
     41 	fnorm = fnorm - 1.0;
     42 
     43 	// calculate the binary form (non-float) of the significand data
     44 	significand = fnorm * ((1LL << significandbits) + 0.5f);
     45 
     46 	// get the biased exponent
     47 	exp = shift + ((1 << (expbits - 1)) - 1); // shift + bias
     48 
     49 	// return the final answer
     50 	return (sign << (bits - 1)) | (exp << (bits-expbits - 1)) | significand;
     51 }
     52 
     53 long double unpack754(uint64_t i, unsigned bits, unsigned expbits)
     54 {
     55 	long double result;
     56 	long long shift;
     57 	unsigned bias;
     58 	unsigned significandbits = bits - expbits - 1; // -1 for sign bit
     59 
     60 	if (i == 0)
     61 		return 0.0;
     62 
     63 	// pull the significand
     64 	result = (i & ((1LL << significandbits) - 1)); // mask
     65 	result /= (1LL << significandbits); // convert back to float
     66 	result += 1.0f; // add the one back on
     67 
     68 	// deal with the exponent
     69 	bias = (1 << (expbits - 1)) - 1;
     70 	shift = ((i >> significandbits) & ((1LL << expbits) - 1)) - bias;
     71 	while (shift > 0) {
     72 		result *= 2.0;
     73 		shift--;
     74 	}
     75 	while (shift < 0) {
     76 		result /= 2.0;
     77 		shift++;
     78 	}
     79 
     80 	// sign it
     81 	result *= (i >> (bits - 1)) & 1 ? -1.0 : 1.0;
     82 
     83 	return result;
     84 }
     85