News Hacker|极客洞察

138 64 天前 16bpp.net
🔍隐匿已久的更快 asin:老公式与性能/精度权衡
连 Abramowitz 的表都不翻了?

🎯 讨论背景

帖子基于一篇把旧近似公式(源自 Hastings 1955,并被 Abramowitz and Stegun 收录)和 shader/CG 实现重新整理、用 minimax/Remez 或多项式调整并做基准比较的文章。讨论延伸到数值逼近方法(Remez、Chebyshev、Pade、Taylor 的利弊)、编译器对浮点重排的限制(默认 IEEE 754 语义下不会做某些优化除非启用 -ffast-math)、以及不同硬件/库(Apple M 系列 libm、glibc、fdlibm)在精度与性能上的权衡。评论普遍指出图形/游戏领域在工程实践中保留了大量“放宽精度以换取速度”的技巧,而这些知识常被教学与系统库忽视,导致被后来的工程师反复“重新发现”。

📌 讨论焦点

历史来源与知识复用

多位评论指出这并非新发明:更快的 asin 近似可以追溯到 Hastings 1955 的工作,并被 Abramowitz and Stegun(数学函数参考手册,后由 NIST 的 DLMF 托管)以公式 4.4.45 收录,后又被 NVIDIA Cg 等着色器数学库沿用。很多实现躲在“死软件”的文档或旧参考书里,图形/游戏开发者在工程压力下反复重发现这些近似并把它们留在引擎代码中,但这些经验很少回流到系统级库或教学中。评论还提到早期库(如 fdlibm)里已有相关实现,说明历史实现可直接复用且能省去大量重复研究工夫。

[来源1] [来源2] [来源3] [来源4] [来源5]

逼近方法与误差分析(minimax / Remez / Chebyshev)

讨论集中在用什么逼近方法更合适:minimax(通过 Remez 算法生成的最小最大误差多项式)在给定区间内通常能取得最佳的“等波动”误差分布,观察误差波形是否出现典型的 minimax 振铃是辨别是否到位的关键。很多评论批评直接用 Taylor 或基于 Taylor 的 Pade 在截断项数有限时效果较差;如果要用 Pade,应针对原函数而非 Taylor 展开。Chebyshev 多项式被推荐为更简单且在许多情况下足够接近最优的方法,但 Remez 在 asin 这类函数的端点附近可能需要手工修正或特别采样策略。社区也提到实用工具(如 lolremez)能自动生成系数并按绝对/相对误差重新优化以满足工程约束。

[来源1] [来源2] [来源3] [来源4] [来源5] [来源6] [来源7]

编译器、霍纳法与浮点重排的限制

多条评论讨论多项式求值的实现细节:Horner 形式能显著减少乘法次数并通常改善数值稳定性,但它改变了运算顺序,浮点运算非结合性使得编译器在默认 IEEE 754 语义下不会自动把展开表达式改写为 Horner,除非启用 -ffast-math 或 -fassociative-math 等选项,这会放弃某些精度/确定性保证。有人指出 Horner 形成长依赖链可能影响 ILP(指令级并行),但在实际示例中朴素展开的依赖关系并不一定更好;编译器的 CSE(公共子表达式消除)在浮点上也受限。结论是对浮点性能与精度不要盲目依赖编译器,必要时应手动重构或显式选择编译选项以获得可预测的速度/误差特性。

[来源1] [来源2] [来源3] [来源4] [来源5] [来源6] [来源7]

硬件与库的权衡:精度、向量化与平台差异

对比结果在不同平台上差异很大:有人注意到作者在 x86 上测得约 1.5× 的加速,而 Apple M 系列上只有 ~1.02×,这暗示 Apple 的 libm 已为 M 系列流水线做了专门调优,而 glibc 在 x86 上较为保守因此留有可优化空间。评论详细讨论了精度/速度权衡:文章里的近似对图形场景足够(示例约为 2.7e11 ULP 量级的误差),但远不能作为系统库的替代;另外使用正确取整的 sqrt 在该误差预算下是过剩的,改用 rsqrt+多项式修正或近似 sqrt 能换来更好的向量化性能。还提到历史上 x86 的 rsqrt 指令语义未完全规范导致厂商差异,后续 ARM NEON/SVE 与 AVX512F 等对近似估计提供了更明确的架构级定义,这影响跨厂商可重复性与移植策略。

[来源1] [来源2] [来源3] [来源4] [来源5] [来源6] [来源7]

工程实践与成本收益:SIMD、LUT 与微优化价值

评论在实用层面上权衡小幅加速的价值:有人建议首选 SIMD/向量化或把计算移到 GPU,因为一次向量化往往比对单个函数做微观优化带来更大收益,但像光线追踪这种分支与内存访问不规则的工作负载,数据布局(SoA vs AoS)与分支组织决定了向量化的可行性。关于查表(LUT),评论指出微基准里 LUT 常能取胜,但在真实程序中会引入缓存污染与不可预测性,只有当访问局部性强且表能驻留在 L1 时才划算。是否值得为了 1–4% 做专门优化存在分歧:有人强调小改进在大规模服务或累积优化里能带来显著成本节约,而另一些人提醒要考虑维护、可移植性与数值一致性的成本。

[来源1] [来源2] [来源3] [来源4] [来源5] [来源6] [来源7]

工具、复现与学习差距(LLM、老文献与经典技巧)

有评论嘲讽文章作者用 LLM 找到的解决方案其实在多年以前的 StackOverflow 或参考实现里就有,说明检索/生成工具会把旧知识快速复现,但不代替对经典文献的熟悉。社区推荐的实践工具与参考包括 lolremez(生成 Remez 系数)、Hacker's Delight(位运算与近似技巧的经典集合),以及 Fast inverse square root(Quake 的快速倒平方根)作为“老技巧被重新发现”的代表性例子。总体观点是现代 CS 教育对数值分析与近似方法覆盖不足,查阅 Abramowitz & Stegun、Hastings 或 fdlibm 等原始资料常能避免重复造轮子。

[来源1] [来源2] [来源3] [来源4] [来源5] [来源6]

📚 术语解释

Horner's scheme (霍纳法): 一种嵌套乘加的多项式求值形式,通过把多项式写成 (((a_n x + a_{n-1}) x + ... ) ) 来减少乘法次数并通常改善数值稳定性;但它改变了运算顺序,浮点下非位等价,且可能形成长的依赖链。

Remez algorithm: 用于生成 minimax(最小化最大误差)多项式逼近的迭代算法,可直接针对区间上的绝对或相对误差最优化,端点或采样策略不当时可能需要人工干预。

Chebyshev approximation (Chebyshev 多项式逼近): 以 Chebyshev 多项式为基底的逼近方法,常能得到接近 minimax 的均匀逼近,算法相对简单且数值特性良好,常作为 Remez 的实用替代或初始解。

Abramowitz and Stegun: 一部经典的数学函数参考手册(Handbook of Mathematical Functions),收录大量函数表与近似公式(例如 4.4.45),其数值内容后被 NIST 的 DLMF 数字化继承,常是函数近似与参考实现的权威来源。

rsqrt(reciprocal square root,快速倒平方根): 硬件/指令集常提供的倒平方根估算(如 x86 的 rsqrtps/rsqrtss 或 ARM 的 NEON 估算),通常需用 Newton-Raphson 或多项式进一步修正以提高精度;历史上 x86 的语义不完全规范,后续架构对估算语义进行了更明确的规定。

ULP (unit in last place): 衡量浮点舍入误差的单位,表示数值在尾数最低位的增量,常用来说明近似或函数实现的精度损失(例如“子 ULP”或“若干 ULP”)。