Migrate Number from float64 to big.Float
- Dominant language
- Go
- Stars
- 2.7k
- Forks
- 241
- PR merge metrics
- No merged PRs in 30d
Description
Currently, Number always converts its value to float64. In many cases it works well, however float64 can't represent big integer values (larger than 2^62) without precision loss.
Actually, there is no native type that can represent ALL values of int64, uint64, and float64 without loss. However, there is a library type that can do it: big.Float (see https://pkg.go.dev/math/big).
Here are the steps:
* replace underlying value of Number from float64 to big.Float
* by default, use precision that is sufficient to represent all values of int64, uint64, and float64 without loss
* allow user to set higher precision in Config (this may be useful if user wants to parse Number from String that contains bigger integer or float)
* rework canonNumber() to return big.Float instead of float64; it should automatically detect precision and create big.Float from any of these types:
* all native float and integer types
* type definitions for those native types (e.g. `type MyInt int`)
* big.Float and big.Int
* json.Number
* rework NewNumber constructor: it should accept interface{} instead of float64 and use canonNumber() to convert it to big.Float
* rework all Number operations, so that they will operate on big.Float values (one stored in Number, another returned from canonNumber for operation argument)
* rework Number.EqualDelta and Number.NotEqualDelta: they should accept interface{} instead of float64; this will allow user to pass big.Float instead of float64, when necessary
* rework JSON decoding:
* find places where we decode JSON: canonValue, Response, WebsocketMessage; configure JSON decoder to use json.Number instead of float64 (see https://pkg.go.dev/encoding/json#Decoder.UseNumber)
* ensure that canonValue() and other canonization functions does not cause precision loss
* rework Number creation
* Expect.Number() should accept interface{} instead of float64
* rework Value.Number() - it should not force float64 type
* rework String.AsNumber() - it should correctly parse big floats and integers
* find all invocations to newNumber() that have unnecessary casts to float64 and pass integers instead; e.g. `newNumber(a.chain, float64(len(a.value)))` can be now replaced with `newNumber(a.chain, len(a.value))` because Number now supports integers
* adjust equality checks:
* find all places that do deep equality checks (e.g. in Object, Array) using reflect.DeepEqual
* ensure that they will work when original values have different representations for same numbers (e.g. json.Number vs float64 vs big.Float)
* cover these cases with unit tests
* add new getters for Number:
* add 4 new methods: AsInt (returns int64), AsUint (return uint64), AsFloat (return float64), AsBig (return big.Float)
* each method should report failure if underlying value can't be converted to requested types without loss
* add IsBig (similar to other Is methods, see #155)
* mark Number.Raw as deprecated and ask user to use AsFloat instead; in httpexpect v3, when we will be able to break compatibility, we'll undeprecate Raw, but change its return type to big.Float
* adjust DefaultFormatter to handle big.Float values:
* if value is integer, print it as integer
* otherwise print it in non-scientific form (see also #190)
* adjust tests:
* add unit tests for Number to check how it works with big integers and floats
* add unit tests for Value.Number() to check how it works with json.Number and integers that can't be represented without loss as float64
* rework tests for String.AsNumber() - rework float_precision test, add tests for big floats and integers that can't be parsed with default precision, but can be parsed when setting higher precision in Config
* cover big integers and floats, and different precisions, in e2e tests (e.g. in e2e_basic_test.go)
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.