Сравните логические переменные в одном операторе до тех пор, пока массив C ++ - PullRequest
0 голосов
/ 10 января 2019

Допустим, у меня есть логический массив с 5 переменными bool, все из которых истинны

bool boo[10];
for(int i = 0; i < 5; i++){
    boo[i] = true;
}

Я хочу, чтобы все они сравнивались сразу в один логический элемент NAND, потому что моя проблема в том, что я всегда сравниваю две переменные и сравниваю объединенную логическую переменную с логической переменной i + 1. Это дает неверный результат.

    bool NANDGate(bool array[]){
    bool at;
    for(int i = 1; i < 5; i++){
        if(i == 1){
            at = !(array[i-1] && array[i]);
        }else{
            at = !(at && array[i]);
        }
    }
    return at;
}
// result here is true even though it should be false

То, что я хочу, - это правильный результат, когда я помещаю каждую переменную из boo в NAND-гейт, так что, возможно, что-то похожее на это:

bool func(bool array[]){
// some loop
result = !(array[0] && array[1] && array[2] && array[3] && array[4]);
return result;
}
// result here would be false

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

РЕДАКТИРОВАТЬ: так много отличных решений, я благодарю вас всех

Ответы [ 8 ]

0 голосов
/ 28 января 2019

Если я использую std::bitset, многие будут хмуриться, но с этим функция не понадобится:

std::bitset<10> boo;
//...
bool boo_nand1= !boo.all();
bool boo_nan2=(~boo).any();
0 голосов
/ 10 января 2019

Поскольку это C ++, нам не нужно писать цикл; вместо этого мы можем использовать std::any_of.

Нам нужно, чтобы наш NAND-шлюз возвратил true, если какой-либо ввод ложен:

#include <algorithm>
#include <functional>

bool NANDGate(const bool array[])
{
    return std::any_of(array, array+5, std::logical_not<bool>());
}

int main()
{
    const bool boo[10] = { true, true, true, true, true };

    return NANDGate(boo);
}
0 голосов
/ 10 января 2019

C ++ имеет std::bitset, особенно для подобных случаев. Чистое решение с C ++ 11:

#include <bitset>
#include <iostream>


const unsigned gateSize = 5;


int main ()
{
    std::bitset<gateSize> booBits;

    //Set all bits to true by this simple function call...
    booBits.set();

    //... or some loop
    for (unsigned i = 0; i < gateSize; ++i)
        booBits[i] = 1;

    std::cout << !booBits.all() << std::endl; //This is your NANDgate
}
0 голосов
/ 10 января 2019

Другое решение с использованием современного C ++:

template <class CONTAINER>
bool NANDGate(const CONTAINER& container) {
    auto is_false = [](const auto& item) { return !(bool)item; };
    return std::any_of(std::begin(container), std::end(container), is_false);
}
0 голосов
/ 10 января 2019

Вы также можете использовать std::all_of с хорошей читабельностью следующим образом:

DEMO

!std::all_of(std::begin(boo), std::begin(boo)+5, [](bool b){ return b; });

Если вы хотите определить функцию bool NANDGate(...) с помощью этой функции STL, тогда вам пригодится следующая реализация:

DEMO

bool NANDGate(const bool *arr, std::size_t n) 
{
    return !std::all_of(arr, arr+n, [](bool b){ return b; });
}

Производительность на GCC и Clang

Я проверил производительность вышеуказанной функции (с меткой std::all_of) и принятый ответ (с меткой Naive) с помощью Quick C ++ Benchmark с обоими gcc-8.2 и Clang-7.0 в C ++ 14 и O3 оптимизация. Результат выглядит следующим образом. Горизонтальная линия представляет размеры каждого логического массива. В обоих компиляторах std::all_of показывает лучшую производительность, чем наивная реализация для размеров, превышающих ~ 8:

GCC ( DEMO ):

enter image description here

Clang ( DEMO ):

enter image description here

Глядя на исходный код GCC, причина этого результата будет довольно ясна. Текущую реализацию GCC std::all_of можно увидеть в gcc / libstdc ++ - v3 / include / bits / stl_algo.h и следующей:

template<typename _InputIterator, typename _Predicate>
inline bool
all_of(_InputIterator __first, _InputIterator __last, _Predicate __pred)
{ 
    return __last == std::find_if_not(__first, __last, __pred);
}

, где std::find_if_not также реализован в том же файле с помощью функции __find_if. Обратите внимание, что есть две перегрузки __find_if. Первый - очень простой, следующий:

