Изящно определите, является ли более одного логического значения истинным - PullRequest
71 голосов
/ 18 декабря 2008

У меня есть набор из пяти логических значений. Если более одного из них являются истинными, я хочу выполнить конкретную функцию. Какой самый элегантный способ, который вы можете себе представить, позволил бы мне проверить это условие в одном операторе if ()? Целевым языком является C #, но мне интересны решения и на других языках (если мы не говорим о конкретных встроенных функциях).

Один интересный вариант - сохранить логические значения в байте, выполнить сдвиг вправо и сравнить с исходным байтом. Что-то вроде if(myByte && (myByte >> 1)) Но для этого потребуется преобразовать отдельные логические значения в байт (через bitArray?), И это кажется немного (каламбур) неуклюжим ... [edit] Извините, это должно было быть if(myByte & (myByte - 1)) [/ edit]

Примечание: это, конечно, очень близко к классической проблеме программирования "подсчет населения", "сложение вбок" или "вес Хэмминга" - но не совсем то же самое. Мне не нужно знать, сколько битов установлено, только если их больше одного. Я надеюсь, что есть гораздо более простой способ сделать это.

Ответы [ 22 ]

0 голосов
/ 18 декабря 2008

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

0x 0000 0000 
0x 0000 0001
0x 0000 0010
0x 0000 0100
0x 0000 1000
0x 0001 0000

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

Это дает вам простой ответ.

   public static boolean moreThan1BitSet(int b)
   {
      final short multiBitLookup[] = { 
            1, 1, 1, 0, 1, 0, 0, 0,
            1, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0,
            1, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0
      };
      if(multiBitLookup[b] == 1)
         return false;
      return true;
   }

Это не масштабируется выше 8 бит, но у вас есть только пять.

0 голосов
/ 19 декабря 2008

Вы упомянули

Один интересный вариант - хранить логические значения в байте, сделайте правильный сдвиг и сравните с исходным байтом. Что-то вроде if (myByte && (myByte >> 1))

Я не думаю, что выражение даст вам желаемый результат (по крайней мере, с использованием семантики C, поскольку выражение не является допустимым C #):

Если (myByte == 0x08), то выражение вернет true, даже если установлен только один бит.

Если вы имели в виду «if (myByte & (myByte >> 1))», тогда, если (myByte == 0x0a), выражение вернет false, даже если установлено 2 бита.

Но вот некоторые методы подсчета количества бит в слове:

Взлом битовых комбинаций - Подсчет битов

Вариант, который вы могли бы рассмотреть, - это использовать метод подсчета Кернигана, но выручить пораньше, поскольку вам нужно только знать, установлено ли более одного бита:

int moreThanOneBitSet( unsigned int v)
{
    unsigned int c; // c accumulates the total bits set in v

    for (c = 0; v && (c <= 1); c++)
    {
      v &= v - 1; // clear the least significant bit set
    }

    return (c > 1);
}

Конечно, использование таблицы поиска тоже неплохой вариант.

...