Таким образом, мы все знаем правила сравнения с подписью/без знака C/С++, где -1 > 2u == true
, и у меня есть ситуация, когда я хочу эффективно выполнять "правильные" сравнения.
Мой вопрос, который более эффективен с учетом того, что многие архитектуры, как люди знакомы. Очевидно, что Intel и ARM имеют более высокий вес.
Дано:
int x;
unsigned int y;
if (x < y) {}
Лучше ли продвигать:
x < y => (int64)x < (int64)y
или лучше выполнить 2 сравнения, то есть:
x < y => (x < 0 || x < y)
Первое подразумевает расширение с нулевой протяженностью, знаком-продолжением и одну ветвь сравнения +, а последняя не требует никаких операций с расширением знака, а 2 последовательных ответвления cmp+.
Традиционная мудрость предполагает, что ветки стоят дороже, чем расширяет знак, что будет и конвейерным, но в первом случае существует разрыв между продолжениями и единственным сравнением, тогда как во втором случае я могу представить, что некоторые архитектуры могут конвейерно выполнить 2 сравнения, но затем следуют две условные ветки?
Существует еще один случай, когда значение unsigned меньше типа подписанного типа, что означает, что он может быть выполнен с единственной нулевой длиной до длины подписанного типа, а затем одно сравнение... в этом случае, предпочтительнее ли использовать версию расширения + cmp или еще предпочтительнее использовать метод сравнения 2?
Intel? РУКА? Другие? Я не уверен, есть ли здесь правильный ответ, но я хотел бы услышать, как люди берут. Низкоуровневую производительность трудно предсказать в наши дни, особенно на Intel и все чаще и чаще на ARM.
Edit:
Я должен добавить, есть одно очевидное разрешение, где типы имеют размер, равный ширине int int; в этом случае очевидно, что предпочтительным является решение с двумя сравнениями, поскольку само продвижение не может быть выполнено эффективно. Очевидно, что пример int
соответствует этому условию для 32-разрядных архитектур, и вы можете перенести мысленный эксперимент на short
для упражнений, применяемых к 32-разрядным платформам.
Изменить 2:
Извините, я забыл u
в -1 > 2u
! > _ & Л;
Изменить 3:
Я хочу изменить ситуацию, чтобы предположить, что результат сравнения является фактической ветвью, а результат НЕ возвращается как логическое. Так я бы предпочел, чтобы структура выглядела; хотя это вызывает интересную мысль о том, что существует еще один набор перестановок, когда результатом является bool vs branch.
int g;
void fun(int x, unsigned in y) { if((long long)x < (long long)y) g = 10; }
void gun(int x, unsigned in y) { if(x < 0 || x < y) g = 10; }
Это создает предполагаемую ветвь, обычно подразумеваемую, когда вы сталкиваетесь с if
;)