测试两个 valarray<double> 是不是相等的最佳方法?

Posted

技术标签:

【中文标题】测试两个 valarray<double> 是不是相等的最佳方法?【英文标题】:Best way to test for equality of two valarray<double>?测试两个 valarray<double> 是否相等的最佳方法? 【发布时间】:2015-06-29 21:22:53 【问题描述】:

我认为==对于valarray的默认重载不是很方便。默认情况下,x==y(对于两个 valarrays x 和 y)返回一个 valarray&lt;bool&gt;,如果 x[i]==y[i],则在 ith 条目上带有 true。相反,我需要一个bool,它告诉我两个valarray&lt;double&gt; 是否包含相同的元素。我知道我可以用一个循环来做到这一点,但是每次都必须做这个循环并不方便。这里最好的解决方法是什么?有没有办法让我定义我自己的 == 重载(以及 !=&lt; 等)?

【问题讨论】:

***.com/questions/24628918/… std::valarray&lt;bool&gt; 上做一个sum @user3528438 sumand 布尔值吗? valarray&lt;bool&gt;的返回值用std::all_of包裹起来方便吗? 【参考方案1】:

“不是很方便”?这种行为正是valarray 的原因。

要覆盖它完全是弄巧成拙。

如果您不喜欢它,请改用vector

【讨论】:

我喜欢x+yvalarray 工作的方式,如果我使用vector,我就无法做到这一点。但我认为x==y 应该返回一个bool。有没有办法只修改==(以及其他比较)? @becko:哼,写个简单的函数就行了? + 只是一个例子。我也想要-*,等等。此外,我知道valarray 已经设计了这些运算符的版本,这些版本比简单的实现更有效(我认为他们使用代理类将中间结果存储在像x + y + z 这样的表达式中,然后一起评估整个表达式)。我想利用这些。【参考方案2】:

不要覆盖默认的operator== 使用例如这个代替:

bool isEqual( const std::valarray< bool >& aResult )

    bool equals = true;
    for ( auto item : aResult )
    
        equals &= item;
    
    return equals;

然后使用它:

std::valarray< int > x;
std::valarray< int > y;

bool equals = isEqual( x == y );

【讨论】:

如果我可以(我可以吗?如何?)覆盖默认的operator==,为什么不这样做呢?这比isEqual(x==y) 更容易阅读。 @becko 因为运营商已经完成了您需要的一半。另一方面,如果x!=y 则不必比较所有元素。看看什么会更快会很有趣。 @tobi303 x==yx!=y 都可以短路(在这个答案中很容易解决)。 @becko 我不是指操作员!=,而是在 x 不等于 y 的情况下对== 的评估。当然,!= 也是如此。 @becko 据我了解,在答案中所有元素都进行了比较(通过内置的x==y)。他只将所有这些结果的 AND 短路,而已经可以将元素的比较短路(但这需要不使用内置的 ==【参考方案3】:

我同意其他人不覆盖== 运算符。原因是这些运算符是使用valarray 的主要原因。如果您不需要逐元素运算符,请不要使用valarray。此外,您可能在某些时候需要原始版本的操作符,那么为什么要扔掉它呢?

我喜欢 p.i.g 的解决方案,但如果效率是一个主要问题,我会这样修改它:

#include <utility>
#include <valarray>

template <typename T>
bool isEqual( const std::valarray<T>& x,const std::valarray<T>& b) 
    bool equals = true;

    for (auto it = std::make_pair(std::begin(x), std::begin(b));it.first != std::end(x);++it.first,++it.second) 
        equals &= ((*it.first) == (*it.second));
        if (!equals) break;
    
    return equals;

并像这样使用它

valarray<T> x,y;
bool b = isEqual(x,y);

如果不使用内置的==,则不必比较 valarray 中的所有元素。

PS:

+ 只是一个例子。我也想要-、*等。此外,我知道 valarray 有这些运算符的人为版本,它们比简单的实现更有效(我认为他们使用代理类将中间结果存储在 x + y + z 这样的表达式中,然后一起评估整个表达式)。我想利用这些。

其实,这很有趣,我以前不知道。结论应该是:不要覆盖这些运算符,否则您将无法利用它们的巧妙实现。

【讨论】:

@Anakhand 哼,好像我根本没有测试代码。真丢人。直到现在我才意识到该函数将第一个参数的元素与第一个参数的元素进行比较:/ @Anakhand 谢谢,已修复(还没有测试过)【参考方案4】:

如果您决定为商品“覆盖”std::valarrayoperator==(而不是像 user463035818's answer 那样编写命名函数),您可以编写一个自定义“适配器”类:

template<typename T>
class CustomValArray : public std::valarray<T> 
public:
    typedef std::valarray<T> base;
    // We need to re-implement any non-default constructors we want to use:
    CustomValArray(std::initializer_list<T> init) : base(init) 
;

/// Accumulation (single bool) comparison 
template<typename T>
bool operator==(const CustomValArray<T> &lhs, const CustomValArray<T> &rhs) 
    return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));

如果您还希望能够将原始operator== 用于std::valarray,您可以通过编写一个命名函数来实现:

/// Element-wise comparison
template<typename T>
auto elementWiseEqual(const CustomValArray<T> &lhs, const CustomValArray<T> &rhs)  
    // We delegate to operator==(const std::valarray<T> &, const std::valarray<T> &)
    typedef std::valarray<T> base;
    return dynamic_cast<const base &>(lhs) == dynamic_cast<const base &>(rhs);

注意:上面的 sn-p 使用了 C++14 的自动返回类型推导。如果您使用的是 C++11,则应在声明符末尾添加类似 -&gt; decltype(std::valarray&lt;T&gt;() == std::valarray&lt;T&gt;()) 的内容。

Try it here.

如果您选择这样做,直接从std::valarray 继承,请注意possible risks of inheriting from an STL class。


作为替代方案,您可以拥有一个带有 std::valarray&lt;T&gt; 私有成员的包装类,并手动将您想要使用的任何成员函数委托给 std::valarray

【讨论】:

以上是关于测试两个 valarray<double> 是不是相等的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章

valarray 划分它的元素

将 std::vector 分配给 std::valarray

-cppC++中的代码重用

将数据从 std::vector 传递到 std::valarray 的最有效方法

20170928-2 单元测试

将 valarray<bool> 转换为 valarray<int>