#algorithm
#алгоритм
Вопрос:
Я хочу вычислить, находится ли точка, (x,y)
, внутри прямоугольника, который определяется двумя точками, (a,b)
и (c,d)
.
Если a<=c
и b<=d
, то это просто:
a<=xamp;amp;x<=camp;amp;b<=yamp;amp;y<=d
Однако, поскольку неизвестно, является ли a<=c
или b<=d
, код должен быть
(a<=xamp;amp;x<=c||c<=xamp;amp;x<=a)amp;amp;(b<=yamp;amp;y<=d||d<=yamp;amp;y<=b)
Этот код может работать, но он слишком длинный. Я могу написать функцию и использовать ее, но мне интересно, есть ли более короткий способ (и он должен выполняться очень быстро — код вызывается много) для его написания.
Я могу себе представить:
((c-x)*(x-a)>=0)amp;amp;((d-y)*(y-b)>=0)
Есть ли более умный способ сделать это?
(И есть ли какой-нибудь хороший способ выполнить итерацию от a до c?)
Комментарии:
1. Это не умно, так что это не ответ. Поменяйте
a/c
местами иb/d
по мере необходимости, чтобы обеспечить правильный порядок, затем примените простую формулу.
Ответ №1:
Меняйте переменные по мере необходимости так, чтобы a = x min и b = y min:
if a > c: swap(a,c)
if b > d: swap(b,d)
a <= x <= c and b <= y <= d
Короче, но немного менее эффективен:
min(a,c) <= x <= max(a,c) and min(b,d) <= y <= max(b,d)
Как всегда, при оптимизации вы должны профилировать различные параметры и сравнивать точные цифры. Конвейерная обработка, переупорядочивание инструкций, прогнозирование ветвлений и другие современные методы оптимизации компилятора / процессора делают неочевидным, стоит ли проводить микрооптимизацию на уровне программиста. Например, раньше умножение было значительно дороже, чем ветвление, но это уже не всегда так.
Ответ №2:
Мне нравится это:
((c-x)*(x-a)>=0)amp;amp;((d-y)*(y-b)>=0)
но с большим количеством пробелов и большей симметрией:
(c-x)*(a-x) <= 0 amp;amp; (d-y)*(b-y) <= 0
Это математически элегантно и, вероятно, самое быстрое. Вам нужно будет измерить, чтобы действительно определить, какой из них самый быстрый. С современными конвейерными процессорами я ожидаю, что прямой код с минимальным количеством операторов будет выполняться быстрее.
Комментарии:
1. То, что вы говорите, может быть правдой, но я думаю, что простое сравнение (сравнения) будет быстрее, чем выполнение от 2 до 4 вычитаний и от 1 до 2 умножений. Что вы думаете?
2. @Sam: простые сравнения не будут быстрее сложения и не могут быть быстрее умножения. Ветвление происходит относительно медленно. На современном процессоре с несколькими ALU четыре вычитания могут выполняться параллельно, и то же самое для двух умножений.
Ответ №3:
Хотя сортировка (a, b)
(c, d)
пар and, как предложено в принятом ответе, вероятно, является лучшим решением в этом случае, еще лучшим применением этого метода, вероятно, было бы повысить a < b
c < d
требование and до уровня общепрограммного инварианта. Т.е. Требовать, чтобы все прямоугольники в вашей программе создавались и поддерживались вэта «нормализованная» форма с самого начала. Таким образом, внутри вашей тестовой функции point-in-rectangle вы должны просто утверждать это a < b
и c < d
вместо того, чтобы тратить ресурсы процессора на фактическую сортировку их при каждом вызове.
Ответ №4:
Определите промежуточные переменные i = min(a,b)
, j = min(c,d)
, k = max(a,b)
, l = max(c,d)
Тогда вам нужно только i<=x amp;amp; x<=k amp;amp; j<=y amp;amp; y<=l
.
РЕДАКТИРОВАТЬ: Имейте в виду, с точки зрения эффективности, вероятно, лучше использовать ваш «слишком длинный» код в функции.