标签 Go 下的文章

算法神话的祛魅:Russ Cox 与浮点数转换的 15 年求索之路

本文永久链接 – https://tonybai.com/2026/02/03/russ-cox-15-year-war-on-floating-point-conversion

大家好,我是Tony Bai。

“浮点数到十进制的转换一直被认为很难。但本质上,它们非常简单直接。” —— Russ Cox (2011)

“我错了。快速的转换器也可以很简单,这篇文章将展示如何做到。” —— Russ Cox (2026)

在计算机科学的深处,潜伏着一条名为“浮点数转换”的恶龙。将一个二进制浮点数(如 float64)转换为人类可读的十进制字符串(如 “0.1″),看似简单,实则是一个困扰了业界半个世纪的难题。

2011 年,Go 语言的核心人物 Russ Cox 写下了一篇博文,试图用一种简单的算法来“驯服”这条龙。然而,在随后的十几年里,学术界和工业界爆发了一场军备竞赛:Dragon4, Grisu3, Ryū, Schubfach, Dragonbox… 每一个新算法都试图在速度上压倒前一个,但也让代码变得越来越复杂,数学证明越来越晦涩。

2026 年初,Russ Cox 带着他的新系列文章强势回归。这一次,他不仅带来了一套比所有已知算法都更快的全新算法,而且证明了:极致的性能不需要极致的复杂性。

这套算法已被确定将在 Go 1.27 (2026年8月) 中发布。今天,我们就来深度解析这项可能改写浮点数处理历史的技术突破。

历史的迷宫与“不可能三角”

要理解 Russ Cox 的成就,我们首先要理解这个问题的难度。一个完美的浮点数打印算法,必须同时满足三个苛刻的条件(“不可能三角”):

  1. 正确性 (Correctness):转换必须是双射的。Parse(Print(f)) == f 必须恒成立。这意味着你不能随意丢弃精度。
  2. 最短性 (Shortest):输出的字符串必须是所有能转回原值的字符串中最短的。例如,0.3 在二进制中无法精确表示,打印时应该是 “0.3″ 而不是 “0.2999999999999999889″。
  3. 速度 (Speed):在大规模数据处理(如 JSON 序列化)中,转换速度直接决定了系统的吞吐量。

历史的演进:
* Dragon4 (1990):实现了正确性和最短性,但依赖大整数(BigInt)运算,慢如蜗牛。
* Grisu3 (2010):Google 的 V8 引擎引入。速度极快,但不保证最短性,约 0.5% 的情况会失败并回退到慢速算法。
* Ryū (2018) & Dragonbox (2020):通过复杂的数学技巧(查表法),终于在不使用 BigInt 的情况下实现了正确且最短。这是性能的巅峰,但代码极其复杂,充满魔术数字。

Russ Cox 的目标,就是打破这个迷宫:能不能既像 Ryū 一样快且正确,又像 2011 年的那个算法一样简单?

核心技术——“未舍入缩放” (Unrounded Scaling)

Russ Cox 的新算法核心,源于一个极其精妙的数学原语:快速未舍入缩放 (Fast Unrounded Scaling)

什么是“未舍入数”?

在传统算法中,我们总是纠结于“何时舍入”。Russ Cox 引入了 “未舍入数” (Unrounded Number) 的概念 ⟨x⟩。它由三部分组成:

  • 整数部分: floor(x)
  • ½ bit: 标记 x – floor(x) >= 0.5
  • sticky bit (粘滞位): 标记 x 是否有非零的小数残余。

这种表示法不仅保留了用于正确舍入(Round half to even)的所有必要信息,而且可以通过极其廉价的位运算(| 和 &)来维护。这就像是在计算过程中保留了一个“高精度的尾巴”,直到最后一步才决定如何截断。

缩放的魔法

浮点数打印本质上是计算 f = m * 2^e 对应的十进制 d * 10^p。核心步骤是将 m * 2^e 乘以 10^p。

Russ Cox 使用查表法(预计算 10^p 的 128 位近似值)来实现这一缩放。但他最惊人的发现是:在 64 位浮点数转换的场景下,我们甚至不需要完整的 128 位乘法!

