Commit | Line | Data |
---|---|---|
90f326d0 JA |
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> | |
802ad4a8 | 9 | #include "ieee754.h" |
90f326d0 JA |
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 | } |