Skip to content

Commit ed35176

Browse files
Simplify Atof and try Ryū-style method even for very long inputs
Change-Id: Id7aa4f3b524ee7fd64714fa97e73dd6cd15c60e1
1 parent efc3feb commit ed35176

File tree

3 files changed

+26
-19
lines changed

3 files changed

+26
-19
lines changed

src/strconv/atof.go

+13-4
Original file line numberDiff line numberDiff line change
@@ -490,8 +490,17 @@ func atof64(s string) (f float64, err error) {
490490
}
491491
}
492492
// Try another fast path.
493-
if ryuEnabled && !trunc {
494-
b, ovf, ok := ryuFromDecimal(mantissa, exp, &float64info)
493+
if ryuEnabled {
494+
// Ryū-style method
495+
b, ovf := ryuFromDecimal(mantissa, exp, &float64info)
496+
ok := true
497+
if trunc {
498+
// check output for the rounded up mantissa.
499+
b2, _ := ryuFromDecimal(mantissa+1, exp, &float64info)
500+
if b != b2 {
501+
ok = false
502+
}
503+
}
495504
if ok {
496505
f = math.Float64frombits(b)
497506
if neg {
@@ -502,8 +511,8 @@ func atof64(s string) (f float64, err error) {
502511
}
503512
return f, err
504513
}
505-
}
506-
if !ryuEnabled {
514+
} else {
515+
// Grisu3-style method
507516
ext := new(extFloat)
508517
if ok := ext.AssignDecimal(mantissa, exp, neg, trunc, &float64info); ok {
509518
b, ovf := ext.floatBits(&float64info)

src/strconv/extfloat2.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ func ryuFixed(d *decimalSlice, mant uint64, exp int, prec int, flt *floatInfo) {
308308
return
309309
}
310310

311-
func ryuFromDecimal(mant uint64, exp int, flt *floatInfo) (fbits uint64, ovf, ok bool) {
311+
func ryuFromDecimal(mant uint64, exp int, flt *floatInfo) (fbits uint64, ovf bool) {
312312
// Conversion from decimal to binary floating-point
313313
// can be achieved by reusing the same building blocks
314314
// as the Ryū algorithm.
@@ -332,9 +332,9 @@ func ryuFromDecimal(mant uint64, exp int, flt *floatInfo) (fbits uint64, ovf, ok
332332
var pow *extfloat128 // a representation of 10^q
333333
switch {
334334
case exp > 309:
335-
return 0x7ff << 52, true, true
335+
return 0x7ff << 52, true
336336
case exp < -342:
337-
return 0, false, true
337+
return 0, false
338338
case exp > 0:
339339
pow = &ryuPowersOfTen[exp]
340340
case exp == 0:
@@ -384,7 +384,7 @@ func ryuFromDecimal(mant uint64, exp int, flt *floatInfo) (fbits uint64, ovf, ok
384384
e2 = flt.bias + 1
385385
}
386386
if extra > uint(blen) {
387-
return 0.0, false, true
387+
return 0.0, false
388388
}
389389
// Compute correct rounding.
390390
extramask := uint64(1<<extra - 1)
@@ -427,7 +427,7 @@ func ryuFromDecimal(mant uint64, exp int, flt *floatInfo) (fbits uint64, ovf, ok
427427
// Assemble bits.
428428
fbits = di & (uint64(1)<<flt.mantbits - 1)
429429
fbits |= uint64((e2-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits
430-
return fbits, ovf, true
430+
return fbits, ovf
431431
}
432432

433433
func divisibleByPower5(m uint64, k int) bool {

src/strconv/extfloat2_test.go

+8-10
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ var ryuAtofTests = []struct {
193193

194194
func TestRyuFromDecimal(t *testing.T) {
195195
for _, x := range ryuAtofTests {
196-
b, _, _ := RyuFromDecimal(x.mant, x.exp, &Float64info)
196+
b, _ := RyuFromDecimal(x.mant, x.exp, &Float64info)
197197
f := math.Float64frombits(b)
198198
if f != x.expect {
199199
t.Errorf("parsing %de%d, expect %v (%b), got %v (%b)",
@@ -326,10 +326,10 @@ func TestRyuAtofRandom(t *testing.T) {
326326
exp := (i % 640) - 342 // range (-342, 298)
327327

328328
fold := OldAtof(mant, exp)
329-
bnew, _, ryuOk := RyuFromDecimal(mant, exp, &Float64info)
329+
bnew, _ := RyuFromDecimal(mant, exp, &Float64info)
330330
fnew := math.Float64frombits(bnew)
331331

332-
if !ryuOk || fold != fnew {
332+
if fold != fnew {
333333
t.Logf("%de%d old=%v new=%v", mant, exp, fold, fnew)
334334
ko++
335335
} else {
@@ -364,15 +364,13 @@ func TestRyuAtofCoverage(t *testing.T) {
364364
// Compute decimal mantissa, exponent.
365365
mant, exp := ReadFloat(s)
366366
f1, ok1 := FastAtof(mant, exp)
367-
b2, _, ok2 := RyuFromDecimal(mant, exp, &Float64info)
367+
b2, _ := RyuFromDecimal(mant, exp, &Float64info)
368368
f2 := math.Float64frombits(b2)
369369
if ok1 {
370370
oldOk++
371371
}
372-
if ok2 {
373-
ryuOk++
374-
}
375-
if ok1 && ok2 && f1 != f2 {
372+
ryuOk++
373+
if ok1 && f1 != f2 {
376374
t.Fatalf("inconsistent results %s => %v %v", s, f1, f2)
377375
}
378376
}
@@ -740,8 +738,8 @@ func BenchmarkRyuAtof(b *testing.B) {
740738
b.Run(fmt.Sprintf("%de%d", c.mant, c.exp), func(b *testing.B) {
741739
var v uint64
742740
for i := 0; i < b.N; i++ {
743-
f, ovf, ok := RyuFromDecimal(c.mant, c.exp, &Float64info)
744-
if ovf || !ok {
741+
f, ovf := RyuFromDecimal(c.mant, c.exp, &Float64info)
742+
if ovf {
745743
b.Fatal("could not parse")
746744
}
747745
v = f

0 commit comments

Comments
 (0)