2

I have a weird requirement,
My destination only supports one integer, But I want to send two integers to it and later I want to get them back from a response.

for example,

allowed input:

 {
    'task': 2
 }

I have subtask kind of a logic in my side, But my target is not aware of this. So, without letting know the target, can I somehow pack two integers and get decode them back in future?

Can this be achieved with hexadecimal?

Shailendra Sharma
  • 6,976
  • 2
  • 28
  • 48
Jithesh Kt
  • 2,023
  • 6
  • 32
  • 48
  • Your need to convert your integer to Hexadecimal right? – Kiran Joshi Aug 10 '18 at 05:17
  • Possible duplicate of [How can I convert an integer to hex with a fix length in Javascript?](https://stackoverflow.com/questions/42368797/how-can-i-convert-an-integer-to-hex-with-a-fix-length-in-javascript) – Kiran Joshi Aug 10 '18 at 05:19
  • There are two things in your question. (1) Storing two numbers in a single integer variable. (2) Hexadecimal representation of numbers. This has nothing to do with (1). Now it is unclear to me, how (1) and (2) relate to one another in your question. – Krisztián Balla Aug 10 '18 at 06:24

4 Answers4

3

You can combine any two numbers and get both numbers back using their product (a * b) as long as a * (a * b) + b < Number.MAX_SAFE_INTEGER

Here's a demo snippet:

(() => {
  document.addEventListener("click", handleStuff);
  // formula: c = (a * (a * b)) + b
  // as long as c < 9007199254740991
  const combine = (a, b) => ({
      a: a, 
      b: b,
      get c() { return this.a * this.b; },
      get combined() { return this.a * this.c + this.b; },
      get unraveled() { return [
        Math.floor(this.combined / this.c), 
        this.combined % this.c ]; }
  });
  const log = txt => document.querySelector("pre").textContent = txt;
  let numbers = combine(
    +document.querySelector("#num1").value, 
    +document.querySelector("#num2").value );

  function handleStuff(evt) {
    if (evt.target.nodeName.toLowerCase() === "button") {
      if (evt.target.id === "combine") {
        numbers = combine(
          +document.querySelector("#num1").value, 
          +document.querySelector("#num2").value );
        if (numbers.combined > Number.MAX_SAFE_INTEGER) {
          log (`${numbers.combined} too large, unraveled will be unreliable`);
        } else {
          log (`Combined ${numbers.a} and ${numbers.b} to ${numbers.combined}`);
        }
      } else {
        log(`${numbers.combined} unraveled to ${numbers.unraveled}`);
      }
    }
  }

})();
input[type=number] {width: 100px;}
<p>
  <input type="number" id="num1" 
    value="12315" min="1"> first number
</p>
<p>
  <input type="number" id="num2" 
    value="231091" min="1"> second number
</p>
<p>
  <button id="combine">combine</button>
  <button id="unravel">unravel</button>
</p>

<pre id="result"></pre>

Note: @RallFriedl inspired this answer

JSFiddle

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
KooiInc
  • 119,216
  • 31
  • 141
  • 177
2

Yes, you can, assuming your two integers don't contain more information than the one integer can handle.

Let's assume your tasks and sub tasks are in the range 1..255. Then you can encode

combined = (task * 256) + subtask

And decode

task = combined / 256
subtask = combined % 256
RalfFriedl
  • 1,134
  • 3
  • 11
  • 12
2

At first, you don't have to convert an integer to hexadecimal to do this. An integer is a value and decimal, hexadecimal or binary is a representation to visualize that value. So all you need is integer arithmetics to achieve your goal.

According to this answer the maximum allowed integer number in javascript would be 9007199254740991. If you write this down in binary you'll get 53 ones, which means there are 53 bits available to store within an integer. Now you can split up this into two or more smaller ranges as you need.

For example let's say you need to save three numbers, the first is always lower 4.294.967.296 (32-bit), the second always lower 65.536 (16-bit) and the third always lower 32 (5-bit). If you sum up all the bits of these three values, you'll get 53 bits which means it would perfectly match.

To pack all these values into one, all you need is to move them at the right bit position within the integer. In my example I'd like to let the 32 bit number on the lowest position, then the 16 bit number and at the highest position the 5 bit number:

var max32bitValue = 3832905829; // binary: 1110 0100 0111 0101 1000 0000 0110 0101
var max16bitValue = 47313;      // binary: 1011 1000 1101 0001
var max5bitValue = 17;          // binary: 1000 1

var packedValue = max32bitValue           // Position is at bit 0, so no movement needed.
                  + max16bitValue << 32   // Move it up next to the first number.
                  + max5bitValue << 48;    // Move it up next to the second number (32 + 16)

This single integer value can now be stored, cause is a perfectly valid javascript integer value, but for us it holds three values.

To get all three values out of the packed value, we have to pick the correct bits out of it. This involves two steps, first remove all unneeded bits on the lower side (by using shift right), then remove all unneeded bits on the higher side (by masking out):

var max32bitValueRead = packedValue & Math.pow(2, 32);         // No bits on the lower side, just mask the higher ones;
var max16bitValueRead = (packedValue >> 32) & Math.pow(2, 16); // Remove first 32 bits and set all bits higher then 16 bits to zero;
var max5bitValueRead = (packedValue >> 48);                    // Remove first 48 bits (32 + 16). No higher bits there, so no mask needed.

So hope this helps to understand, how to put multiple integer values into one, if the ranges of these values don't exceed the maximum bit range. Depending on your needs you could put two values with 26 bits each into this or move the range like one 32 bit value and one 21 bit value or a 48 bit value and a 5 bit value. Just be sure what your maximum value for each one could be and set the width accordingly (maybe add one to three bits, just to be sure).

Oliver
  • 43,366
  • 8
  • 94
  • 151
0

I wouldn't suggest using hexadecimal if you can not have 2 sequential numbers. Try converting to an ASCII character and then back. So if you wanted to send: { 'task': 21 } You could set the 21 to a character like: var a = 55; var b = String.fromCharCode(a); var send2 = { 'task': b };

And to convert it back it would be: var res = { 'task': b }; var original = res.task.charCodeAt();

Tim
  • 1,105
  • 13
  • 14