第 35 章 · Eigen 进阶技巧
最后一章 Eigen讲实战中常用的技巧和模式与 STL 结合、自定义函数、常用工具函数、用Eigen::Map接管外部数据、内存对齐以及几个容易被忽略的坑。35.1 用 vector 管理一批矩阵实战中经常要存一批矩阵/向量用std::vector#includevector#includeEigen/Dense#includeiostreamintmain(){// 存一批 3D 点std::vectorEigen::Vector3dpoints;points.push_back(Eigen::Vector3d(1,0,0));points.push_back(Eigen::Vector3d(0,1,0));points.push_back(Eigen::Vector3d(0,0,1));// 遍历求和Eigen::Vector3d totalEigen::Vector3d::Zero();for(constautop:points){totalp;}std::cout总和 total.transpose()std::endl;// 1 1 1return0;}打印这一行不是可有可无的算出结果却不输出程序跑起来一句话都不说你会以为它坏了。每个完整示例都至少要有像样的输出这是本书写代码的习惯也是你验收自己代码的习惯。35.2 写操作矩阵的函数把常用操作封装成函数参数用const MatrixXd// 计算矩阵所有元素的和doublesumAll(constEigen::MatrixXdm){returnm.sum();}// 把矩阵归一化每列除以自己的范数Eigen::MatrixXdnormalizeColumns(constEigen::MatrixXdm){Eigen::MatrixXd resultm;for(Eigen::Index j0;jm.cols();j){result.col(j).normalize();// 每列归一化}returnresult;}35.3 模板函数处理任意 Eigen 类型想写一个能处理任意类型MatrixXd、Matrix3d、VectorXd的函数用模板templatetypenameDeriveddoublesumAll(constEigen::MatrixBaseDerivedm){returnm.sum();}MatrixBaseDerived是所有矩阵类型的基类模板能接受任何 Eigen 矩阵。35.4 常用工具函数Eigen 内置了很多方便的工具v.normalized();// 返回单位向量不修改原向量v.normalize();// 原地归一化m.cwiseProduct(n);// 逐元素乘等价 .array()*m.cwiseAbs();// 逐元素绝对值m.cwiseMax(other);// 逐元素取最大Eigen::Vector3d vEigen::Vector3d::UnitX();// X 轴单位向量Eigen::Vector3d uEigen::Vector3d::UnitY();// Y 轴Eigen::Vector3d wEigen::Vector3d::UnitZ();// Z 轴35.5 生成单位向量、对角矩阵// 单位轴向量Eigen::Vector3d xEigen::Vector3d::UnitX();// (1,0,0)// 把向量变成对角矩阵Eigen::Vector3dd(1,2,3);Eigen::Matrix3d Dd.asDiagonal();// 对角矩阵 diag(1,2,3)35.6 三维向量的几何操作Eigen::Vector3da(1,0,0),b(0,1,0);doubleanglestd::acos(a.dot(b));// 两向量夹角Eigen::Vector3d normala.cross(b);// 法向量垂直两者doubledist(a-b).norm();// 两点距离35.7 Eigen::Map把外部数据零拷贝接进 Eigen实战中数据常常不在 Eigen 矩阵里而在一段普通内存里C 接口给的double*、传感器缓冲区、std::vectordouble、别的语言传过来的数组。Eigen::Map让你不拷贝地把这块内存当成矩阵用——它只是一个视图改它就等于改原数据。#includeEigen/Dense#includecstdint#includeiostream#includevectorintmain(){// 1) 一段普通 C 数组比如驱动/其他语言给你的缓冲区当矩阵用doubleraw[6]{1,2,3,4,5,6};Eigen::MapEigen::MatrixXdm(raw,2,3);// 默认按「列优先」解读这块内存std::coutMap 出来的 2x3:\nm\n;// 2) 同一块内存换「行优先」解读Eigen::MapEigen::Matrixdouble,2,3,Eigen::RowMajorrm(raw);std::coutRowMajor 视角:\nrm\n;// 3) 改视图就是改原数组全程没有第二份数据m(0,0)100.0;std::cout改 m(0,0) 之后 raw[0] raw[0]\n\n;// 4) 与 std::vector 衔接数据存在 vector 里想让 Eigen 就地算std::vectordoublebuf{1,2,3,4};Eigen::MapEigen::Vector4dv(buf.data());v*2.0;std::coutvector 被就地改成:;for(doublex:buf)std::cout x;std::cout\n\n;// 5) 只取数组中间一段这里内存不满足对齐要求显式写 UnalignedEigen::MapEigen::Vector2d,Eigen::Unalignedpart(raw[1]);std::cout从 raw[1] 起的两个数 part.transpose()\n;// 6) C17 的 new 会遵守对齐要求vector 里直接放 Eigen 类型是安全的std::vectorEigen::Vector4dpts(3);boolaligned16(reinterpret_caststd::uintptr_t(pts.data())%160);std::coutvectorVector4d 的数据地址 16 字节对齐吗 (aligned16?是:否)\n;return0;}存成ch35_map.cpp按附录 C.3 编译运行实际输出-O0与-O2 -DNDEBUG完全一致Map 出来的 2x3: 1 3 5 2 4 6 RowMajor 视角: 1 2 3 4 5 6 改 m(0,0) 之后 raw[0] 100 vector 被就地改成: 2 4 6 8 从 raw[1] 起的两个数 2 3 vectorVector4d 的数据地址 16 字节对齐吗 是注意第 1、2 两段同一块内存读法不同矩阵就不同。raw里的 1 2 3 4 5 6按列优先排就是1 3 5 / 2 4 6按行优先排就是1 2 3 / 4 5 6。对接外部数据时先问清楚对方是哪种排法选错会得到转置了的结果——这正是第 17 章讲的行/列主序在真实工程里的样子。要点Eigen::MapMatrixXd(ptr, rows, cols)动态大小要显式给行列数固定大小可省MapVector4d(ptr)。Map不拥有内存也不拷贝原数据必须活得比 Map 久。想立刻固化一份自己的数据Eigen::MatrixXd copy m;这时才真拷贝。一次算完就丢的场合用 Map 能省掉整块拷贝大数组上差别很明显。35.8 关于「内存对齐」你需要知道的Eigen 用 SIMD 指令一次搬 2、4 甚至 8 个数这类指令要求数据起始地址是 16或 32字节倍数——这就是对齐。三个结论按重要程度排std::vectorEigen::Vector4d这类容器是安全的本书统一 C17 的原因之一。C17 起new会遵守类型的对齐要求上面第 6 段实测打印是。若你在 C11/14 下写这类代码Eigen 老文档会让你给容器加EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION或aligned_allocator——那套已经过时别在 C17 项目里照抄。**把 Eigen 类型作为结构体/类的成员或者放进固定数组编译器一般会自动处理对齐。**真正会出问题的是手工拿一个指针去 Map。Map 一个不保证对齐的地址时显式写Eigen::Unaligned上面第 5 段。默认Map...声称已对齐写错就是未定义行为本书在 MinGW x86-64 上故意用未对齐地址试过MapVector4d实测没有崩、结果也对但这不能当保证——同一段代码换到 ARM 或不同指令集上可能直接段错误。既然多写一个模板参数只要几秒钟别赌。一句话自己 new 的 Eigen 对象不用管对齐拿外来指针做 Map 时才需要想这件事。35.9 几个容易被忽略的坑坑 1MatrixXd::Random()的值范围Random()生成 [-1, 1) 的均匀随机数。想要 0~1 或整数要自己变换Eigen::MatrixXd rEigen::MatrixXd::Random(3,3);// [-1, 1)Eigen::MatrixXd r01(rEigen::MatrixXd::Ones(3,3))/2;// 映射到 [0, 1)坑 2整数矩阵的除法MatrixXi的除法是整数除法截断和 double 矩阵不同Eigen::Matrix2i a;a5,6,7,8;a/2;// 结果是 2 3; 3 4截断不是 2.5 3 ...坑 3临时表达式的生命周期// ❌ 危险auto 捕获临时表达式见第 34 章—— 假设 A 是矩阵、b 和 c 是向量autoxA*bc;// ✅ 用明确类型这里换个名字否则和上面的 x 重名编译不过Eigen::VectorXd x2A*bc;实测这个区别auto x A * b c;之后打印x得51 111此时把A重新赋成全 0再打印x变成了1 1——因为x里存的是待计算的表达式它跟着A变。而Eigen::VectorXd版本一赋值就把结果定下来了。要保留auto就写auto x (A * b c).eval();实测这样推导出的类型就是Eigen::VectorXd。坑 4resize会丢失数据resize到更小尺寸会丢弃超出的数据更大的会保留原有部分但新增部分是垃圾值。35.10 完整示例批量数据处理#includeEigen/Dense#includeiostream#includevectorintmain(){// 模拟一批数据点每个点 3 维std::vectorEigen::Vector3ddata;for(inti0;i5;i){data.push_back(Eigen::Vector3d(i,i*2,i*3));}// 求所有点的平均Eigen::Vector3d meanEigen::Vector3d::Zero();for(constautop:data)meanp;mean/data.size();std::cout平均值 mean.transpose()std::endl;// 求离平均值最近的点doubleminDist1e9;Eigen::Vector3d closest;for(constautop:data){doubled(p-mean).norm();if(dminDist){minDistd;closestp;}}std::cout最近点 closest.transpose()std::endl;return0;}存成ch35.cpp按附录 C.3 编译运行实际输出平均值 2 4 6 最近点 2 4 65 个点是 (0,0,0)、(1,2,3)、(2,4,6)、(3,6,9)、(4,8,12)平均值就是 (2,4,6)它本身恰好在点集里所以离平均值最近的点也是它。把循环里的i * 2改成i * 2 1再跑一次预测一下输出会变成什么再用程序验证——这种改一处、猜结果、跑一遍是学 Eigen 最快的节奏。35.11 小结vectorEigen::...管理一批矩阵。函数参数用const MatrixXd或模板。工具函数normalized、asDiagonal、UnitX/Y/Z、cwiseProduct。Eigen::Map把外部内存零拷贝当矩阵用先确认对方是行主序还是列主序。对齐只在拿外来指针做 Map时才需要考虑不保证对齐就显式写Eigen::Unaligned。注意 Random 范围、整数除法、auto 陷阱、resize 丢数据。 第三部分完成你已经完整掌握了 Eigen 库下一部分我们用两个综合项目把知识串起来并规划你的学习路线。练习题用std::vector存 5 个三维向量求它们的平均值。写一个模板函数求任意 Eigen 矩阵的元素的平均值。用asDiagonal把一个向量变成对角矩阵。求两个三维向量的夹角用acos(dot)。有一行 12 个double的数组用Eigen::Map把它当成 3×4 矩阵打印再换成行主序的 Map 打印一次比较两者差别。从数组中间某个元素开始Map应该加哪个模板参数为什么本书不推荐反正实测没崩的写法总结你学到的所有 Eigen 的坑。

相关新闻

TeamCenter ITK二次开发入门:从官方Demo到环境配置与避坑指南

TeamCenter ITK二次开发入门:从官方Demo到环境配置与避坑指南

简介:面向西门子Teamcenter平台从事ITK二次开发的工程师,这份官方Demo包聚焦集成工具包扩展场景,适合希望快速掌握定制开发流程的初、中级开发者。包内共225个文件,涵盖C/C与Java示例源码、XML与XSD配置定义、bat批处理编译链接脚…

2026/10/9 15:15:50 阅读更多 →
WiresharkPortable:便携式协议分析工具,30秒快速抓包与HTTPS/QUIC解密

WiresharkPortable:便携式协议分析工具,30秒快速抓包与HTTPS/QUIC解密

简介:WiresharkPortable是一款开箱即用的便携式网络协议分析器,面向网络管理员、安全工程师与开发人员,专为无安装环境下的实时抓包、协议解析与流量诊断而设计。资源包体为20.16MB的RAR压缩文件,虽未提供具体文件列表&#xff0c…

2026/10/9 15:15:50 阅读更多 →
北京路网Shapefile数据处理与Python网络分析实战指南

北京路网Shapefile数据处理与Python网络分析实战指南

简介:北京城区道路矢量数据包提供主城区范围内的精细化路网,覆盖主干道、次干道、支路及部分街巷,适合地理信息、城市规划与地图制图人员直接使用。压缩包共22个文件,大小约8.08兆字节,除核心的矢量图形、索引、属性表…

2026/10/9 15:14:48 阅读更多 →

最新新闻

2026年AI助手APP实战指南:从选型配置到效率翻倍

2026年AI助手APP实战指南:从选型配置到效率翻倍

2026年一开年,"效率翻倍"成了开发者群里出现频率最高的词,而翻倍这件事基本绕不开同一个核心工具——AI助手APP。过去两年我几乎把市面上能接触到的AI开发工具都试了一遍,从手机端随开随用的对话应用,到和IDE深度绑定的…

2026/10/9 15:53:45 阅读更多 →
基于TensorRT-LLM部署Qwen1.5:从编译到高并发推理实战

基于TensorRT-LLM部署Qwen1.5:从编译到高并发推理实战

简介:本资源面向希望掌握大语言模型高效推理部署的开发者与算法工程师,聚焦如何借助TensorRT-LLM对Qwen1.5进行推理加速与工程化落地,解决模型规模增大后推理速度慢、显存占用高、实时响应难等部署痛点,适合具备一定深度学习与GPU…

2026/10/9 15:53:45 阅读更多 →
依赖升级风险控制:package.json 和 requirements.txt 跨版本升级的 AI 辅助

依赖升级风险控制:package.json 和 requirements.txt 跨版本升级的 AI 辅助

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 15:53:45 阅读更多 →
C++链表从入门到进阶:节点、增删改查、反转合并与快慢指针

C++链表从入门到进阶:节点、增删改查、反转合并与快慢指针

不夸张地说,链表几乎是每个学C的人都会在某个阶段卡一下的东西。数组用顺手了之后,突然来了个需要手动申请内存、用指针串起来的数据结构,很多人第一次看到 Node* next 这种写法的时候都会有点懵。我当年学的时候,最直观的感受就…

2026/10/9 15:53:45 阅读更多 →
魔方阵的工程本质:从数学结构到确定性生成算法

魔方阵的工程本质:从数学结构到确定性生成算法

1. 魔方阵不是玩具,是数学结构的活体标本“魔方阵”这三个字一出来,很多人第一反应是手里那个能拧来拧去、颜色错乱后又拼命复原的塑料立方体。但今天要说的,和它半毛钱关系都没有——它不靠手指转动,不靠空间直觉,甚至…

2026/10/9 15:53:45 阅读更多 →
如何降低大模型 Token 调用成本?2026 年模型分级、缓存、路由和提示词优化清单(TaoToken 统一 Key 实践版)

如何降低大模型 Token 调用成本?2026 年模型分级、缓存、路由和提示词优化清单(TaoToken 统一 Key 实践版)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 15:52:43 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →