Here is how to store 2 integers in 1, taken off a site. It's programmed in C.
It can be modified to store 4 as 2. Only problem is that we have to assume that integers are less then 65535.
void take2IntegersAsOne(int x)
{
// int1 is stored in the bottom half of x, so take just that part.
int int1 = x & 0xFFFF;
// int2 is stored in the top half of x, so slide that part of the number
// into the bottom half, and take just that part.
int int2 = (x >> 16) & 0xFFFF
// use int1 and int2 here. They must both be less than 0xFFFF of 65535 in decimal
}
void pass2()
{
int int1 = 345;
int int2 = 2342;
take2Integers( int1 | (int2 << 16) );
}
Another solution:
Let's say I have a function that takes an X and Y coordinate, and returns a longint representing that Point's linear value. I tend to call this linearization of 2d data:
public long asLong(int x, int y) {
return ( ((long)x) << 32 ) | y;
}
public int getX(long location) {
return (int)((location >> 32) & 0xFF);
}
public int getY(long location) {
return (int)(location & 0xFF);
}
Forgive me if I'm paranoid about order of operations, sometimes other operations are greedier than <<, causing things to shift further than they should.
Why does this work? When might it fail? It's convenient that integers tend to be exactly half the size of longints. What we're doing is casting x to a long, shifting it left until it sits entirely to the left of y, and then doing a union operation (OR) to combine the bits of both.
Let's pretend they're 4-bit numbers being combined into an 8-bit number:
x = 14 : 1110
y = 5 : 0101
x = x << 4 : 1110 0000
p = x | y : 1110 0000
OR 0101
---------
1110 0101
Meanwhile, the reverse:
p = 229 : 1110 0101
x = p >> 4 : 1111 1110 //depending on your language and data type, sign extension
//can cause the bits to smear on the left side as they're
//shifted, as shown here. Doesn't happen in unsigned types
x = x & 0xF:
1111 1110
AND 0000 1111
-------------
0000 1110 //AND selects only the bits we have in common
y = p & 0xF:
1110 0101
AND 0000 1111
-------------
0000 0101 //AND strikes again
This sort of approach came into being a long time ago, in environments that needed to squeeze every bit out of their storage or transmission space. If you're not on an embedded system or immediately packing this data for transmission over a network, the practicality of this whole procedure starts to break down really rapidly:
It's way too much work just for boxing a return value that almost always immediately needs to be unboxed and read by the caller. That's kind of like digging a hole and then filling it in.
It greatly reduces your code readability. "What type is returned?" Uh... an int.. and another int... in a long.
It can introduce hard-to-trace bugs down the line. For instance, if you use unsigned types and ignore the sign extension, then later on migrate to a platform that causes those types to go two's complement. If you save off the longint, and try to read it later in another part of your code, you might hit an off-by-one error on the bitshift and spend an hour debugging your function only to find out it's the parameter that's wrong.
If it's so bad, what are the alternatives?
This is why people were asking you about your language. Ideally, if you're in something like C or C++, it'd be best to say
struct Point { int x; int y; };
public Point getPosition() {
struct Point result = { 14,5 };
return result;
}
Otherwise, in HLLs like Java, you might wind up with an inner class to achieve the same functionality:
public class Example { public class Point { public int x; public int y; public Point(int x, int y) { this.x=x; this.y=y; } }
public Point getPosition() {
return new Point(14,5);
}
In this case, getPosition returns an Example.Point - if you keep using Point often, promote it to a full class of its own. In fact, java.awt has several Point classes already, including Point and Point.Float
Finally, many modern languages now have syntactic sugar for either boxing multiple values into tuples or directly returning multiple values from a function. This is kind of a last resort. In my experience, any time you pretend that data isn't what it is, you wind up with problems down the line. But if your method absolutely must return two numbers that really aren't part of the same data at all, tuples or arrays are the way to go.
The reference for the c++ stdlib tuple can be found at
http://www.cplusplus.com/reference/std/tuple/