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
11uint64_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
53long 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