У меня есть два целых числа, которые мне нужно передать через одно целое, а затем вернуть значения двух целых чисел.
Я имею в виду использование логических операторов (AND, OR, XOR и т.д.).
У меня есть два целых числа, которые мне нужно передать через одно целое, а затем вернуть значения двух целых чисел.
Я имею в виду использование логических операторов (AND, OR, XOR и т.д.).
Используя язык программирования 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) заставляет все биты, которые не находятся в этих нижних двух байтах, отключить ( обратно к нулю). Это можно использовать для удаления любых частей "другого целого" из того, которое вы в настоящее время извлекаете.
Есть две части этого вопроса. Во-первых, как вы можете маскаровать два 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
Такой подход возник очень давно, в средах, которые должны были выжать каждый бит из пространства для хранения или передачи. Если вы не находитесь в встроенной системе или не сразу упаковываете эти данные для передачи по сети, практичность всей этой процедуры начинает быстро разрушаться:
Если это так плохо, какие альтернативы?
Вот почему люди спрашивали вас о вашем языке. В идеале, если вы похожи на 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/
Хорошо.. @Felice прав, но если они оба подходят в 16 бит, то есть способ:
output_int = (first_int << 16) | second_int
^
means 'or'
чтобы упаковать их, и
first_int = output_int & 0xffff
second_int = (output int >> 16) & 0xffff
^
means 'and'
чтобы извлечь их.
Два целых числа не могут соответствовать одному целому числу, или, по крайней мере, вы не можете вернуть два исходных.
Но в любом случае, если два исходных целых числа ограничены определенным количеством битов, которое вы можете (в псевдокоде): Первое целое число ИЛИ с (Второе целое число SHIFTLEFT (nOfBits))
для возврата двух целых чисел замаскируйте объединенное целое число с двоичным числом, представленным nOfBitsOne, и вы получите первое целое число, затем ShiftRight от nOfBits объединенного целого числа, и вы вернули второе.
Вы можете сохранить 2 16-битных целых числа в 32-разрядном целое. Сначала один из 16 первых бит и второй в последних 16 бит. Для извлечения и компоновки значения используются операторы shift.