Pass two integers as one integer

11,333

Solution 1

Using the C programming language, it could be done as follows assuming that the two integers are less than 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 or 65535 in decimal

}


void pass2()
{
  int int1 = 345;
  int int2 = 2342;
  take2Integers( int1 | (int2 << 16) );
}

This relies on the fact that in C an integer is stored in 4 bytes. So, the example uses the first two bytes to store one of the integers, and the next two bytes for the second. This does impose the limit though that each of the integers must have a small enough value so that they will each fit into just 2 bytes.

The shift operators << and >> are used to slide the bits of an integer up and down. Shifting by 16, moves the bits by two bytes (as there are 8 bits per byte).

Using 0xFFFF represents the bit pattern where all of the bits in the lower two bytes of the number are 1s So, ANDing (with with & operator) causes all the bits that are not in these bottom two bytes to be switched off (back to zero). This can be used to remove any parts of the 'other integer' from the one you're currently extracting.

Solution 2

There are two parts to this question. First, how do you bitmask two 32-bit Integers into a 64-bit Long Integer?

As others have stated, 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) & 0xFFFFFFFF);
}

public int getY(long location) {
    return (int)(location & 0xFFFFFFFF);
}

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/

Solution 3

Well.. @Felice is right, but if they both fit in 16 bit there's a way:

output_int = (first_int << 16) | second_int
                               ^
                           means 'or'

to pack them, and

first_int = output_int & 0xffff
second_int = (output int >> 16) & 0xffff
                                ^
                           means 'and'

to extract them.

Solution 4

Two integer can't fit one integer, or at least you cant get back the two original one.
But anyway, if the two original integer are bounded to a sure number of bits you can ( in pseudocode ): First integer OR with (Second integer SHIFTLEFT(nOfBits))

for getting back the two integer mask the merged integer with a number that is binary represented by nOfBitsOne and you obtain the first integer, then ShiftRight by nOfBits the merged integer, and you have back the second.

Share:
11,333
Muhammad Hewedy
Author by

Muhammad Hewedy

Updated on June 05, 2022

Comments

  • Muhammad Hewedy
    Muhammad Hewedy almost 2 years

    I have two integers that I need to pass through one integer and then get the values of two integers back.

    I am thinking of using Logic Operators (AND, OR, XOR, etc) .