如何基于Eigen快速同时计算平方范数与归一化向量?
优化Eigen中百万次调用的
directedInverseSquare函数 问题分析
你的代码中,diff.normalized()和diff.squaredNorm()会重复计算差分向量的平方和:
normalized()内部会先调用squaredNorm()得到模长平方,再开根号得到模长,最后完成归一化- 后续又单独调用一次
squaredNorm()获取模长平方
对于百万次调用的场景,这种重复计算会带来显著的性能开销。而你提到的等价形式R/r³(R为差分向量)可以帮我们复用计算结果,避免重复开销。
优化实现
下面是直接复用平方和计算的优化版本,同时保留原逻辑的正确性:
#include <Eigen/Core> using Eigen::Vector2d; inline Vector2d directedInverseSquare(const Vector2d &pos1, const Vector2d &pos2) { Vector2d diff = pos2 - pos1; const double r_squared = diff.squaredNorm(); // 处理零点避免除以0的情况 if (r_squared == 0.0) { return Vector2d::Zero(); } const double r = std::sqrt(r_squared); // 等价于 rHat / r_squared,只计算一次平方和+一次开根号 return diff / (r_squared * r); }
关键优化点
- 复用平方和计算:仅调用一次
squaredNorm(),后续通过开根号得到模长r,避免原代码中两次计算平方和的开销 - 直接计算等价形式:
diff / (r_squared * r)完全等价于原逻辑的rHat / r_squared,但省去了单独生成rHat的步骤 - const引用参数:将
pos1/pos2改为const Vector2d &,既保证安全性,也有助于编译器进行优化 - inline修饰:对于高频调用的函数,
inline可以避免函数调用的额外开销
额外性能选项(精度换速度)
如果你的场景对精度要求不高,可以使用Eigen的fastNorm()替代std::sqrt(r_squared),它采用快速平方根近似算法,速度更快:
inline Vector2d directedInverseSquare(const Vector2d &pos1, const Vector2d &pos2) { Vector2d diff = pos2 - pos1; const double r = diff.fastNorm(); if (r == 0.0) { return Vector2d::Zero(); } const double r_cubed = r * r * r; return diff / r_cubed; }
Eigen原生函数说明
Eigen并没有直接提供同时返回归一化向量和平方距离的原生函数,但通过上述手动复用计算的方式,已经能达到比原生分开调用更优的性能——本质上是避免了重复的平方和计算,这是原生分开调用无法做到的。
内容的提问来源于stack exchange,提问作者Malmel
相关产品推荐
相关产品推荐

