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 
pack754(long double f,unsigned bits,unsigned expbits)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 
unpack754(uint64_t i,unsigned bits,unsigned expbits)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