Imagine two positive integers A and B. I want to combine these two into a single integer C.
There can be no other integers D and E which combine to C. So combining
Although Stephan202's answer is the only truly general one, for integers in a bounded range you can do better. For example, if your range is 0..10,000, then you can do:
#define RANGE_MIN 0
#define RANGE_MAX 10000
unsigned int merge(unsigned int x, unsigned int y)
{
return (x * (RANGE_MAX - RANGE_MIN + 1)) + y;
}
void split(unsigned int v, unsigned int &x, unsigned int &y)
{
x = RANGE_MIN + (v / (RANGE_MAX - RANGE_MIN + 1));
y = RANGE_MIN + (v % (RANGE_MAX - RANGE_MIN + 1));
}
Results can fit in a single integer for a range up to the square root of the integer type's cardinality. This packs slightly more efficiently than Stephan202's more general method. It is also considerably simpler to decode; requiring no square roots, for starters :)
We can encode two numbers into one in O(1) space and O(N) time. Suppose you want to encode numbers in the range 0-9 into one, eg. 5 and 6. How to do it? Simple,
5*10 + 6 = 56.
5 can be obtained by doing 56/10
6 can be obtained by doing 56%10.
Even for two digit integer let's say 56 and 45, 56*100 + 45 = 5645. We can again obtain individual numbers by doing 5645/100 and 5645%100
But for an array of size n, eg. a = {4,0,2,1,3}, let's say we want to encode 3 and 4, so:
3 * 5 + 4 = 19 OR 3 + 5 * 4 = 23
3 :- 19 / 5 = 3 3 :- 23 % 5 = 3
4 :- 19 % 5 = 4 4 :- 23 / 5 = 4
Upon generalising it, we get
x * n + y OR x + n * y
But we also need to take care of the value we changed; so it ends up as
(x%n)*n + y OR x + n*(y%n)
You can obtain each number individually by dividing and finding mod of the resultant number.
The standard mathematical way for positive integers is to use the uniqueness of prime factorization.
f( x, y ) -> 2^x * 3^y
The downside is that the image tends to span quite a large range of integers so when it comes to expressing the mapping in a computer algorithm you may have issues with choosing an appropriate type for the result.
You could modify this to deal with negative x
and y
by encoding a flags with powers of 5 and 7 terms.
e.g.
f( x, y ) -> 2^|x| * 3^|y| * 5^(x<0) * 7^(y<0)
If you want more control such as allocate X bits for the first number and Y bits for the second number, you can use this code:
class NumsCombiner
{
int num_a_bits_size;
int num_b_bits_size;
int BitsExtract(int number, int k, int p)
{
return (((1 << k) - 1) & (number >> (p - 1)));
}
public:
NumsCombiner(int num_a_bits_size, int num_b_bits_size)
{
this->num_a_bits_size = num_a_bits_size;
this->num_b_bits_size = num_b_bits_size;
}
int StoreAB(int num_a, int num_b)
{
return (num_b << num_a_bits_size) | num_a;
}
int GetNumA(int bnum)
{
return BitsExtract(bnum, num_a_bits_size, 1);
}
int GetNumB(int bnum)
{
return BitsExtract(bnum, num_b_bits_size, num_a_bits_size + 1);
}
};
I use 32 bits in total. The idea here is that if you want for example that first number will be up to 10 bits and second number will be up to 12 bits, you can do this:
NumsCombiner nums_mapper(10/*bits for first number*/, 12/*bits for second number*/);
Now you can store in num_a
the maximum number that is 2^10 - 1 = 1023
and in num_b
naximum value of 2^12 - 1 = 4095
.
To set value for num A and num B:
int bnum = nums_mapper.StoreAB(10/*value for a*/, 12 /*value from b*/);
Now bnum
is all of the bits (32 bits in total. You can modify the code to use 64 bits)
To get num a:
int a = nums_mapper.GetNumA(bnum);
To get num b:
int b = nums_mapper.GetNumB(bnum);
EDIT:
bnum
can be stored inside the class. I did not did it because my own needs
I shared the code and hope that it will be helpful.
Thanks for source:
https://www.geeksforgeeks.org/extract-k-bits-given-position-number/
for function to extract bits and thanks also to mouviciel
answer in this post.
Using these to sources I could figure out more advanced solution
Is this even possible?
You are combining two integers. They both have the range -2,147,483,648 to 2,147,483,647 but you will only take the positives.
That makes 2147483647^2 = 4,61169E+18 combinations.
Since each combination has to be unique AND result in an integer, you'll need some kind of magical integer that can contain this amount of numbers.
Or is my logic flawed?
How about something much simpler: Given two numbers, A and B let str be the concatenation: 'A' + ';' + 'B'. Then let the output be hash(str). I know that this is not a mathematical answer, but a simple python (which has an in built hash function) script should do the job.