c++ - Eigen 版本 3.2.0 和 3.3.4 之间的数值差异
问题描述
我最近推出了一个使用一些基本向量数学和SelfAdjointEigenSolver
从Eigen 3.2.0 到 3.3.4 的代码。该代码是用 Matlab 制作的,它与 3.2.0 一致。滚动到 3.3.4 的动机是避免在 C++11(及更高版本)和 3.2.0 中出现的一些警告和错误。
该代码通过将数千个点读入Eigen::Matrix<double, Eigen::Dynamic, 3>
. 当我使用 gdb 检查值时,输入值是相同的。一段显示数字差异的代码如下所示。 pilType
定义为double
。
// this is the point cloud, center it about the origin
Eigen::Matrix<pilType, 1, 3> center = gridPnts.colwise().mean();
gridPnts.rowwise() -= center;
// Get the transformation matrix to align the point cloud with it's normal
// Build the co variance matrix
Eigen::Matrix<double, 3, 3> S = gridPnts.transpose() * gridPnts;
S /= static_cast<pilType>(gridPnts.rows() - 1);
Eigen::SelfAdjointEigenSolver<pilMat3> es(S);
Eigen::Matrix<pilType, 3, 2> trans;
trans = es.eigenvectors().block<3, 2>(0, 1);
// convert the point cloud to 2D for Convex Hull calculation
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> output(gridPnts.rows(), 2);
output = gridPnts * trans;
我正在使用 GCC 5.3.0 编译新版本,标志 -std=c++11 -O3 -DEIGEN_NO_DEBUG -Wall -Wextra -Werror -march=native -mtune=native。我尝试过使用和不使用 March 和 mtune 选项。旧版本使用 GCC 4.3.4 和标志 -O3 -DEIGEN_NO_DEBUG -Wall -Wextra -Werror 编译。CPU 是运行 SuSE Enterprise SLES 11 的 SandyBridge E5-2670。差异在划分后开始S
通过点数 - 1。它们非常小,大约为 1e-12,但是当涉及到特征解时,非常接近 0 的值会导致特征向量中的符号发生变化。这会导致转换矩阵针对一个轴进行切换。结果输出沿该轴翻转。生成的 2D 补丁被发送到一个例程以找到凸包。由于轴翻转,返回相同的点但顺序相反。这不是错误,但出乎意料。
事实上,在整个申请中,不同的数字显示了 1e-12 到 1e-15 范围内的差异。
以下是使用 GDB 运行时的一些值(最高值来自 3.3.4 版本,较低值来自 3.2.0)
S
划分前:
Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb0b0) = {[0,0] = 3532221.7020642869,
[1,0] = 1.0913936421275139e-11, [2,0] = 3332.4628071428679, [0,1] = 1.0913936421275139e-11,
[1,1] = 335265.83999999962, [2,1] = -1.3073986337985843e-12, [0,2] = 3332.4628071428679,
[1,2] = -1.3073986337985843e-12, [2,2] = 4697.4509785714226}
Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb8f0) = {[0,0] = 3532221.7020642869,
[1,0] = 1.0913936421275139e-11, [2,0] = 3332.4628071428679, [0,1] = 1.0913936421275139e-11,
[1,1] = 335265.83999999962, [2,1] = -1.3073986337985843e-12, [0,2] = 3332.4628071428679,
[1,2] = -1.3073986337985843e-12, [2,2] = 4697.4509785714226}
S
分工后
Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb0b0) = {[0,0] = 21151.028156073575,
[1,0] = 6.5352912702246338e-14, [2,0] = 19.954867108639927, [0,1] = 6.5352912702246338e-14,
[1,1] = 2007.5798802395186, [2,1] = -7.8287343341232597e-15, [0,2] = 19.954867108639927,
[1,2] = -7.8287343341232597e-15, [2,2] = 28.128448973481571}
Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb8f0) = {[0,0] = 21151.028156073575,
[1,0] = 6.5352912702246351e-14, [2,0] = 19.954867108639927, [0,1] = 6.5352912702246351e-14,
[1,1] = 2007.5798802395188, [2,1] = -7.8287343341232597e-15, [0,2] = 19.954867108639927,
[1,2] = -7.8287343341232597e-15, [2,2] = 28.128448973481575}
在执行特征解之后,其值为trans
:
{[0,0] = 3.4096942364292876e-18, [1,0] = -1,
[2,0] = 3.9893751393767394e-18, [0,1] = 0.99999955376919869, [1,1] = 3.4134614846087836e-18,
[2,1] = 0.00094470175363752104}
{[0,0] = 0, [1,0] = 1,
[2,0] = -3.2750362278258563e-15, [0,1] = 0.9999995537691988, [1,1] = 3.093932467653499e-18,
[2,1] = 0.00094470175363752125}
诚然,数值差异非常小,并且在准确性的噪音范围内。在显示的数字中,变换矩阵的符号翻转,导致 2D 云翻转。有没有办法清理所做的事情以使这些差异消失?我见过一些Eigen
具有小值阈值的函数,但我没有看到一个用于除法的函数。
解决方案
您根本不应该依赖特征向量上的符号(无论求解器和库如何),而是根据您的需要调整它们。例如,如果您想确保有一个右手基,则从前两个的叉积中更新最后一个。
推荐阅读
- python - Python PandaSQL sqldf 没有这样的表错误,但是如果手动执行函数它将起作用
- python - *Python* 非递归函数和字符串
- python - 在python中设置imageio压缩级别
- python - 将列表中的项目附加到带有规则的 Pandas df
- javascript - Firefox Web 控制台 - 网络活动
- java - 异常堆栈跟踪和原因未映射到 Micronaut 2.5.8 中的自定义全局异常处理
- java - 在 jooq 的条件表达式中使用自定义数据类型
- maven - 为什么 SonarScanner for Maven 会跳过除根项目之外的所有项目
- reactjs - rtk 查询突变被拒绝
- wordpress - 等待meetlookup.com