Эффективный для процессора метод проверки, является ли позиция массива нулевой в C ++

0

Программа, которую я написал, должна проверять миллионы точек в 2D-массиве, чтобы узнать, не являются ли они нулевыми. Вот код, который я использую:

Particle *particleGrid[1920][1080];
bool Sensor::checkForParticle(int x, int y) {
    if (x > 1920 || x < 0) return 0;
    if (y > 1080 || y < 0) return 0;
    if (mainController->particleGrid[x][y] != NULL) {
        return 1;
    }
    return 0;
}

Эта функция использует большинство процессоров во всем приложении (около 70% использования ЦП приложения связано с этой функцией), даже больше, чем моя реализация алгоритма рисования линии Брешенема (функция примера вызывается в каждой точке сгенерированной строки по алгоритму Брешенема). Есть ли более эффективный для процессора способ выполнения операции проверки нулевой точки?

  • 1
    (~ 70% загрузки процессора приложением связано с этой функцией) . Откуда ты это знаешь?
  • 0
    Этот вопрос может быть лучше подходит для просмотра кода. В любом случае, есть ли причина, по которой ваши х / у подписаны? одно неоплаченное сравнение вместо двух подписанных кажется дешевле.
Показать ещё 10 комментариев
Теги:
arrays

5 ответов

2

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

2

Если вы сравните с неподписанными литералами, вы получите проверку против 0 бесплатно, потому что отрицательные числа оказываются очень большими при преобразовании в unsigned. Кроме того, вам не нужны все эти ifs:

bool Sensor::checkForParticle(int x, int y)
{
    return (x < 1920u) && (y < 1080u)   // note both "u" suffixes for unsigned
        && (mainController->particleGrid[x][y] != NULL);
}

Кстати, почему у вас есть массив в порядке столбцов? Являются ли ваши внешние циклы на x или y? Если они находятся на y, переход на row-major значительно улучшит эффективность из-за удобства кеширования:

Particle *particleGrid[1080][1920];

bool Sensor::checkForParticle(int x, int y)
{
    return (x < 1920u) && (y < 1080u)
        && (mainController->particleGrid[y][x] != NULL);   // note switched order
}
0

Если 2D-массив разрежен, что-то вроде этого может помочь вам ускорить замкнутый цикл:

Particle *particleGrid[1920][1080];

// somewhere before your tight loop
std::map<std::pair<unsigned int, unsigned int>, Particle*> createCache()
{
    std::map<std::pair<unsigned int, unsigned int>, Particle*> cache;
    for (unsigned int i = 0; i < 1920; ++i)
    {
        for (unsigned int j = 0; j < 1080; ++j)
        {
            if (mainController->particleGrid[i][j])
            {
                std::pair<unsigned int, unsigned int> coord = std::make_pair(i, j);
                cache[coord] = mainController->particleGrid[i][j];
            }
        }
    }
    return cache;
}

// then this is called in your tight loop
bool Sensor::checkForParticle(unsigned int x, unsigned int y, const std::map<std::pair<unsigned int, unsigned int>, Particle*>& cache) 
{
    std::pair<unsigned int, unsigned int> coord = std::make_pair(x, y);
    return cache.find(coord) != map.end();
}

Если он не разрежен, это вообще не поможет.

0

Шаг 1: Поднимите консистенцию из цикла:

bool Sensor::uncheckedCheckForParticle(int x, int y) {
    return mainController->particleGrid[y][x];
}

Если вам действительно нужно защититься от неаккуратного программирования, вы можете assert() в функции и/или защищать сайт вызова. Готов поспорить, что это значительно улучшит производительность.

Шаг 2: сделайте теперь тривиальную функцию inline.

0

Вы можете сгладить массив от двумерного к одномерному (к сожалению, это может потребовать рефакторинга в другом месте кода):

Particle *particleGrid[1920 * 1080];
bool Sensor::checkForParticle(int x, int y) {
    return (mainController->particleGrid[x * 1080 + y] != NULL)
}

Ещё вопросы

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