Unrounded Scaling:Go 1.27 浮點數轉換演算法的深度拆解
前言 開始之前先看這支影片,講的是 Quake III 那個 0x5f3759df。它跟本文沒有直接關係,但用的是同一類招式:把浮點數的 bit pattern 當成整數讀,用整數的乘加移位取代超越函數。差別在於那一招接受 3.4% 的誤差,而本文接下來要講的東西,一個 bit 的誤差都不能有。這個對照後面定點對數那節會再回來收。 TL;DR 中間一大段是演算法拆解,有興趣再啃。只想知道「Go 1.27 實際上改了什麼、變多快、輸出有沒有跑掉」的話,可以直接跳到 Go 1.27 到底改了什麼,結論是 878 行三套演算法變成 290 行一套、快了 11–21%、輸出零變化。如果你在意的是「那我平常記帳該用什麼」,跳到 附錄,那一節比較了 float64、math/big 三兄弟與 shopspring/decimal。 我把 Go 升到 1.27 之後,照慣例翻了一遍 release notes,也寫了新特性整理。整份文件從頭到尾沒有一個字提到 strconv。 但是 Go 1.27 把 fmt.Sprintf("%v", f)、strconv.ParseFloat、json.Marshal 底下那顆浮點數轉換引擎整個換掉了。舊的實作是三套演算法各自為政:最短列印用 Dragonbox、固定位數列印用 Ryū 風格的程式碼、解析用 Eisel-Lemire,新的實作是一個叫 unrounded scaling 的東西,作者是 Russ Cox,論文是 2026 年 1 月才發表的。 這件事之所以值得寫一篇,是因為 Russ Cox 在 2011 年寫過一篇 Floating Point to Decimal Conversion is Easy,副標題是 Part 1。文章的論點是: ...