template<typename _InputIterator, typename _Predicate>
inline _InputIterator
__find_if(_InputIterator __first, _InputIterator __last,
          _Predicate __pred, input_iterator_tag)
{
    while (__first != __last && !__pred(__first))
        ++__first;

    return __first;
}

OTOH, вторая функция перегрузки для итераторов произвольного доступа и оптимизированная для них. Реализация заключается в следующем. Поскольку расстояние между итераторами произвольного доступа быстро вычисляется с постоянной сложностью O (1), это ручное развертывание цикла эффективно работает. В нашем текущем случае boo является необработанным указателем, который является итератором произвольного доступа. Таким образом, эта оптимизированная функция перегрузки вызывается. Это должно быть причиной того, что std::all_of показывает лучшую производительность, чем наивная реализация для почти всех размеров:

DEMO (RAI ver. Называется)

/// This is an overload used by find algos for the RAI case.
template<typename _RandomAccessIterator, typename _Predicate>
_RandomAccessIterator
__find_if(_RandomAccessIterator __first, _RandomAccessIterator __last,
          _Predicate __pred, random_access_iterator_tag)
{
    typename iterator_traits<_RandomAccessIterator>::difference_type __trip_count = (__last - __first) >> 2;

    for (; __trip_count > 0; --__trip_count)
    {
       if (__pred(__first))
           return __first;

       ++__first;

       if (__pred(__first))
           return __first;

       ++__first;

       if (__pred(__first))
           return __first;

       ++__first;

       if (__pred(__first))
           return __first;

       ++__first;
    }

    switch (__last - __first)
    {
    case 3:
      if (__pred(__first))
          return __first;

      ++__first;
    case 2:
      if (__pred(__first))
          return __first;

      ++__first;
    case 1:
      if (__pred(__first))
          return __first;

      ++__first;
    case 0:
    default:
      return __last;
    }
}

Хотя я не знаю подробностей реализации Clang, похоже, это также оптимизировано из приведенного выше графика. Кроме того, по той же причине функции, предложенные @ 0x0x5453 и @TobySpeight, также будут показывать лучшую производительность, по крайней мере, в этих компиляторах.

0 голосов
/ 10 января 2019

Если вы принимаете решение C ++ 17, вы можете сделать все constexpr, используя вспомогательную функцию и сворачивание шаблона следующим образом

#include <iostream>
#include <utility>
#include <type_traits>

template <std::size_t N, std::size_t ... Is>
constexpr bool NANDhelper (bool const (&a)[N],
                           std::index_sequence<Is...> const &)
 { return ! (a[Is] && ...); }

template <std::size_t N>
constexpr bool NANDgate (bool const (&a)[N])
 { return NANDhelper(a, std::make_index_sequence<N>{}); }

int main ()
 {
   bool a[] { true, true, true, true, true };
   bool b[] { true, false, true, true, true };

   std::cout << NANDgate(a) << std::endl;
   std::cout << NANDgate(b) << std::endl;
 }

Если вы не можете использовать C ++ 17, но, по крайней мере, C ++ 14, вы не можете использовать свертывание шаблона, но вы можете смоделировать его в неиспользуемой инициализации массива; что-то следующее

template <std::size_t N, std::size_t ... Is>
constexpr bool NANDhelper (bool const (&a)[N],
                           std::index_sequence<Is...> const &)
 {
   using unused = bool[];

   bool val { true };

   (void)unused { true, (val &= a[Is])... };

   return ! val; 
 }

К сожалению, std::index_sequence и std::make_index_sequence доступны только начиная с C ++ 14, поэтому, если вы хотите что-то подобное, вы должны эмулировать их (а NANDhelper() не может быть, в C ++ 11, constexpr).

0 голосов
/ 10 января 2019

Следующие должны сделать это:

bool NANDGate(bool array[])
{
    for(int i = 0; i < 5; i++)
    {
        if (!array [i])
            return true;
    }
    return false;
}
0 голосов
/ 10 января 2019

замените ваше определение на:

 bool NANDGate(bool array[]){
   bool at = array[0];
   for(int i = 1; i < 5; i++){
     at &&= array[i];
   }
   return !at;
 } 

Not (!) должен быть сделан в конце, чтобы быть совместимым с !(array[0] && array[1] && array[2] && array[3] && array[4]);

И в своем определении вы также учитываете некоторые записи 2 раза

Но делать && до конца бесполезно, лучше всего сделать:

 bool NANDGate(bool array[]){
   for(int i = 0; i < 5; i++){
     if (!array[i])
       return true;
   }
   return false;
 } 
...