This is an automated email from the ASF dual-hosted git repository.
zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-go.git
The following commit(s) were added to refs/heads/main by this push:
new bc6d2df0 fix(compute): round negative HalfToOdd ties correctly (#1094)
bc6d2df0 is described below
commit bc6d2df0192bf4cde2ec5da6fb1e57bc86f73c29
Author: Minh Vu <[email protected]>
AuthorDate: Thu Aug 6 18:07:44 2026 +0200
fix(compute): round negative HalfToOdd ties correctly (#1094)
### Rationale for this change
The decimal HalfToOdd kernel uses the remainder sign incorrectly when
adjusting negative ties. Some negative values therefore round to an even
result instead of the nearest odd result.
### What changes are included in this PR?
Use the signed remainder when choosing the adjustment for Decimal128 and
Decimal256. Leave round_to_multiple unchanged.
### Are these changes tested?
- `go test ./arrow/compute/...`
### Are there any user-facing changes?
No API changes. This corrects the reported behavior while preserving the
existing ownership and compatibility contracts.
---
arrow/compute/arithmetic_test.go | 26 ++++++++++++++++++++++++++
arrow/compute/internal/kernels/rounding.go | 2 +-
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/arrow/compute/arithmetic_test.go b/arrow/compute/arithmetic_test.go
index 67e22e8e..d670db7b 100644
--- a/arrow/compute/arithmetic_test.go
+++ b/arrow/compute/arithmetic_test.go
@@ -1726,6 +1726,32 @@ func (ds *DecimalUnaryArithmeticSuite) TestRound() {
}
}
+func (ds *DecimalUnaryArithmeticSuite) TestRoundHalfToOddTies() {
+ for _, ty := range []arrow.DataType{
+ &arrow.Decimal128Type{Precision: 5, Scale: 2},
+ &arrow.Decimal256Type{Precision: 5, Scale: 2},
+ } {
+ ds.Run(ty.String(), func() {
+ options := compute.RoundOptions{NDigits: 0, Mode:
compute.RoundHalfToOdd}
+ values := ds.getArr(ty, `["2.50", "-2.50", "3.50",
"-3.50", null]`)
+ defer values.Release()
+
+ expected := ds.getArr(ty, `["3.00", "-3.00", "3.00",
"-3.00", null]`)
+ defer expected.Release()
+ checkScalar(ds.T(), "round",
[]compute.Datum{&compute.ArrayDatum{values.Data()}},
+ &compute.ArrayDatum{expected.Data()}, options)
+
+ options.NDigits = 1
+ values = ds.getArr(ty, `["12.25", "-12.25"]`)
+ defer values.Release()
+ expected = ds.getArr(ty, `["12.30", "-12.30"]`)
+ defer expected.Release()
+ checkScalar(ds.T(), "round",
[]compute.Datum{&compute.ArrayDatum{values.Data()}},
+ &compute.ArrayDatum{expected.Data()}, options)
+ })
+ }
+}
+
func (ds *DecimalUnaryArithmeticSuite) TestRoundTowardsInfinity() {
fn := "round"
options := compute.RoundOptions{NDigits: 0, Mode:
compute.RoundTowardsInfinity}
diff --git a/arrow/compute/internal/kernels/rounding.go
b/arrow/compute/internal/kernels/rounding.go
index a0428749..88794edb 100644
--- a/arrow/compute/internal/kernels/rounding.go
+++ b/arrow/compute/internal/kernels/rounding.go
@@ -306,7 +306,7 @@ func getDecRounding[T decimal128.Num | decimal256.Num](mode
RoundMode, opsImpl *
return func(val, remainder, _ T, scale int32) T {
scaled := opsImpl.reduceScale(val, scale, false)
if opsImpl.lowBits(scaled)%2 == 0 {
- if opsImpl.Sign(remainder) != 0 {
+ if opsImpl.Sign(remainder) > 0 {
scaled = opsImpl.Add(scaled, one)
} else {
scaled = opsImpl.Add(scaled, neg)