// Copyright 2026 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Floating point binary↔decimal conversion by fast unrounded scaling.// See “Floating-Point Printing and Parsing Can Be Simple And Fast”,// https://research.swtch.com/fppackage strconvimport ()// bool2 converts b to an integer: 1 for true, 0 for false.func [ ~int | ~uint32 | ~uint64]( bool) {if {return1 }return0}// pack64 takes m, e and returns f = m * 2**e.// It assumes the caller has provided a 53-bit mantissa m// and an exponent that is in range for the mantissa.func ( uint64, int) (float64, error) {if &(1<<52) == 0 {returnfloat64frombits(), nil }if >= 0x7FF-1075 {returnfloat64frombits(&(1<<63) | 0x7ff<<52), ErrRange }returnfloat64frombits(&^(1<<52) | uint64(1075+)<<52), nil}// pack32 takes m, e and returns f = m * 2**e.// It assumes the caller has provided a 24-bit mantissa m// and an exponent that is in range for the mantissa.func ( uint32, int) (float32, error) {if &(1<<23) == 0 {returnfloat32frombits(), nil }if >= 0xFF-150 {returnfloat32frombits(&(1<<31) | 0xff<<23), ErrRange }returnfloat32frombits(&^(1<<23) | uint32(150+)<<23), nil}// An unrounded represents an unrounded value.typeunroundeduint64func ( unrounded) () uint64 { returnuint64(( + 0) >> 2) }func ( unrounded) () uint64 { returnuint64(( + 1) >> 2) }func ( unrounded) () uint64 { returnuint64(( + 1 + (>>2)&1) >> 2) }func ( unrounded) () uint64 { returnuint64(( + 2) >> 2) }func ( unrounded) () uint64 { returnuint64(( + 3) >> 2) }func ( unrounded) ( int) unrounded { return + unrounded() }func ( unrounded) ( uint64) unrounded { := uint64()returnunrounded(/) | &1 | bool2[unrounded](% != 0)}func ( unrounded) ( int) unrounded {return >> | &1 | bool2[unrounded](&((1<<)-1) != 0)}// log10Pow2(x) returns ⌊log₁₀ 2**x⌋ = ⌊x * log₁₀ 2⌋.func ( int) int {// log₁₀ 2 ≈ 0.30102999566 ≈ 78913 / 2^18return ( * 78913) >> 18}// log2Pow10(x) returns ⌊log₂ 10**x⌋ = ⌊x * log₂ 10⌋.func ( int) int {// log₂ 10 ≈ 3.32192809489 ≈ 108853 / 2^15return ( * 108853) >> 15}// uint64pow10[x] is 10**x.varuint64pow10 = [...]uint64{1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,}// fixedWidthFloat returns the n-digit decimal form of f = m * 2**e as d * 10**p.// n can be at most 18.// If fmt == 'f' then n is a conservative estimate of the number of digits,// and digits are discarded to match prec.func ( uint64, , , int, byte) ( uint64, int) { = - 1 - log10Pow2(+63)varscalerprescale(&, , , log2Pow10()) := uscale(, &)if >= unmin(uint64pow10[]) { = .div(10) -- }if == 'f' {for > { = .div(10) -- } }return .round(), -}// parseFloat64 rounds d * 10**p to the nearest float64 f.// d can have at most 19 digits.// It returns ErrRange if the result rounds to infinity.func ( uint64, int, uint64) (float64, error) { := bits.Len64() := log2Pow10() := min(1074, 53--)varscalerprescale(&, -(64-), , )if .s >= 64 {returnfloat64frombits( | 0), nil } := uscale(<<(64-), &)// This block is branch-free code for: // if u.round() >= 1<<53 { // u = u.rsh(1) // e = e - 1 // } := bool2[int]( >= unmin(1<<53)) = >> | &1 = - returnpack64(|.round(), -)}// parseFloat32 rounds d * 10**p to the nearest float32 f.// d can have at most 19 digits.// It returns ErrRange if the result rounds to infinity.func ( uint64, int, uint32) (float32, error) { := bits.Len64() := log2Pow10() := min(149, 24--)varscalerprescale(&, -(64-), , )if .s >= 64 {returnfloat32frombits( | 0), nil } := uscale(<<(64-), &)// This block is branch-free code for: // if u.round() >= 1<<24 { // u = u.rsh(1) // e = e - 1 // } := bool2[int]( >= unmin(1<<24)) = >> | &1 = - returnpack32(|uint32(.round()), -)}// unmin returns the minimum unrounded that rounds to x.func ( uint64) unrounded {returnunrounded(<<2 - 2)}// shortFloat computes the shortest formatting of f,// using as few digits as possible that will still round trip// back to the original float.func [ float32 | float64]( uint64, int) ( uint64, int) {var , int// parameterized constantsswitch8 * unsafe.Sizeof((0)) {case32: = float32MantBits = float32MinExpcase64: = float64MantBits = float64MinExp }// Note: these cases could be factored a little more, // but in the first two branches, z is a constant, // allowing the compiler to greatly simplify the code.var , uint64varint := 63 - if == 1<<63 && > { = -skewed( + ) = - 1<<(-2) // min = m - 1/4 * 2**(e+z) = + 1<<(-1) // max = m + 1/2 * 2**(e+z) = int(>>) & 1 } elseif >= { = -log10Pow2( + ) = - 1<<(-1) // min = m - 1/2 * 2**(e+z) = + 1<<(-1) // max = m + 1/2 * 2**(e+z) = int(>>) & 1 } else { = + ( - ) = -log10Pow2( + ) = - 1<<(-1) // min = m - 1/2 * 2**(e+z) = + 1<<(-1) // max = m + 1/2 * 2**(e+z) = int(>>) & 1 }varscalerprescale(&, , , log2Pow10()) := uscale(, &).nudge(+).ceil() := uscale(, &).nudge(-).floor()if = / 10; *10 >= {return , -( - 1) }if = ; < { = uscale(, &).round() }return , -}// skewed computes the skewed footprint of m * 2**e,// which is ⌊log₁₀ 3/4 * 2**e⌋ = ⌊e*(log₁₀ 2)-(log₁₀ 4/3)⌋.func ( int) int {return (*631305 - 261663) >> 21}// A pmHiLo represents hi<<64 - lo.typepmHiLostruct {hiuint64louint64}// A scaler holds derived scaling constants for a given e, p pair.typescalerstruct {// Note: using pm pmHiLo here nudges uscale just over the inlining boundary. Don't.pmHiuint64pmLouint64sint}// prescale returns the scaling constants for e, p.// lp must be log2Pow10(p).// The caller is responsible for either avoiding e, p pairs// that cause pre.s < 0 or pre.s >= 64, or else handling// those cases before passing the result to uscale.// In practice, pre.s < 0 would indicate a buggy caller// and pre.s >= 64 can only happen for parsing and is// picked off at those call sites.func ( *scaler, , , int) { .pmHi = pow10Tab[-pow10Min].hi .pmLo = pow10Tab[-pow10Min].lo .s = -( + + 3)}// uscale returns unround(x * 2**e * 10**p).// The caller should pass &pre for prescale(&pre, e, p, log2Pow10(p))// and should have left-justified x so its high bit is set.// The caller is also responsible for checking that c.s < 64.// For formatting, that's always true.// For parsing, the caller needs to pick it off early and return a signed 0.func ( uint64, *scaler) unrounded { , := bits.Mul64(, .pmHi) := .s & 63// make shifts cheaperif >><< != {returnunrounded(>> | 1) } , := bits.Mul64(, .pmLo) -= bool2[uint64]( < )returnunrounded(>> | bool2[uint64](- > 1))}// setDigits sets digs to the nd digits described by d, p.func ( []byte, uint64, , int) (, int) {// Note: nd <= len(s) is guaranteed by caller, // but writing it explicitly here lets the compiler know, // so that it can remove the bounds check in the loop. // (The slice s[:nd] not panicking only establishes nd <= cap(s).)if <= len() {formatBase10([:], ) = + for > 0 && [-1] == '0' { -- } }return , }// numDigits returns the number of decimal digits in d.// It requires d ≥ 1.func ( uint64) int { := log10Pow2(bits.Len64())return + bool2[int]( >= uint64pow10[])}
The pages are generated with Goldsv0.8.4. (GOOS=linux GOARCH=amd64)