Улучшает ли вложенность операторов if производительность или имеет другие преимущества по сравнению с операторами if?

1

У меня есть несколько неуклюжий ряд утверждений о том, что по привычке я гнезду вот так:

// Cannot collide with right
    if(direction.x < 0)
    {
        // Cannot collide with top
        if(direction.y < 0)
        {
            // Check left and bottom
        }
        // Cannot collide with bottom
        else if (direction.y > 0)
        {
            // Check left and top
        }
        // Cannot collide with top or bottom
        else
        {
            // Check left only

        }
    }
    // Cannot collide with left
    else if (direction.x > 0)
    {
        // Cannot collide with top
        if(direction.y < 0)
        {
            // Check right and bottom
        }
        // Cannot collide with bottom
        else if (direction.y > 0)
        {
            // Check right and top
        }
        // Cannot collide with top or bottom
        else
        {
            // Check right only

        }
    }

Однако мне трудно читать и думать, что было бы легче следовать как плоский набор утверждений if, несколько похожий на переключатель:

// Cannot collide with right or top
    if(direction.x < 0 && direction.y < 0)
    {
        // Check left and bottom
    }
    // Cannot collide with right or bottom
    else if(direction.x < 0 && direction.y > 0)
    {
        // Check left and top
    }
    // Cannot collide with right, top or bottom
    else if(direction.x < 0)
    {
        // Check left only
    }
    // Cannot collide with left or top
    else if (direction.x > 0 && direction.y < 0)
    {
        // Check right and bottom
    }
    // Cannot collide with left or bottom
    else if (direction.x > 0 && direction.y > 0)
    {
        // Check right and top
    }
    // Cannot collide with left, top or bottom
    else
    {
        // Check right only
    }

Очевидным недостатком этого является то, что я повторно проверяю условие несколько раз. В этом случае он настолько мал, что я не могу представить, что это имеет значение, но мои вопросы:

  1. Можете/сделать современные компиляторы для С#, Java и т.д. Оптимизировать второй пример, чтобы удалить повторные проверки? Это было бы хорошо в этом примере, но может вызвать проблемы, если проверка состояния также имела побочные эффекты.
  2. Также в целом, какой подход будет одобрен?
  • 2
    Ваш второй пример никоим образом не сплющен, каждый другой, если добавляет новый слой вложения, поскольку он эквивалентен else { if(predicate) { ... , вам просто не нужно { .
  • 0
    Я думаю, что чтение ваших комментариев к коду показывает, какой путь предпочтительнее
Показать ещё 1 комментарий
Теги:
optimization
if-statement
compilation

3 ответа

0

Операторы AND будут содержать ярлык компилятором в С#, поэтому, если direction.x <= 0, второе предложение в ваших инструкциях if не будет оцениваться, поэтому нет необходимости в гнезде на основе "direction> 0",,

  • 0
    За исключением случаев, когда direction.x объявлен как volatile .
0

Я бы предпочел первый подход, потому что он уменьшает дубликаты кода (кроме того, что он может быть немного быстрее - в случае volatile атрибутов переменные должны быть перечитаны).

Что произойдет, если вам нужно изменить direction.x < 0 условие direction.x > 1 (может быть, не лучший пример здесь, но вы получите идею...)? Вам нужно только изменить его в одном месте.

Также я думаю, что первый подход легче понять: когда вы следуете коду, вы знаете, что если вы находитесь в первой ветке оператора if, то он "не может столкнуться с правильным", а при втором подходе вам всегда нужно думать через все условие, а также все условия предыдущих утверждений if чтобы знать, если вы даже доберетесь туда.

улучшение

Ваш код можно улучшить, разделив условия с помощью фактического кода, который вы хотите сделать, действительно превратив его в switch.

Для этого мы будем использовать эти константы:

static final int LEFT   = 0x01;
static final int RIGHT  = 0x02;
static final int TOP    = 0x10;
static final int BOTTOM = 0x20;

И код:

final int dir = (d.x < 0 ? LEFT : d.x > 0 ? RIGHT  : 0)
              + (d.y < 0 ? TOP  : d.y > 0 ? BOTTOM : 0);

switch (dir) {
case LEFT:           // Check left only
    break;
case RIGHT:          // Check right only
    break;
case LEFT + TOP:     // Check left and top
    break;
case LEFT + BOTTOM:  // Check left and bottom
    break;
case RIGHT + TOP:    // Check right and top
    break;
case RIGHT + BOTTOM: // Check right and bottom
    break;
}
0

Преждевременная оптимизация - зло.

С точки зрения удобочитаемости я бы сделал что-то вроде

[Flags]
enum Direction
{
    None = 0,
    Top = 1 << 0,
    Bottom = 1 << 1,
    Left = 1 << 2,
    Right = 1 << 3,
}

А потом

var d = (x > 0 ? Direction.Right : (x < 0 ? Direction.Left : Direction.None)) |
    (y > 0 ? Direction.Top : (y < 0 ? Direction.Bottom : Direction.None));
switch(d)
{
    case Direction.Left:
        ...
        break;
    case Direction.Right | Direction.Bottom:
        ...
        break;
    ...
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню