Первые решения для сдвига (сдвиг - это расстояние сдвига, он не должен быть отрицательным, a - это операнд, который должен быть сдвинут, и также содержит результат, когда это сделано). Таблица мощности используется всеми тремя операциями смены.
// table used for shift operations
powtab = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, -32768 };
// logical shift left
if (shift > 15) {
a = 0; // if shifting more than 15 bits to the left, value is always zero
} else {
a *= powtab[shift];
}
// logical shift right (unsigned)
if (shift > 15) {
a = 0; // more than 15, becomes zero
} else if (shift > 0) {
if (a < 0) {
// deal with the sign bit (15)
a += -32768;
a /= powtab[shift];
a += powtab[15 - shift];
} else {
a /= powtab[shift];
}
}
// arithmetic shift right (signed)
if (shift >= 15) {
if (a < 0) {
a = -1;
} else {
a = 0;
}
} else if (shift > 0) {
if (a < 0) {
// deal with the sign bit
a += -32768;
a /= powtab[shift];
a -= powtab[15 - shift];
} else {
// same as unsigned shift
a /= powtab[shift];
}
}
Для AND, OR и XOR я не смог придумать простое решение, так что я сделаю это с циклической обработкой каждого отдельного бита. Там может быть лучший трюк для этого. Псевдокод предполагает, что a и b - входные операнды, c - значение результата, x - счетчик цикла (каждый цикл должен выполняться ровно 16 раз):
// XOR (^)
c = 0;
for (x = 0; x <= 15; ++x) {
c += c;
if (a < 0) {
if (b >= 0) {
c += 1;
}
} else if (b < 0) {
c += 1;
}
a += a;
b += b;
}
// AND (&)
c = 0;
for (x = 0; x <= 15; ++x) {
c += c;
if (a < 0) {
if (b < 0) {
c += 1;
}
}
a += a;
b += b;
}
// OR (|)
c = 0;
for (x = 0; x <= 15; ++x) {
c += c;
if (a < 0) {
c += 1;
} else if (b < 0) {
c += 1;
}
a += a;
b += b;
}
То есть при условии, что все переменные являются 16-битными, и все операции ведут себя как подписанные (поэтому <0 на самом деле истинно, когда установлен бит 15). </p>
РЕДАКТИРОВАТЬ: я фактически проверил все возможные значения операндов (от -32768 до 32767) для сдвигов в диапазоне от 0 до 31 на правильность, и он работает правильно (при условии целочисленного деления). Для кода AND / OR / XOR исчерпывающий тест занимает слишком много времени на моей машине, но, поскольку код для этого довольно прост, в любом случае не должно быть крайних случаев.