From: Jens Axboe Date: Wed, 5 Oct 2011 06:43:47 +0000 (+0200) Subject: Add IEEE 754 pack and unpack helpers X-Git-Tag: fio-1.99~8 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=90f326d04602d0df35ca32f251dd6cc353d26a25;ds=sidebyside Add IEEE 754 pack and unpack helpers Signed-off-by: Jens Axboe --- diff --git a/Makefile b/Makefile index c89bb173..b361603b 100644 --- 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 index 00000000..0fbc7f0e --- /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 + +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 index 00000000..2087da5e --- /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