Как узнать, состоит ли значение массива из нулей? - PullRequest
2 голосов
/ 09 февраля 2010

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

Я пишу небольшой алгоритм, который включает проверку значений в матрице. Допустим,

char matrix[100][100];
char *ptr = &matrix[0][0];

представьте, что я заполнил матрицу парой значений (5 или 6) из 1, например:

matrix[20][35]=1;
matrix[67][34]=1;

Как узнать, что двоичное значение интервала матрицы равно нулю, например (в псевдокоде)

if((the value from ptr+100 to ptr+200)==0){ ... // do something

Я пытаюсь снова перейти на c / c ++. Должен быть способ выбрать те сто байтов (которые находятся рядом друг с другом) и проверить, все ли их значения равны нулю, без проверки на единицу (учитывая, что char равен одному байту)

Ответы [ 6 ]

3 голосов
/ 09 февраля 2010

Вы можете использовать std :: find_if.

bool not_0(char c)
{
    return c != 0;
}

char *next = std::find_if(ptr + 100, ptr + 200, not_0);
if (next == ptr + 200)
    // all 0's

Вы также можете использовать связыватели для удаления функции free (хотя я думаю, что связующие трудно читать):

char *next = std::find_if(ptr + 100, ptr + 200,
                           std::bind2nd(std::not_equal_to<char>(), 0));

Черт, я просто замечаю просьбу не делать этот байт за байтом. find_if все равно будет делать побайтово, хотя он и скрыт. Вы должны будете сделать это 1 на 1, хотя использование более крупного типа поможет. Вот мой окончательный вариант.

template <class T>
bool all_0(const char *begin, const char *end, ssize_t cutoff = 10)
{
    if (end - begin < cutoff)
    {
        const char *next = std::find_if(begin, end,
           std::bind2nd(std::not_equal_to<char>(), 0));
        return (next == end);
    }
    else
    {
        while ((begin < end) && ((reinterpret_cast<uintptr_t>(begin) % sizeof(T)) != 0))
        {
            if (*begin != '\0')
                return false;

            ++begin;
        }

        while ((end > begin) && ((reinterpret_cast<uintptr_t>(end) % sizeof(T)) != 0))
        {
            --end;

           if (*end != '\0')
               return false;
        }

        const T *nbegin = reinterpret_cast<const T *>(begin);
        const T *nend = reinterpret_cast<const T *>(end);

        const T *next = std::find_if(nbegin, nend,
           std::bind2nd(std::not_equal_to<T>(), 0));
        return (next == nend);
    }
}

Сначала он проверяет, достаточно ли длинны данные, чтобы оправдать более сложный алгоритм. Я не уверен на 100%, что это необходимо, но вы можете настроить необходимый минимум.

Предполагая, что данные достаточно длинные, они сначала выравнивают начальный и конечный указатели, чтобы соответствовать выравниванию типа, используемого для сравнения. Затем он использует новый тип для проверки объема данных.

Я бы порекомендовал использовать:

all_0<int>(); // 32 bit platforms
all_0<long>(); // 64 bit LP64 platforms (most (all?) Unix platforms)
all_0<long long>() // 64 bit LLP64 platforms (Windows)
2 голосов
/ 09 февраля 2010

Для этого нет встроенной функции языка, и нет стандартной библиотеки для этого. memcmp() может работать, но вам потребуется второй массив всех нулей для сравнения; этот массив должен быть большим, и при сравнении вы также израсходуете ненужную пропускную способность памяти.

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

1 голос
/ 09 февраля 2010

вы пометили этот C ++, чтобы вы могли использовать указатель в качестве итератора и использовать алгоритм stl. станд :: макс. Затем посмотрите, если макс 0 или нет.

0 голосов
/ 09 февраля 2010

Резервный элемент 0 вашего массива для установки на все нули.

Используйте memcmp для сравнения соответствующих диапазонов в двух элементах.

0 голосов
/ 09 февраля 2010

Нет способа определить, имеет ли массив какое-либо значение, отличное от нуля, кроме проверки всех элементов по одному. Но если вы начнете с массива, который, как вы знаете, имеет все нули, вы можете сохранить флаг, который указывает нулевое состояние массива.

std::vector<int> vec(SIZE);
bool allzeroes = true;

// ...

vec[SIZE/2] = 1;
allzeroes = false;

// ...

if( allzeroes ) {
    // ...
}
0 голосов
/ 09 февраля 2010

Вы можете привести свой указатель как int * и затем проверять четыре байта за раз, а не один.

...