Сравните биты слева направо, ища самые левые биты, которые отличаются.Предполагая, что машина является дополнением до двух, самый верхний бит определяет знак и будет иметь перевернутый смысл сравнения с другими битами.Это должно работать на любых двух дополнительных компьютерах:
int compare(int x, int y) {
unsigned int mask = ~0U - (~0U >> 1); // select left-most bit
if (x & mask && ~y & mask)
return -1; // x < 0 and y >= 0, therefore y > x
else if (~x & mask && y & mask)
return 1; // x >= 0 and y < 0, therefore x > y
for (; mask; mask >>= 1) {
if (x & mask && ~y & mask)
return 1;
else if (~x & mask && y & mask)
return -1;
}
return 0;
}
[Обратите внимание, что это технически не переносимо.Си не дает никаких гарантий, что подписанная арифметика будет дополнением к двум.Но вам будет сложно найти реализацию C на современном компьютере, который ведет себя по-разному.]
Чтобы понять, почему это работает, сначала сравните два числа без знака: 13d = 1101b и 11d = 1011b.(Для краткости я предполагаю 4-битный размер слова.) Самый левый отличающийся бит - это второй слева, который первый установил, а другой - нет.Поэтому первое число тем больше.Должно быть достаточно ясно, что этот принцип выполняется для всех чисел без знака.
Теперь рассмотрим два числа дополнения.Вы отрицаете число, добавляя биты и добавляя один.Таким образом, -1d = 1111b, -2d = 1110b, -3d = 1101b, -4d = 1100b и т. Д. Вы можете видеть, что два отрицательных числа можно сравнить, как если бы они были без знака.Аналогично, два неотрицательных числа также можно сравнить, как если бы они были без знака.Только когда знаки различаются, мы должны их учитывать - но если они различаются, сравнение тривиально!