只要数组 C++,就可以在一个语句中比较布尔变量
Compare Boolean Variables in one statement as long as array C++
假设我有一个布尔数组,其中有 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
实际上它不必看起来像上面那样具有正确结果的解决方案。
编辑:这么多很棒的解决方案,谢谢大家
将您的定义替换为:
bool NANDGate(bool array[]){
bool at = array[0];
for(int i = 1; i < 5; i++){
at &&= array[i];
}
return !at;
}
非(!
)必须放在最后才能兼容!(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;
}
下面应该这样做:
bool NANDGate(bool array[])
{
for(int i = 0; i < 5; i++)
{
if (!array [i])
return true;
}
return false;
}
如果您接受 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
).
你也可以使用std::all_of
,可读性好,如下:
!std::all_of(std::begin(boo), std::begin(boo)+5, [](bool b){ return b; });
如果你想用这个STL函数定义函数bool NANDGate(...)
,那么下面的实现很适合你:
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[=74] 测试了上述函数(标记为 std::all_of
)和 答案(标记为 Naive
)的性能=] 在 C++14 和 O3 优化中同时使用 gcc-8.2 和 Clang-7.0。
结果如下。
水平线表示每个布尔数组的大小。
在两个编译器中,std::all_of
对于大于 ~8 的大小表现出比简单实现更好的性能:
海湾合作委员会(DEMO):
叮当声 (DEMO):
看看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
对于几乎所有尺寸都显示出比简单实现更好的性能的原因:
/// 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 提出的函数至少在这些编译器中也会表现出更好的性能。
另一种使用现代 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);
}
因为这是C++,我们不需要写循环;我们可以使用 std::any_of
代替。
如果任何输入为假,我们需要我们的 NAND 门 return 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);
}
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
}
如果我使用 std::bitset
很多人会皱眉,但有了它就不需要函数了:
std::bitset<10> boo;
//...
bool boo_nand1= !boo.all();
bool boo_nan2=(~boo).any();
假设我有一个布尔数组,其中有 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
实际上它不必看起来像上面那样具有正确结果的解决方案。
编辑:这么多很棒的解决方案,谢谢大家
将您的定义替换为:
bool NANDGate(bool array[]){
bool at = array[0];
for(int i = 1; i < 5; i++){
at &&= array[i];
}
return !at;
}
非(!
)必须放在最后才能兼容!(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;
}
下面应该这样做:
bool NANDGate(bool array[])
{
for(int i = 0; i < 5; i++)
{
if (!array [i])
return true;
}
return false;
}
如果您接受 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
).
你也可以使用std::all_of
,可读性好,如下:
!std::all_of(std::begin(boo), std::begin(boo)+5, [](bool b){ return b; });
如果你想用这个STL函数定义函数bool NANDGate(...)
,那么下面的实现很适合你:
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[=74] 测试了上述函数(标记为 std::all_of
)和 Naive
)的性能=] 在 C++14 和 O3 优化中同时使用 gcc-8.2 和 Clang-7.0。
结果如下。
水平线表示每个布尔数组的大小。
在两个编译器中,std::all_of
对于大于 ~8 的大小表现出比简单实现更好的性能:
海湾合作委员会(DEMO):
叮当声 (DEMO):
看看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
对于几乎所有尺寸都显示出比简单实现更好的性能的原因:
/// 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 提出的函数至少在这些编译器中也会表现出更好的性能。
另一种使用现代 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);
}
因为这是C++,我们不需要写循环;我们可以使用 std::any_of
代替。
如果任何输入为假,我们需要我们的 NAND 门 return 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);
}
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
}
如果我使用 std::bitset
很多人会皱眉,但有了它就不需要函数了:
std::bitset<10> boo;
//...
bool boo_nand1= !boo.all();
bool boo_nan2=(~boo).any();