From d447064515d36b8d539e489e28408c1e44d4d434 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 5 Mar 2020 20:05:52 +0300 Subject: [PATCH] util: implement FixedN from string When working with NEP5 contracts we frequently need to parse fixed-point decimals with arbitrary precision. --- pkg/util/fixed8.go | 20 ++++++++++++++++---- pkg/util/fixed8_test.go | 14 ++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/pkg/util/fixed8.go b/pkg/util/fixed8.go index c511f76de..c11badae7 100644 --- a/pkg/util/fixed8.go +++ b/pkg/util/fixed8.go @@ -3,6 +3,7 @@ package util import ( "encoding/json" "errors" + "math" "strconv" "strings" @@ -71,25 +72,36 @@ func Fixed8FromFloat(val float64) Fixed8 { // Fixed8FromString parses s which must be a fixed point number // with precision up to 10^-8 func Fixed8FromString(s string) (Fixed8, error) { + num, err := FixedNFromString(s, precision) + if err != nil { + return 0, err + } + return Fixed8(num), err +} + +// FixedNFromString parses s which must be a fixed point number +// with precision 10^-d. +func FixedNFromString(s string, precision int) (int64, error) { parts := strings.SplitN(s, ".", 2) + d := int64(math.Pow10(precision)) ip, err := strconv.ParseInt(parts[0], 10, 64) if err != nil { return 0, errInvalidString } else if len(parts) == 1 { - return Fixed8(ip * decimals), nil + return ip * d, nil } fp, err := strconv.ParseInt(parts[1], 10, 64) - if err != nil || fp >= decimals { + if err != nil || fp >= d { return 0, errInvalidString } for i := len(parts[1]); i < precision; i++ { fp *= 10 } if ip < 0 { - return Fixed8(ip*decimals - fp), nil + return ip*d - fp, nil } - return Fixed8(ip*decimals + fp), nil + return ip*d + fp, nil } // UnmarshalJSON implements the json unmarshaller interface. diff --git a/pkg/util/fixed8_test.go b/pkg/util/fixed8_test.go index 5f01dee12..aff92644b 100644 --- a/pkg/util/fixed8_test.go +++ b/pkg/util/fixed8_test.go @@ -85,6 +85,20 @@ func TestFixed8FromString(t *testing.T) { assert.Error(t, err) } +func TestFixedNFromString(t *testing.T) { + val := "123.456" + num, err := FixedNFromString(val, 3) + require.NoError(t, err) + require.EqualValues(t, 123456, num) + + num, err = FixedNFromString(val, 4) + require.NoError(t, err) + require.EqualValues(t, 1234560, num) + + _, err = FixedNFromString(val, 2) + require.Error(t, err) +} + func TestSatoshi(t *testing.T) { satoshif8 := Satoshi() assert.Equal(t, "0.00000001", satoshif8.String())