diff --git a/numeric.go b/numeric.go index f68e418..fda2499 100644 --- a/numeric.go +++ b/numeric.go @@ -115,9 +115,13 @@ func round(a interface{}, p int, rOpt ...float64) float64 { var round float64 pow := math.Pow(10, places) digit := pow * val + // Modf keeps the sign of the fraction. A negative fraction below the + // threshold rounds toward zero, matching the positive side. _, div := math.Modf(digit) if div >= roundOn { round = math.Ceil(digit) + } else if div < 0 && div > -roundOn { + round = math.Ceil(digit) } else { round = math.Floor(digit) } diff --git a/numeric_test.go b/numeric_test.go index 1252cd7..5f1105e 100644 --- a/numeric_test.go +++ b/numeric_test.go @@ -298,6 +298,15 @@ func TestRound(t *testing.T) { assert.Equal(t, 123.0, round(123.49999999, 0)) assert.Equal(t, 123.23, round(123.2329999, 2, .3)) assert.Equal(t, 123.24, round(123.233, 2, .3)) + // A negative fraction below the threshold rounds toward zero. + // -1.25 is exact in float64. Floor would return -2. + assert.Equal(t, -1.0, round(-1.25, 0)) + assert.Equal(t, -2.0, round(-1.5, 0)) + assert.Equal(t, -2.0, round(-1.75, 0)) + assert.Equal(t, -123.0, round(-123.49999999, 0)) + assert.Equal(t, -124.0, round(-123.500001, 0)) + assert.Equal(t, -123.23, round(-123.2329999, 2, .3)) + assert.Equal(t, -123.24, round(-123.233, 2, .3)) } func TestRandomInt(t *testing.T) {