I have 12 bytes saved as 24 HEX chars array, for example: "0123456789abcdef12345678" and I must storage this hex string as a lot of double variables (in time-series database). Yes, this is crazy, but in SaaS aplications, time to time it is normal that we need to do ridiculous workaround.
But… how to do it?
var input = "0123456789abcdef12345678"; // always 12 bytes input, but converted to 24 hex chars string by SaaS software on beginning of this script
var output1 = 0.0; // double - probably 8 bytes
var output2 = 0.0; // double - probably 8 bytes
var output3 = 0.0; // double - probably 8 bytes
// how to divide input variable into outputX variables?
I think it is possible to do it in 2 output's
variables, but I could use as many I need – if it helps but I think, 12 variables is not the most optimal choice.
And another, easier question: how to rollback this, and transform output's
variables back to input
variable?
Of course it has to be a lossless way. And of course, it should work in pure JavaScript – dynamic typing does not make this task any easier.
So… what is the most effective way to code and decode this?
2
Answers
You could put the bytes in an
Uint8Array
(of length 12), then use aFloat64Array
(of length 1.5) as a view on the same buffer, or aFloat32Array
(of length 3). However, interpreting arbitrary raw bytes as floats might end up withNaN
, which will probably not serialise nicely into your database and may return as a differentNaN
value.It’s much easier to use
Uint32
values instead, for which you don’t even need typed arrays. To get your hex string into three integers, just slice and parse them:Reversal is similarly simple, just convert the integers back to hex strings and concatenate them:
The format of a double involves a sign (1 bit), an exponent (11 bits) and a significand (53 bits, but the first is always a 1, so only 52 bits of data).
A byte is 8 bits. You want to save 12 bytes, so you need 96 bits. You want to do this in 2 doubles, so you have to find 48 bits per double. And you’d like it to be easy to work with.
One answer is that numbers that require at at most 53 binary digits of precision are represented exactly. So let
x = 1/2**48
then0*x, 1*x, ..., 2**48 * x
are all represented exactly. Which allows us to encode and decode 6 bytes per double using those numbers. Here is code to do that with an easy test so that you can verify that it actually works correctly.