-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
Go version
go1.25.x
Output of go env in your module/workspace:
GOEXPERIMENT=jsonv2What did you do?
func main() {
var (
pi32 = float32(math.Pi)
pi64 = float64(math.Pi)
)
m := map[string]any{
"f32": pi32,
"f64": pi64,
}
out, _ := json.Marshal(m, jsontext.WithIndent(" "))
fmt.Printf("%s\n", out)
enc := jsontext.NewEncoder(os.Stdout, jsontext.WithIndent(" "))
enc.WriteToken(jsontext.BeginObject)
enc.WriteToken(jsontext.String("f32"))
enc.WriteToken(jsontext.Float(float64(pi32)))
enc.WriteToken(jsontext.String("f64"))
enc.WriteToken(jsontext.Float(pi64))
enc.WriteToken(jsontext.EndObject)
}What did you see happen?
The above program prints:
{
"f32": 3.1415927,
"f64": 3.141592653589793
}
{
"f32": 3.1415927410125732,
"f64": 3.141592653589793
}
Notice how json.Marshal nicely formats the float32 version of pi with a correct number of significant digits while the most obvious way to produce the same output with jsontext.Encoder formats it with a misleading (and wrong) set of digits.
I discovered this while experimenting with retrofitting the json implementation of a structured logging encoder to use jsontext. Although the logging encoder in question is not public its encoding interface is quite similar to the zapcore.ObjectEncoder which has an AddFloat32(key string, value float32) method.
Our log encoder does not use the json package but does have unit tests that ensure it produces the same output as an equivalent json.Marshal call for all the primitive types we support. Using jsontext.Encoder it was trivial to match the output for all types except float32.
Note that in order to match the json.Marshal behavior for floating point values our current log encoder has a copy of an older version of the code that json/v2 has in the encoding/json/internal/jsonwire.AppendFloat function.
What did you expect to see?
I think the jsontext package needs better support for float32 tokens.
For use cases like the above there should be a way to construct a jsontext.Token that carries a float32 value in a way that the Encoder eventually calls jsonwire.AppendFloat with 32 for its bits parameter.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status