Add IEEE 754 pack and unpack helpers
authorJens Axboe <axboe@kernel.dk>
Wed, 5 Oct 2011 06:43:47 +0000 (08:43 +0200)
committerJens Axboe <axboe@kernel.dk>
Wed, 5 Oct 2011 06:43:47 +0000 (08:43 +0200)
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Makefile
ieee754.c [new file with mode: 0644]
ieee754.h [new file with mode: 0644]

index c89bb1737b62eb09cc83ba686fafced2775b7159..b361603beac626a3b921550adf22ff7eb8638841 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ SOURCE = gettime.c fio.c ioengines.c init.c stat.c log.c time.c filesetup.c \
                rbtree.c smalloc.c filehash.c profile.c debug.c lib/rand.c \
                lib/num2str.c $(wildcard crc/*.c) engines/cpu.c \
                engines/mmap.c engines/sync.c engines/null.c engines/net.c \
-               memalign.c server.c client.c iolog.c
+               memalign.c server.c client.c iolog.c ieee754.c
 
 ifeq ($(UNAME), Linux)
   SOURCE += diskutil.c fifo.c blktrace.c helpers.c cgroup.c trim.c \
diff --git a/ieee754.c b/ieee754.c
new file mode 100644 (file)
index 0000000..0fbc7f0
--- /dev/null
+++ b/ieee754.c
@@ -0,0 +1,83 @@
+/*
+ * Shamelessly lifted from Beej's Guide to Network Programming, found here:
+ *
+ * http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#serialization
+ *
+ * Below code was granted to the public domain.
+ */
+#include <inttypes.h>
+
+uint64_t pack754(long double f, unsigned bits, unsigned expbits)
+{
+       long double fnorm;
+       int shift;
+       long long sign, exp, significand;
+       unsigned significandbits = bits - expbits - 1; // -1 for sign bit
+
+       // get this special case out of the way
+       if (f == 0.0)
+               return 0;
+
+       // check sign and begin normalization
+       if (f < 0) {
+               sign = 1;
+               fnorm = -f;
+       } else {
+               sign = 0;
+               fnorm = f;
+       }
+
+       // get the normalized form of f and track the exponent
+       shift = 0;
+       while (fnorm >= 2.0) {
+               fnorm /= 2.0;
+               shift++;
+       }
+       while (fnorm < 1.0) {
+               fnorm *= 2.0;
+               shift--;
+       }
+       fnorm = fnorm - 1.0;
+
+       // calculate the binary form (non-float) of the significand data
+       significand = fnorm * ((1LL << significandbits) + 0.5f);
+
+       // get the biased exponent
+       exp = shift + ((1 << (expbits - 1)) - 1); // shift + bias
+
+       // return the final answer
+       return (sign << (bits - 1)) | (exp << (bits-expbits - 1)) | significand;
+}
+
+long double unpack754(uint64_t i, unsigned bits, unsigned expbits)
+{
+       long double result;
+       long long shift;
+       unsigned bias;
+       unsigned significandbits = bits - expbits - 1; // -1 for sign bit
+
+       if (i == 0)
+               return 0.0;
+
+       // pull the significand
+       result = (i & ((1LL << significandbits) - 1)); // mask
+       result /= (1LL << significandbits); // convert back to float
+       result += 1.0f; // add the one back on
+
+       // deal with the exponent
+       bias = (1 << (expbits - 1)) - 1;
+       shift = ((i >> significandbits) & ((1LL << expbits) - 1)) - bias;
+       while (shift > 0) {
+               result *= 2.0;
+               shift--;
+       }
+       while (shift < 0) {
+               result /= 2.0;
+               shift++;
+       }
+
+       // sign it
+       result *= (i >> (bits - 1)) & 1 ? -1.0 : 1.0;
+
+       return result;
+}
diff --git a/ieee754.h b/ieee754.h
new file mode 100644 (file)
index 0000000..2087da5
--- /dev/null
+++ b/ieee754.h
@@ -0,0 +1,10 @@
+#ifndef FIO_IEEE754_H
+#define FIO_IEEE754_H
+
+extern uint64_t pack754(long double f, unsigned bits, unsigned expbits);
+extern long double unpack754(uint64_t i, unsigned bits, unsigned expbits);
+
+#define fio_double_to_uint64(val)      pack754((val), 64, 11)
+#define fio_uint64_to_double(val)      unpack754((val), 64, 11)
+
+#endif