我使用Boost.Test来测试数值非常多。我经常要比较数学对象的值。下面是一个玩具示例,展示了我必须进行相当多的测试。
#define BOOST_TEST_MODULE VektorTest
#include <boost/test/included/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
struct Vector {
Vector(double x, double y, double z) : x(x), y(y), z(z) {}
double x;
double y;
double z;
};
BOOST_AUTO_TEST_CASE(Rotations, * boost::unit_test::tolerance(1.0e-2)) {
Vector vector1(1.5,3.,7.4);
Vector vector2(1.51, 3.01, 7.41);
// The following can get really annoying and is error prone.
BOOST_TEST(vector1.x==vector2.x);
BOOST_TEST(vector1.y==vector2.y);
BOOST_TEST(vector1.z==vector2.z);
// This should be the expected usage, but only if the tolerance is considered.
// BOOST_TEST(vector1==vector2); // Will not compile!
}
我可以教Boost.Test识别考虑boost::unit_test::tolerance
装饰器的自定义类型吗?
仅仅对x,y,z
对象的内容Vector
进行一对一的比较将是不可行的解决方案。
#define BOOST_TEST_MODULE VektorTest #包括 #include
struct Vector { 矢量(双x,双y,双z):x(x),y(y),z(z){}
double x;
double y;
double z;
};
修改
在我更仔细地研究了Boost.Test的文档之后,我找到了有趣的函数per_element()
,它允许对序列中包含的值进行比较。这个函数已经是一个很大的好处,因为它考虑了tolerance
装饰器,如下所示。 std::vector<T>
满足序列接口,可以在此框架中很好地使用。
Boost.Test文档说,序列应该实现size()
和begin()
函数,以及字段const_iterator
和value_type
。至于我,这不是一个可行的解决方案,因为我无法改变数学类的界面。更多的是我无法扩展下面的玩具示例来满足这个界面。
#define BOOST_TEST_MODULE VektorTest
#include <boost/test/included/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
struct Vector {
Vector(double x, double y, double z) : x(x), y(y), z(z) {}
double x;
double y;
double z;
};
BOOST_AUTO_TEST_CASE(VectorTest, * boost::unit_test::tolerance(1.0e-4)) {
{
std::vector<double> vector1;
vector1.push_back(1.5);
vector1.push_back(3.);
vector1.push_back(7.4);
std::vector<double> vector2;
vector2.push_back(1.51);
vector2.push_back(3.01);
vector2.push_back(7.41);
BOOST_TEST(vector1==vector2, boost::test_tools::per_element());
}
{
Vector vector1(1.5,3.,7.4);
Vector vector2(1.51, 3.01, 7.41);
//BOOST_TEST(vector1==vector2, boost::test_tools::per_element()); // Will not compile!!!
}
}
答案 0 :(得分:1)
我不确定完全理解您的问题,但也许BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE
(请参阅here)就是您问题的答案。
如果您想将Vektor
视为应执行基于容差的比较的类型,那么您可以在文档中查看here
您需要的是:
EqualityComparable
,LessThanComparable
)。所有比较(参见here和there)操作都涉及要计算的两个值之间的差异,因此您需要您的类实现LessThanComparable
,否定 - 绝对值 - 以及来自单一价值 - 原产地所需 - 。 boost.operators
在这里可能会有很好的帮助。 tolerance_based
专业化来通知boost.test您的班级与基于宽容的操作兼容在您的情况下,您要实现的容差区域位于特定位置周围的3D立方体内。给出容差\ epsilon,
所有这些操作都由close_at_tolerance执行。
由于您想要执行每轴的公差,您可以实现
operator-
为每轴差异operator-
(一元否定)作为每轴的否定operator<
作为每轴比较operator/
作为每轴的分割等。 operator<
和operator-
(一元)用于计算绝对值。
但是,这不会按预期工作,因为std::max
和std::min
也应该实施(请参阅here)。在您的情况下,他们应该为每个轴提供max
和min
。目前
close_at_tolerance
的专业化(请参阅here)。std::min
和std::max
并专门设置boost::math::fpc::fpc_detail::fpt_abs
(私有API)以计算绝对值。在一天结束时,这只是比较问题。公差,差异和绝对值计算。
如果你选择
|v1 - v2| = (|a1-a2|, |b1-b2|, |c1-c2|)
|v1 - v2|/|v1| = (|a1-a2|/|a1|, |b1-b2|/|b1|, |c1-c2|/|c1|) // same for v2
max(|v1 - v2|/|v1|, |v1 - v2|/|v2|) = (max(|a1-a2|/|a1|, |a1-a2|/|a2|),
max(|b1-b2|/|b1|, |b1-b2|/|b2|),
... )
进行测试所需的是:
|v1 - v2|/|v1| < eps. && |v1 - v2|/|v2| < eps.
=> max(|v1 - v2|/|v1|, |v1 - v2|/|v2|) < eps.
=> max(|v1 - v2|/|v1|, |v1 - v2|/|v2|) < vektor(eps., eps., eps.)
=> max(|a1-a2|/|a1|, |a1-a2|/|a2|) < eps.
&& max(|b1-b2|/|b1|, |b1-b2|/|b2|) < eps. ...
它与每轴的最大值,除法和比较一致。