From aaa563729a0aefcc95c24669b4046fb285676063 Mon Sep 17 00:00:00 2001 From: Elias Van Ootegem Date: Mon, 5 Jul 2021 15:57:32 +0100 Subject: [PATCH] add uint support --- decimal.go | 40 ++++++++++++++++++++++++++++++++++++++++ decimal_test.go | 39 +++++++++++++++++++++++++++++++++++++++ go.mod | 2 ++ 3 files changed, 81 insertions(+) diff --git a/decimal.go b/decimal.go index 4f6d81a..e11f47f 100644 --- a/decimal.go +++ b/decimal.go @@ -25,6 +25,8 @@ import ( "regexp" "strconv" "strings" + + "github.com/holiman/uint256" ) // DivisionPrecision is the number of decimal places in the result when it @@ -98,6 +100,29 @@ func NewFromInt(value int64) Decimal { } } +// NewFromUint converts a uint256.Int to Decimal. +// Example: +// +// NewFromInt(uint256.NewInt(123)).String() // output: "123" +func NewFromUint(u *uint256.Int) Decimal { + return Decimal{ + value: u.ToBig(), + exp: 0, + } +} + +// NewFromUintExp converts a Uint to Decimal with given exponent +// +// Example: +// +// NewFromInt(uint256.NewInt(1), 2).String() // output: "100" +func NewFromUintExp(u *uint256.Int, exp int32) Decimal { + return Decimal{ + value: u.ToBig(), + exp: exp, + } +} + // NewFromInt32 converts a int32 to Decimal. // // Example: @@ -797,6 +822,21 @@ func (d Decimal) Rat() *big.Rat { return new(big.Rat).SetFrac(num, oneInt) } +// Uint returns integer component of the decimal as a uint256.Int. +func (d Decimal) Uint() (*uint256.Int, bool) { + i := &big.Int{} + i.SetString(d.rescale(0).String(), 10) + return uint256.FromBig(i) +} + +// UintNO returns integer component of the decimal as a uint256.Int. +// NO stands for No Overflow. Ignore the bool indicating whether or not +// overflow occured. +func (d Decimal) UintNO() *uint256.Int { + u, _ := d.Uint() + return u +} + // Float64 returns the nearest float64 value for d and a bool indicating // whether f represents d exactly. // For more details, see the documentation for big.Rat.Float64 diff --git a/decimal_test.go b/decimal_test.go index 6367653..24e6780 100644 --- a/decimal_test.go +++ b/decimal_test.go @@ -15,6 +15,8 @@ import ( "testing" "testing/quick" "time" + + "github.com/holiman/uint256" ) type testEnt struct { @@ -2241,6 +2243,43 @@ func TestBigInt(t *testing.T) { } } +func TestUint(t *testing.T) { + testCases := []struct { + Dec string + UintRep string + }{ + {"0.0", "0"}, + {"0.00000", "0"}, + {"0.01", "0"}, + {"12.1", "12"}, + {"9999.999", "9999"}, + // {"-32768.01234", "-32768"}, + // {"-572372.0000000001", "-572372"}, + } + for _, testCase := range testCases { + d, err := NewFromString(testCase.Dec) + if err != nil { + t.Fatal(err) + } + bi := &big.Int{} + bi.SetString(testCase.UintRep, 10) + exp, ok := uint256.FromBig(bi) + got, ok2 := d.Uint() + if ok != ok2 { + t.Fatalf("overflow from string (%v) <> vs from decimal (%v)", ok, ok2) + } + if !exp.Eq(got) { + t.Fatalf("expected %s == %s", exp, got) + } + if !ok { + if got = d.UintNO(); !exp.Eq(got) { + t.Fatalf("UintNO: expected %s == %s", exp, got) + } + + } + } +} + func TestBigFloat(t *testing.T) { testCases := []struct { Dec string diff --git a/go.mod b/go.mod index ae1b7aa..760e571 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/shopspring/decimal go 1.13 + +require github.com/holiman/uint256 v1.2.0 // indirect