diff --git a/feature_stream_float.go b/feature_stream_float.go index 27af5a3..0b8e8a0 100644 --- a/feature_stream_float.go +++ b/feature_stream_float.go @@ -2,6 +2,7 @@ package jsoniter import ( "strconv" + "math" ) var _POW10 []uint64 @@ -11,7 +12,15 @@ func init() { } func (stream *Stream) WriteFloat32(val float32) { - stream.WriteRaw(strconv.FormatFloat(float64(val), 'f', -1, 32)) + abs := math.Abs(float64(val)) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if float32(abs) < 1e-6 || float32(abs) >= 1e21 { + fmt = 'e' + } + } + stream.WriteRaw(strconv.FormatFloat(float64(val), fmt, -1, 32)) } func (stream *Stream) WriteFloat32Lossy(val float32) { @@ -20,7 +29,7 @@ func (stream *Stream) WriteFloat32Lossy(val float32) { val = -val } if val > 0x4ffffff { - stream.WriteRaw(strconv.FormatFloat(float64(val), 'f', -1, 32)) + stream.WriteFloat32(val) return } precision := 6 @@ -43,7 +52,15 @@ func (stream *Stream) WriteFloat32Lossy(val float32) { } func (stream *Stream) WriteFloat64(val float64) { - stream.WriteRaw(strconv.FormatFloat(float64(val), 'f', -1, 64)) + abs := math.Abs(val) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if abs < 1e-6 || abs >= 1e21 { + fmt = 'e' + } + } + stream.WriteRaw(strconv.FormatFloat(float64(val), fmt, -1, 64)) } func (stream *Stream) WriteFloat64Lossy(val float64) { @@ -52,7 +69,7 @@ func (stream *Stream) WriteFloat64Lossy(val float64) { val = -val } if val > 0x4ffffff { - stream.WriteRaw(strconv.FormatFloat(val, 'f', -1, 64)) + stream.WriteFloat64(val) return } precision := 6 diff --git a/jsoniter_1dot8_only_test.go b/jsoniter_1dot8_only_test.go index 1153a27..50f7a6a 100644 --- a/jsoniter_1dot8_only_test.go +++ b/jsoniter_1dot8_only_test.go @@ -1,4 +1,5 @@ // +build go1.8 + package jsoniter import ( diff --git a/jsoniter_float_test.go b/jsoniter_float_test.go index 62fa90f..9c42e18 100644 --- a/jsoniter_float_test.go +++ b/jsoniter_float_test.go @@ -85,7 +85,9 @@ func Test_write_float32(t *testing.T) { stream.WriteFloat32Lossy(val) stream.Flush() should.Nil(stream.Error) - should.Equal(strconv.FormatFloat(float64(val), 'f', -1, 32), buf.String()) + output, err := json.Marshal(val) + should.Nil(err) + should.Equal(string(output), buf.String()) }) t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { should := require.New(t) @@ -94,7 +96,9 @@ func Test_write_float32(t *testing.T) { stream.WriteVal(val) stream.Flush() should.Nil(stream.Error) - should.Equal(strconv.FormatFloat(float64(val), 'f', -1, 32), buf.String()) + output, err := json.Marshal(val) + should.Nil(err) + should.Equal(string(output), buf.String()) }) } should := require.New(t)