Last active
January 3, 2016 11:59
-
-
Save josiahcarlson/8459874 to your computer and use it in GitHub Desktop.
Pack large integers into doubles, and extract large integers from doubles.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
Written October 26, 2012 by Josiah Carlson | |
Released into the public domain. | |
I'm sure this has been done before, but I've not seen any code for it. | |
This code will take an integer with absolute value of up to 2**63-2**53 | |
and pack it losslessly into an IEEE 753 FP double, preserving sort order | |
by reusing the exponent field for high order bits. | |
Note that if you keep your values under 2**62, we only use standard fp | |
values (no denormals). | |
This was originally written to allow for sorting of integers > 2**52 | |
using Redis ZSETs without worrying about precision. | |
''' | |
import struct | |
_SHIFT = 2**52 | |
def bigint_to_float(v, safe=True): | |
unsafe = not safe | |
assert isinstance(v, (int, long)) | |
sign = -1 if v < 0 else 1 | |
v *= sign | |
if safe: | |
assert v < 2**62 | |
else: | |
# 2**63 - 2**53 | |
assert v < 0x7fe0000000000000 | |
exponent, mantissa = divmod(v, _SHIFT) | |
return sign * (_SHIFT + mantissa) * 2.0**(exponent-52-unsafe*1022) | |
def float_to_bigint(v, safe=True): | |
sign = -1 if v < 0 else 1 | |
v *= sign | |
safe = bool(safe) | |
data = struct.pack('>d', v).encode('hex') | |
exponent = int(data[:3], 16) | |
assert exponent < 2048 | |
return sign * (((exponent-1-safe*1022)<<52) + int(data[3:], 16)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment