在创建用于获取行平均值的矩阵xf 的副本时遇到错误。它似乎在调试中生成非常大的值,在发布中生成零值。在这两种情况下,答案都是错误的,因为平均值是 0.5。如果我不使用额外的行来创建输入副本,则错误就会消失并且输出将按预期进行。为什么会出现这种情况?
我在 cpp 中创建了一个最小的示例。我在 vs2022 中使用 cl.exe 和 cmake 编译它。
int main() {
auto startTime = std::chrono::high_resolution_clock::now();
#ifdef NDEBUG
std::cout << "Release Build" << std::endl;
#else
std::cout << "Debug Build" << std::endl;
#endif
std::cout << "Eigen world version: " << EIGEN_WORLD_VERSION << "\n";
std::cout << "Eigen major version: " << EIGEN_MAJOR_VERSION << "\n";
std::cout << "Eigen minor version: " << EIGEN_MINOR_VERSION << "\n";
std::cout << "cpp version: " << __cplusplus << "\n";
Eigen::setNbThreads(1);
std::cout << "Eigen threads: " << Eigen::nbThreads() << "\n";
Eigen::MatrixXf inputs(2, 4);
inputs <<
1, 0, 1, 0,
1, 1, 0, 0;
Eigen::MatrixXf calcNextLine = inputs;
calcNextLine = calcNextLine.rowwise().mean();
Eigen::MatrixXf calcSameLine = inputs.rowwise().mean();
std::cout << "\ninputs = \n" << inputs << "\n";
std::cout << "\ncalcNextLine = \n" << calcNextLine << "\n";
std::cout << "\ncalcSameLine = \n" << calcSameLine << "\n";
auto currentTime = std::chrono::high_resolution_clock::now();
auto deltaTime = std::chrono::duration_cast<std::chrono::nanoseconds>(currentTime - startTime).count();
std::cout << "\nFinished in " << (deltaTime / 1.0e6) << " milliseconds.\n";
return 0;
}
调试中的控制台输出:
Debug Build
Eigen world version: 3
Eigen major version: 4
Eigen minor version: 0
cpp version: 199711
Eigen threads: 1
inputs =
1 0 1 0
1 1 0 0
calcNextLine =
-1.07901e+08
-1.07901e+08
calcSameLine =
0.5
0.5
Finished in 4.2896 milliseconds.
发布中的控制台输出:
Release Build
Eigen world version: 3
Eigen major version: 4
Eigen minor version: 0
cpp version: 199711
Eigen threads: 1
inputs =
1 0 1 0
1 1 0 0
calcNextLine =
0
0
calcSameLine =
0.5
0.5
Finished in 3.6746 milliseconds.
如果我不使用额外的行来创建输入副本,则错误就会消失并且输出将按预期进行。为什么会出现这种情况?
这不是副本。以下是该特定行中发生的情况:
calcNextLine = calcNextLine.rowwise().mean();
rowwise().mean()
创建一个表示部分归约的对象,该对象 引用 calcNextLine
矩阵。calcNextLine
本身,调用其赋值运算符我很确定有关别名问题的 Eigen 文档页面解释了这些内容,但该网站目前(再次)不可用。一般来说,只有在以下情况下,才可以在 Eigen 中的赋值左侧和右侧之间使用别名:
left_side.noalias() = right_side
a = a + b
。这不行:a.topRows(N) = a.middleRows(1, N) + b
无论如何,你如何解决这个问题?两种选择:
eval()
创建一个新向量,然后将其分配给其输入calcNextLine = calcNextLine.rowwise().mean().eval();