他证明了:只需计算 64 位 x 64 位的高位结果,并利用低位的“粘滞位”来修正,就能得到完全正确的结果。这意味着,曾经需要几十次乘法或大整数运算的转换过程,现在被缩减为极少数几次 CPU 原生乘法

这一发现被称为 “Omit Needless Multiplications”(省略不必要的乘法),它是新算法性能超越 Ryū 的关键。

从理论到 Go 1.27

基于这个核心原语,Russ Cox 构建了一整套算法家族:

  • FixedWidth: 定点打印(如 %.2f)。
  • Shortest: 最短表示打印(如 %g)。
  • Parse: 字符串转浮点数。

性能碾压

Russ Cox 在 Apple M4 和 AMD Ryzen 9 上进行了详尽的基准测试:

  • 定点打印:新算法 (uscale) 显著快于 glibc 和 double-conversion,甚至快于 Ryū。
  • 最短打印:在纯算法层面,新算法与业界最快的 Dragonbox 持平或更快,但代码逻辑要简单得多。
  • 解析:同样基于该原理的解析算法,性能超越了目前业界标杆 fast_float (Eisel-Lemire 算法)。

更令人兴奋的是,Go 1.27 将直接集成这套算法或算法的一部分。对于 Gopher 来说,这意味着你的 fmt.Sprintf、json.Marshal 和 strconv.ParseFloat 将在下个版本中自动获得显著的性能提升,而无需修改一行代码。

证明的艺术

除了代码,Russ Cox 还做了一件很“极客”的事:他用 Ivy(一种 APL 风格的语言)编写了完整的数学证明。

他没有选择形式化验证工具(如 Coq),而是通过编写可执行的代码来验证算法在每一个可能的 float64 输入下都是正确的。这种“通过计算来证明” (Proof by Computation) 的方法,不仅验证了算法的正确性,也为后来者留下了一份可交互的、活生生的文档。

小结:简单是终极的复杂

从 2011 年的初次尝试,到 2026 年的最终突破,Russ Cox 用 15 年的时间完成了一个完美的闭环。

这一系列文章是一种工程哲学的胜利。它告诉我们:当我们面对复杂的遗留问题时,不要只是盲目地堆砌优化技巧。回到数学的源头,重新审视问题的本质,或许能找到那条既简单又快的“捷径”。

现在的 Go 标准库中,即将拥有一颗比以往任何时候都更强大、更轻盈的“心脏”。

资料链接:https://research.swtch.com/fp-all


你更看重哪一点?

在算法的世界里,正确性、最短表示、运行速度,这“不可能三角”总是让我们反复权衡。在你平时的开发中,有哪些场景曾让你被浮点
能或精度困扰?或者,你对 Russ Cox 这种“死磕 15 年”的工程精神有何感触?

欢迎在评论区分享你的看法!如果这篇文章让你对浮点数实现算法方面有了新的认识,别忘了点个【赞】和【在看】,并转发给你的Go开发朋友们!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

我用 Go 重写了 Python 网关,性能提升 10 倍,却成了职场噩梦

本文永久链接 – https://tonybai.com/2026/02/01/go-rewrite-python-gateway-10x-performance-career-nightmare

大家好,我是Tony Bai。

“如果你没有坏,就不要修它。” (If it ain’t broke, don’t fix it.)

这句老生常谈的工程谚语,最近在 r/golang 社区的一次热议中再次得到了血淋淋的验证。

一位开发者 分享了他即使成功将一个 Python 服务重写为 Go,并取得了显著的性能提升,却依然感到挫败和后悔的经历。

你可以将其看成是一个关于 Go vs Python 的技术故事,但在我眼中这更像是一堂关于技术决策、团队协作和职场生存的必修课。

故事:一场“完美”的技术胜利

故事的开端听起来像是一个典型的技术爽文。

作者说服了管理层,让他将现有的 API 网关从 Python/Flask 重写为 Go。理由非常充分且“正确”:性能和并发

经过两个月的努力,重写非常成功:

  • 吞吐量提升 10 倍
  • 内存占用减少到原来的 1/3
  • 部署时间从分钟级缩短到秒级

