Можно ли вводить punning, подписанные в целые числа без знака, заставляют проверку границ быстрее, устраняя необходимость в >= сравнении?

Предположим, что в моей программе был критический цикл, зависящий от производительности, когда мне нужно проверить, находилась ли точка внутри прямоугольника, но во время компиляции я знаю, что нижние границы всегда будут равны 0, например: (x >= 0 && y >= 0 && x < width && y < height)

Могу ли я исключить первые два сравнения путем ввода чисел типа x и y в беззнаковые целые числа (например, с чем-то вроде reinterpret_cast<>() или union в С++), поскольку бит знака гарантирует, что любое отрицательное число превратится в unsigned int достаточно большой, чтобы не проверить границы? Если да, то как вы собираетесь реализовать это на С++ или на другом языке? Не могли бы вы добиться какого-либо улучшения производительности, выполнив это?

Ответ 1

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

Я только что протестировал это на GCC 4.9 и подтвердил, проверив сгенерированный код сборки, что он автоматически выполняет эту оптимизацию при -O1 и выше. Я ожидал бы, что все современные компиляторы сделают то же самое.

Ответ 2

Может быть...

В то время как на "бумаге" это, по-видимому, позволит вам выполнять только два сравнения, а не четыре (что приятно) - вы не можете гарантировать, как это будет выполняться. Большинство процессоров в эти дни могут выполнять несколько параллельных операций одновременно - и четыре сравнения, которые у вас есть, легко вычисляются параллельно.

Ваш вопрос зависит от компилятора, процессора, а также от кода до и после проверки - так что мой ответ "возможно".

Избегайте приведения x, y к типу, который отличается от того, чем они являются в настоящее время, т.е. отбрасывается из int8_t в uint8_t, а int8_t - uint32_t может нанести штраф.

Переписывание по вашему желанию:

if ( ( static_cast<uint8_t>(x) < width ) &&
     ( static_cast<uint8_t>(y) < length ) )

Тестирование дельта производительности довольно сложно, вам нужно будет обернуть свой код некоторой сборкой, используя инструкцию RDTSC, чтобы уловить время до и после. Вам также, вероятно, также потребуется использовать команду CPUID для очистки трубопровода.

Короче, для меня ваша оптимизация кажется разумной, но, вероятно, вряд ли уступит. Он будет работать, хотя.