// Copyright 2020 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.package strconv// This file implements the Eisel-Lemire ParseFloat algorithm, published in// 2020 and discussed extensively at// https://nigeltao.github.io/blog/2020/eisel-lemire.html//// The original C++ implementation is at// https://github.com/lemire/fast_double_parser/blob/644bef4306059d3be01a04e77d3cc84b379c596f/include/fast_double_parser.h#L840//// This Go re-implementation closely follows the C re-implementation at// https://github.com/google/wuffs/blob/ba3818cb6b473a2ed0b38ecfc07dbbd3a97e8ae7/internal/cgen/base/floatconv-submodule-code.c#L990//// Additional testing (on over several million test strings) is done by// https://github.com/nigeltao/parse-number-fxx-test-data/blob/5280dcfccf6d0b02a65ae282dad0b6d9de50e039/script/test-go-strconv.goimport ()func eiselLemire64( uint64, int, bool) ( float64, bool) {// The terse comments in this function body refer to sections of the // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post.// Exp10 Range.if == 0 {if { = float64frombits(0x8000000000000000) // Negative zero. }return , true } , , := pow10()if ! {return0, false }// Normalization. := bits.LeadingZeros64() <<= uint() := uint64(+63-float64Bias) - uint64()// Multiplication. , := bits.Mul64(, .Hi)// Wider Approximation.if &0x1FF == 0x1FF && + < { , := bits.Mul64(, .Lo) , := , +if < { ++ }if &0x1FF == 0x1FF && +1 == 0 && + < {return0, false } , = , }// Shifting to 54 Bits. := >> 63 := >> ( + 9) -= 1 ^ // Half-way Ambiguity.if == 0 && &0x1FF == 0 && &3 == 1 {return0, false }// From 54 to 53 Bits. += & 1 >>= 1if >>53 > 0 { >>= 1 += 1 }// retExp2 is a uint64. Zero or underflow means that we're in subnormal // float64 space. 0x7FF or above means that we're in Inf/NaN float64 space. // // The if block is equivalent to (but has fewer branches than): // if retExp2 <= 0 || retExp2 >= 0x7FF { etc }if -1 >= 0x7FF-1 {return0, false } := <<float64MantBits | &(1<<float64MantBits-1)if { |= 0x8000000000000000 }returnfloat64frombits(), true}func eiselLemire32( uint64, int, bool) ( float32, bool) {// The terse comments in this function body refer to sections of the // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. // // That blog post discusses the float64 flavor (11 exponent bits with a // -1023 bias, 52 mantissa bits) of the algorithm, but the same approach // applies to the float32 flavor (8 exponent bits with a -127 bias, 23 // mantissa bits). The computation here happens with 64-bit values (e.g. // man, xHi, retMantissa) before finally converting to a 32-bit float.// Exp10 Range.if == 0 {if { = float32frombits(0x80000000) // Negative zero. }return , true } , , := pow10()if ! {return0, false }// Normalization. := bits.LeadingZeros64() <<= uint() := uint64(+63-float32Bias) - uint64()// Multiplication. , := bits.Mul64(, .Hi)// Wider Approximation.if &0x3FFFFFFFFF == 0x3FFFFFFFFF && + < { , := bits.Mul64(, .Lo) , := , +if < { ++ }if &0x3FFFFFFFFF == 0x3FFFFFFFFF && +1 == 0 && + < {return0, false } , = , }// Shifting to 54 Bits (and for float32, it's shifting to 25 bits). := >> 63 := >> ( + 38) -= 1 ^ // Half-way Ambiguity.if == 0 && &0x3FFFFFFFFF == 0 && &3 == 1 {return0, false }// From 54 to 53 Bits (and for float32, it's from 25 to 24 bits). += & 1 >>= 1if >>24 > 0 { >>= 1 += 1 }// retExp2 is a uint64. Zero or underflow means that we're in subnormal // float32 space. 0xFF or above means that we're in Inf/NaN float32 space. // // The if block is equivalent to (but has fewer branches than): // if retExp2 <= 0 || retExp2 >= 0xFF { etc }if -1 >= 0xFF-1 {return0, false } := <<float32MantBits | &(1<<float32MantBits-1)if { |= 0x80000000 }returnfloat32frombits(uint32()), true}
The pages are generated with Goldsv0.8.3-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.