Skip to content

Commit

Permalink
apacheGH-38395: [Go] fix rounding errors in decimal256 string functions
Browse files Browse the repository at this point in the history
  • Loading branch information
zeroshade committed Oct 23, 2023
1 parent 0428c5e commit 531d60d
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 2 deletions.
4 changes: 2 additions & 2 deletions go/arrow/decimal256/decimal256.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func FromString(v string, prec, scale int32) (n Num, err error) {
return
}

out.Mul(out, big.NewFloat(math.Pow10(int(scale)))).SetPrec(precInBits)
out.Mul(out, (&big.Float{}).SetInt(scaleMultipliers[scale].BigInt())).SetPrec(precInBits)
// Since we're going to truncate this to get an integer, we need to round
// the value instead because of edge cases so that we match how other implementations
// (e.g. C++) handles Decimal values. So if we're negative we'll subtract 0.5 and if
Expand Down Expand Up @@ -506,7 +506,7 @@ func (n Num) FitsInPrecision(prec int32) bool {

func (n Num) ToString(scale int32) string {
f := (&big.Float{}).SetInt(n.BigInt())
f.Quo(f, (&big.Float{}).SetInt(scaleMultipliers[scale].BigInt()))
f.SetPrec(256).Quo(f, (&big.Float{}).SetInt(scaleMultipliers[scale].BigInt()))
return f.Text('f', int(scale))
}

Expand Down
32 changes: 32 additions & 0 deletions go/arrow/decimal256/decimal256_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"math"
"math/big"
"strings"
"testing"

"github.com/apache/arrow/go/v14/arrow/decimal256"
Expand Down Expand Up @@ -575,3 +576,34 @@ func TestFromString(t *testing.T) {
})
}
}

// Test issues from GH-38395
func TestToString(t *testing.T) {
const decStr = "3379334159166193114608287418738414931564221155305735605033949613740461239999"

integer, _ := (&big.Int{}).SetString(decStr, 10)
dec := decimal256.FromBigInt(integer)

expected := "0." + decStr
actual := dec.ToString(76)

if expected != actual {
t.Errorf("expected: %s, actual: %s\n", expected, actual)
}
}

// Test issues from GH-38395
func TestHexFromString(t *testing.T) {
const decStr = "11111111111111111111111111111111111111.00000000000000000000000000000000000000"

num, err := decimal256.FromString(decStr, 76, 38)
if err != nil {
t.Error(err)
} else if decStr != num.ToString(38) {
t.Errorf("expected: %s, actual: %s\n", decStr, num.ToString(38))

actualCoeff := num.BigInt()
expectedCoeff, _ := (&big.Int{}).SetString(strings.Replace(decStr, ".", "", -1), 10)
t.Errorf("expected(hex): %X, actual(hex): %X\n", expectedCoeff.Bytes(), actualCoeff.Bytes())
}
}

0 comments on commit 531d60d

Please sign in to comment.