只要数组C ++,就可以在一条语句中比较布尔变量

时间:2019-01-10 16:19:46

标签: c++ c++11 boolean-logic

让我们说我有一个布尔数组,其中5个布尔变量都为真

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 :(得分:12)

通过以下方式替换您的定义:

 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]);兼容

在您的定义中,您还将两次输入考虑在内

但是直到最后的&&都是没有用的,最好的方法就是这样做:

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

答案 1 :(得分:10)

您还可以按如下所示使用std::all_of并具有良好的可读性:

DEMO

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

如果要使用此STL函数定义函数bool NANDGate(...),则以下实现对您来说很有效:

DEMO

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

GCC和Clang的性能

我通过 Quick C ++ Benchmark 测试了上述函数(标记为std::all_of)和the accepted答案(标记为Naive)的性能,同时使用了gcc C ++ 14和O3优化中的-8.2和Clang-7.0。 结果如下。 水平线表示每个布尔数组的大小。 在两个编译器中,对于大于〜8的大小,std::all_of的性能都比朴素的实现好。

海湾合作委员会(DEMO):

enter image description here

C语(DEMO):

enter image description here

看看GCC的源代码,得出此结果的原因将非常清楚。 std::all_of的当前GCC实施可以在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. is called)

/// 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建议的函数也将显示出更好的性能。

答案 2 :(得分:9)

如果您接受C ++ 17解决方案,则可以使用辅助函数和如下模板折叠来制作所有<form class="contact-us" method="post" action="/../contact" name="form_contact" onSubmit="alert('Thank you for your Contacting us');"> <input type="hidden" name="formID_contact" value="609" /> <div style="padding:10px;" class="bg-boxshadow "> <!-- Text input--> <div class="row"> <div class="col-xl-4 col-lg-4 col-md-12 col-sm-12 col-12"> <div class="form-group"> <label class="sr-only control-label" for="name">name<span class=" "> </span></label> <input id="name" name="name" type="text" maxlength="30" placeholder="Name" class="form-control input-md" required> </div> </div> <!-- Select Basic --> <div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12"> <div class="form-group"> <label class="control-label" for="message"> </label> <textarea class="form-control" id="message" rows="7" name="message" maxlength="200" placeholder="Message" required></textarea> </div> </div> <!-- Button --> <div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12"> <button type="submit" class="btn btn-default">Submit</button> </div> </div> </form>

constexpr

如果不能使用C ++ 17,但至少不能使用C ++ 14,则不能使用模板折叠,但是可以在未使用的数组初始化中模拟它;如下

#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;
 }

不幸的是,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仅从C ++ 14开始可用,因此,如果您想要类似的内容,则必须模拟它们(而std::make_index_sequence不能, C ++ 11,NANDhelper())。

答案 3 :(得分:8)

请执行以下操作:

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

答案 4 :(得分:4)

使用现代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);
}

答案 5 :(得分:4)

因为这是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);
}

答案 6 :(得分:2)

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
}

答案 7 :(得分:1)

如果我使用std::bitset,很多人都会皱眉,但是有了它,就不需要功能了:

std::bitset<10> boo;
//...
bool boo_nand1= !boo.all();
bool boo_nan2=(~boo).any();