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"
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
18         // get this special case out of the way
19         if (f == 0.0)
20                 return 0;
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         }
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;
43         // calculate the binary form (non-float) of the significand data
44         significand = fnorm * ((1LL << significandbits) + 0.5f);
46         // get the biased exponent
47         exp = shift + ((1 << (expbits - 1)) - 1); // shift + bias
49         // return the final answer
50         return (sign << (bits - 1)) | (exp << (bits-expbits - 1)) | significand;
51 }
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
60         if (i == 0)
61                 return 0.0;
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
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         }
80         // sign it
81         result *= (i >> (bits - 1)) & 1 ? -1.0 : 1.0;
83         return result;
84 }