算法与计算机科学moyix.blogspot.com
有人在捣鼓我的次正规浮点数
Someone’s Been Messing with My Subnormals
2022 — 2024,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
这篇博客文章讲述作者发现某些编译器(如 GCC 的 -ffast-math)会在程序启动代码中悄悄修改浮点控制寄存器,启用 FTZ/DAZ 模式,把次正规数(subnormal numbers)刷新为零,从而改变浮点运算的语义。作者追踪了这一隐蔽行为的来源,并展示了如何在代码中检测和恢复这些被篡改的浮点设置。
为什么经久不衰:它揭示了一个潜伏多年、影响无数程序的隐蔽陷阱:编译器优化标志会全局篡改浮点行为,这类问题至今仍会在数值计算中造成难以排查的错误。
HN 评论精选
第三方 DLL 也会篡改浮点控制字,作者用反向包裹调用的方式解决了类似问题
在之前的公司,我们的 Windows 软件会随机崩溃。调试后发现,只有当用户在本次会话中先打印过东西或打开过文件选择器时才会触发。罪魁祸首是某个打印机驱动或 shell 扩展 DLL,它加载时会把浮点控制字改为陷阱模式——因为它是用某个特定编译器编译的,该编译器在每个 DLL 的启动例程里都塞入了这段代码。我们的解决方案与文中相反:不是包裹自己的例程临时设置正确的浮点控制字,而是包裹打印和文件选择器的调用,在调用后把浮点控制字恢复为之前的正常值。
cesarb查看英文原文
At a previous company I worked at, we had an issue with our software (Windows-based, written in a proprietary language) randomly crashing. After some debugging, we found that this happened whenever the user made some specific actions, but only if, in that session, the user had previously printed something or opened a file picker. The culprit was either a printer driver or a shell extension which, when loaded, changed the floating point control word to trap. That happened whenever the culprit DLL had been compiled by a specific compiler, which had the offending code in the startup routine it linked into every DLL it produced. Our solution was the inverse of the one presented in this article: instead of wrapping our routines to temporarily set the floating point control word to sane values, we wrapped the calls to either printing or the file picker, and reset the floating point control word to its previous (and sane) value after these calls.
Julia 生态通过报错和语义层面的 @fastmath 防止全局浮点设置被滥用
Julia 包生态对这类静默错误行为有很多防护。例如,如果某个包的二进制构建试图使用 fast math 标志,会直接报错让你悔过。用户代码可以用 @fastmath,但它是语义层面的,只会把 sin 换成 sin_fast,不会递归进入别人的函数——否则就是自找麻烦。也有人建议把它改名为 @unsafemath 以示警告。总之 fastmath 被滥用了,很多人其实想要的是其他优化(如自动 FMA),大家不该随意做全局修改,语言也应在语义和包生态规范上阻止这种全局性问题。
ChrisRackauckas查看英文原文
The Julia package ecosystem has a lot of safeguards against silent incorrect behavior like this. For example, if you try to add a package binary build which would use fast math flags, it will throw an error and tell you to repent: https://github.com/JuliaPackaging/BinaryBuilderBase.jl/blob/186b1350fa925ff9722d320b4c8549ec6a5735db/src/Runner.jl#L289 In user codes you can do `@fastmath`, but it's at the semantic level so it will change `sin` to `sin_fast` but not recurse down into other people's functions, because at that point you're just asking for trouble. There's also calls to rename it `@unsafemath` in Julia, just to make it explicit. In summary, "Fastmath" is overused and many times people actually want other optimizations (automatic FMA), and people really need to stop throwing global changes around willy-nilly, and programming languages need to force people to avoid such global issues both semantically and within its package ecosystems norms.
FTZ/DAZ 修改昂贵且非标准,编译器支持差,是问题难以根治的原因
问题在于启用 FTZ/DAZ 标志需要修改全局(严格说是线程局部)状态,而且开销相对较大。理想情况下只想对需要的代码启用,但由于开销,无法自动给每个函数调用加上,手动做又很困难,因为编译器对访问浮点状态的支持很差。另外 FTZ/DAZ 不属于 IEEE 754 标准,所以没有像其他舍入模式那样的可移植接口。顺带一提,icc 的 -fp-model=fast 和 MSVC 的 /fp:fast 正确地没有链接 crtfastmath。
jcranmer查看英文原文
The problem here is that enabling FTZ/DAZ flags involves modifying global (technically thread-local) state that is relatively expensive to do. Ideally, you'd want to twiddle these flags only for code that wants to work in this mode, but given the relative expense of this operation, it's not entirely practicable to auto-add twiddling to every function call, and doing it manually is somewhat challenging because compilers tend to support accessing the floating-point status rather poorly. Also, FTZ/DAZ aren't IEEE 754, so there's no portable function for twiddling these bits as there is for other rounding mode or exception controls. I will note that icc's -fp-model=fast and MSVC's /fp:fast correctly do not link code with crtfastmath. As a side note, this kind of thing is why I think a good title for a fast-math would be "Fast math, or how I learned to start worrying and hate floating point."
浮点模式等全局状态是诸多 bug 的根源,应当废除
全局状态是万恶之源!FPU 舍入模式、flush-to-zero 模式、C locale、errno 等等都应该被消灭。功能可以保留,但不该以全局标志的形式存在。
TazeTSchnitzel查看英文原文
Global state is the root of so many evils! FPU rounding mode, FPU flush-to-zero mode, C locale, errno, and probably some other things should all be eliminated. The functionality should still exist but not as global flags.
历次讨论
同类还值得读
位运算技巧集
Bit Twiddling Hacks
斯坦福页面上的经典位运算技巧合集,收录了 popcount、前导/尾随零、位反转、交换、舍入等大量技巧,并附有解释和性能讨论。
算法与计算机科学上首页 8 次 · 2011–2024graphics.stanford.edu编辑精选如何不按平均评分排序
How Not To Sort By Average Rating
经典文章解释了为什么按平均评分排序不可靠:只有少量评价的条目(比如仅一条五星)会轻易排到最前,而评价数量的差异被忽略。
算法与计算机科学上首页 7 次 · 2009–2024evanmiller.org编辑精选数据结构可视化
Data Structure Visualizations
旧金山大学 David Galles 教授制作的数据结构与算法交互式可视化网站,涵盖 B 树、红黑树、排序、图算法等,可逐步操作观察其运行过程。
算法与计算机科学上首页 6 次 · 2011–2021cs.usfca.edu编辑精选1996 年以来的计算机科学最佳论文奖
Best Paper Awards in Computer Science since 1996
Jeff Huang 维护的一个汇总页面,收录了自 1996 年以来计算机科学各主要会议的“最佳论文奖”获奖名单,并按年份和会议整理,方便读者一站式浏览历届获奖论文。
算法与计算机科学上首页 6 次 · 2010–2018jeffhuang.com编辑精选算法(Jeff Erickson)
Algorithms, by Jeff Erickson
伊利诺伊大学 Jeff Erickson 教授的算法课教材,免费在线开放。
算法与计算机科学上首页 5 次 · 2018–2022jeffe.cs.illinois.edu编辑精选