从技术指标上看,这是一场完胜。Go 语言在这个场景下再次证明了其在云原生和高并发领域的统治力。

反转:一场“无感”的商业失败

然而,当新系统上线后,现实给了作者一记重拳。

用户感知到了什么?
Absolutely nothing.(完全没有。)

响应时间从 45ms 降到了 38ms。这 7ms 的提升,除了作者盯着 Grafana 监控面板自我陶醉外,没有任何用户能察觉到区别。

团队感知到了什么?

巨大的风险和负担。

原来的 Python 版本虽然性能稍逊,但完全能扛住现有的负载,而且团队所有人都知道如何维护它。现在,系统变成了一个只有作者一人能懂的 Go 服务。

结果就是:作者成为了唯一的维护者(Single Point of Failure),任何报警都只能找他,哪怕是在半夜或周末。

社区的“毒舌”与洞见

这篇帖子引发了数百条评论,虽然有些评论非常“毒舌”,但其中蕴含的工程智慧却发人深省。

技术正确 ≠ 商业价值

正如一位开发者指出的:“你花了公司两个月的薪水和机会成本,解决了一个并不存在的问题。”

在商业环境中,技术是手段,不是目的。如果性能提升不能转化为用户体验的改善(如更流畅的交互)或成本的显著降低(如服务器费用减半),那么这种优化就是没有商业价值的。

“简历驱动开发” (Resume-Driven Development)

不少人犀利地指出,这种重构往往是出自开发者的私心——为了学习新技术、为了给简历镀金。

“这就是为什么我不想让程序员做商业决策。他们会为了微秒级的性能提升,制造出一系列未来的维护挑战。”

团队同质性的重要性

在一个 Python 团队中引入 Go,打破了技术栈的同质性。这不仅增加了维护成本,还降低了团队的“巴士系数”(Bus Factor)。

“有时候,最好的技术选择,就是你团队已经掌握的那一个。”

注:巴士系数(Bus Factor)是一个用于衡量团队或项目中关键人员的依赖程度的指标。它的核心概念是,如果某些关键成员(例如开发人员、设计师或管理人员)因意外(如被公交车撞到)而无法继续工作,项目仍能以多大程度上保持运作。

Go 的正确打开方式

那么,这是否意味着我们在 Python/Java/Node 团队中就不能引入 Go 了?当然不是。但需要满足特定的前提:

  1. 痛点必须足够痛:现有的技术栈确实无法支撑业务发展(如严重的性能瓶颈、不可接受的延迟)。
  2. 团队共识:重写不应该是个人的“独角戏”,而必须是团队的战略决策。至少要有 2-3 人愿意学习并维护新语言。
  3. 渐进式引入:不要一上来就重写核心网关,可以从边缘服务或工具链开始,逐步培养团队的 Go 技能。

小结:成熟工程师的标志

这个故事告诉我们,成为一名 Senior 工程师,不仅仅意味着写出更快的代码,更意味着懂得何时不写代码

Go 是一把锋利的“屠龙刀”,但如果你的面前并没有龙,用它来切菜,可能不仅切不好,还会伤到自己。

下次当你想要重写一个服务时,请先问自己三个问题:

  1. 它真的坏了吗?
  2. 这能为公司省钱或赚钱吗?
  3. 如果我离职了,谁来维护它?

如果答案不确定,或许最好的选择是——Don’t fix what’s not broke.

资料链接:https://www.reddit.com/r/golang/comments/1qr9375/rewrote_our_python_api_gateway_in_go_and_now_its/


你的“重构”悔恨录

“重写”是每个程序员都曾有过的冲动。在你的职业生涯中,是否也曾因为执着于某种“新技术”或“极致性能”,而给团队带来了意想不到的麻烦?或者,你见过哪些典型的“简历驱动开发”案例?

欢迎在评论区分享你的故事!让我们在别人的教训中,学会做更成熟的决策。

如果这篇文章让你停下来思考了 30 秒,别忘了点个【赞】和【在看】,并转发给那个正准备“大干一场”的同事!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 AI原生开发工作流实战 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com
这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats