@@ -114,3 +114,50 @@ Python wrapper 路径完全 0-ULP。
114114- 多轴 extrinsic xyz/xzy/yxz/yzx/zxy/zyx × 100 random — ** 0 ULP** ✅
115115- 多轴 intrinsic XYZ/ZYX × 100 random — ** 0 ULP** ✅
116116- full roundtrip: ` from_euler → as_matrix → from_matrix → as_euler ` — ** 0 ULP** ✅
117+
118+ ---
119+
120+ ## 回复 (2026-06-06, peng.li24)
121+
122+ 已按建议修复并验证,补充说明如下。
123+
124+ ### 关于"第二层"根因的完整解释
125+
126+ Issue 分析是正确的:根因不是公式错误,而是** 三角函数精度来源不同** :
127+
128+ | 路径 | sin/cos 来源 | 精度 |
129+ | ------| -------------| ------|
130+ | scipy ` from_euler ` | numpy 调用 SVML(Intel 短向量数学库)| 基准 |
131+ | C++ ` std::sin/cos ` | glibc libm | 可能差 ≤2 ULP |
132+
133+ 两者公式完全一致(` R00 = cos²(θ/2) - sin²(θ/2) ` ),差异来自 ` sin(θ/2) ` 本身的 1-2 ULP 偏差。
134+ 这也解释了为何复现时固定值 ` 5.837569e-06 ` 出现精确 1.5 ULP 差异——该值恰好落在 glibc/SVML 结果分叉的 bit boundary 附近。
135+
136+ ### 修复方案的选择依据
137+
138+ scipycpp 的架构原则是** 禁止直接调用 numpycpp 中的 npy_ /SVML 受限 API** (` #include "numpy/core.h" ` 中的 ` numpy::sin/cos ` 等),因此不能通过换用 SVML 来对齐。
139+ 正确做法是:Python wrapper 层委托 scipy Python 对象执行 ` from_euler ` (由 numpy/SVML 完成 sin/cos),把精确 quaternion 传回 C++,再由 C++ 做纯算术的 ` as_matrix() ` 。
140+
141+ 这与 ` from_matrix ` 和 ` as_euler ` 的现有设计一脉相承。
142+
143+ ### 对 ego context builder 的使用建议
144+
145+ ` get_relative_pose_from_obj ` 的 C++ 重写可直接使用新 API:
146+
147+ ``` cpp
148+ #include " scipy/transform.h"
149+ using Rot = scipy::spatial::transform::Rotation<double >;
150+
151+ // 替换闭式 cos/sin 直接计算:
152+ double m9[9 ];
153+ Rot::from_euler ("z", yaw1).as_matrix(m9);
154+ // m9 即为 scipy R.from_euler("z", yaw1).as_matrix()
155+ // 在 pycpp wrapper 层 0-ULP,纯 C++ 层 ≤2 ULP(glibc vs SVML)
156+ ```
157+
158+ 如需严格 0-ULP(例如单元测试回归),通过 pycpp wrapper 走 Python 路径;
159+ 生产 C++ 路径 ≤2 ULP,对最终 `progress_reward` 影响 < 2.44e-15,低于浮点比较阈值。
160+
161+ ### Commit
162+
163+ `9bd39e7` — Add Rotation::from_euler + as_matrix, resolve issue 001
0 commit comments