Передайте два целых числа в виде одного целого числа

У меня есть два целых числа, которые мне нужно передать через одно целое, а затем вернуть значения двух целых чисел.

Я имею в виду использование логических операторов (AND, OR, XOR и т.д.).

Ответ 1

Используя язык программирования C, это можно сделать следующим образом, предполагая, что два целых числа меньше 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) );
}

Это зависит от того, что в C целое число хранится в 4 байта. Итак, пример использует первые два байта для хранения одного из целых чисел, а следующие два байта для второго. Это налагает ограничение, хотя каждый из целых чисел должен иметь достаточно малое значение, чтобы каждый из них вписывался в 2 байта.

Операторы сдвига < < и → используются для сдвига битов целого числа вверх и вниз. Сдвиг на 16, перемещает биты на два байта (как есть 8 бит на байт).

Использование 0xFFFF представляет бит-шаблон, где все биты в младших двух байтах числа равны 1s. Итак, ANDing (с оператором with и operator) заставляет все биты, которые не находятся в этих нижних двух байтах, отключить ( обратно к нулю). Это можно использовать для удаления любых частей "другого целого" из того, которое вы в настоящее время извлекаете.

Ответ 2

Есть две части этого вопроса. Во-первых, как вы можете маскаровать два 32-битных целых числа в 64-битное длинное целое?

Как утверждали другие, скажем, у меня есть функция, которая принимает координату X и Y и возвращает longint, представляющий линейное значение Point. Я склонен назвать эту линеаризацию данных 2d:

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);
}

Простите меня, если я параноик по порядку операций, иногда другие операции более жадны, чем < < < <, заставляющие вещи сдвигаться дальше, чем они должны.

Почему это работает? Когда это может произойти? Удобно, что целые числа имеют ровно половину размера longints. То, что мы делаем, - это отбрасывание x до длинного, сдвигающее его до тех пор, пока оно не останется полностью слева от y, а затем выполнит операцию объединения (OR), чтобы объединить бит обоих.

Предположим, что они представляют собой 4-битные числа, которые объединяются в 8-битное число:

x = 14     :      1110
y =  5     :      0101

x = x << 4 : 1110 0000

p = x | y  : 1110 0000
           OR     0101
             ---------
             1110 0101

Между тем, наоборот:

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

Такой подход возник очень давно, в средах, которые должны были выжать каждый бит из пространства для хранения или передачи. Если вы не находитесь в встроенной системе или не сразу упаковываете эти данные для передачи по сети, практичность всей этой процедуры начинает быстро разрушаться:

  • Это слишком много работает только для бокса возвращаемого значения, которое почти всегда нужно немедленно распаковать и прочитать вызывающим. Такой вид, как копать яму и затем заполнять ее.
  • Это значительно снижает читаемость кода. "Какой тип возвращается?" Uh... int.. и еще int... в длинном.
  • Он может вводить жесткие следы ошибок по строке. Например, если вы используете неподписанные типы и игнорируете расширение знака, а затем переходите на платформу, которая заставляет эти типы перейти на два дополнения. Если вы сберете longint и попытаетесь прочитать его позже в другой части вашего кода, вы можете нанести ошибку "один за другим" в битрейде и потратить час на отладку своей функции, чтобы узнать ее неверный параметр.

Если это так плохо, какие альтернативы?

Вот почему люди спрашивали вас о вашем языке. В идеале, если вы похожи на C или С++, было бы лучше сказать

struct Point { int x; int y; };

public Point getPosition() {
    struct Point result = { 14,5 };
    return result;
}

В противном случае в HLL, таких как Java, вы можете завершить свой внутренний класс для достижения той же функциональности:

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);
    }
}

В этом случае getPosition возвращает Example.Point - если вы часто используете Point, продвигайте его до полного класса. Фактически, java.awt уже имеет несколько классов Point, включая Point и Point.Float

Наконец, многие современные языки теперь имеют синтаксический сахар для бокса в несколько значений в кортежи или прямое возвращение нескольких значений из функции. Это отчасти последнее средство. По моему опыту, в любое время, когда вы притворяетесь, что данные не то, что есть, вы заканчиваете проблемы с линии. Но если ваш метод абсолютно должен возвращать два числа, которые действительно не являются частью одних и тех же данных, кортежи или массивы - это путь.

Ссылка на С++ stdlib кортеж можно найти по адресу http://www.cplusplus.com/reference/std/tuple/

Ответ 3

Хорошо.. @Felice прав, но если они оба подходят в 16 бит, то есть способ:

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

чтобы упаковать их, и

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

чтобы извлечь их.

Ответ 4

Два целых числа не могут соответствовать одному целому числу, или, по крайней мере, вы не можете вернуть два исходных.
Но в любом случае, если два исходных целых числа ограничены определенным количеством битов, которое вы можете (в псевдокоде): Первое целое число ИЛИ с (Второе целое число SHIFTLEFT (nOfBits))

для возврата двух целых чисел замаскируйте объединенное целое число с двоичным числом, представленным nOfBitsOne, и вы получите первое целое число, затем ShiftRight от nOfBits объединенного целого числа, и вы вернули второе.

Ответ 5

Вы можете сохранить 2 16-битных целых числа в 32-разрядном целое. Сначала один из 16 первых бит и второй в последних 16 бит. Для извлечения и компоновки значения используются операторы shift.