Skip to content

Commit

Permalink
fix: zero value incorect comparison (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
quagmt authored Oct 17, 2024
1 parent 9d5eef5 commit 603c3aa
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 7 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ name: CI

on:
pull_request:
paths:
- "**.go"
- go.mod
- go.sum
- ".github/workflows/ci.yaml"
- ".golangci.yaml"

jobs:
lint:
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/codecov.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ on:
push:
branches:
- master
paths:
- "**.go"
- go.mod
- go.sum
- ".github/workflows/codecov.yaml"

jobs:
test:
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/quagmt/udecimal)](https://goreportcard.com/report/github.com/quagmt/udecimal)
[![codecov](https://codecov.io/gh/quagmt/udecimal/graph/badge.svg?token=662ET843EZ)](https://codecov.io/gh/quagmt/udecimal)
[![GoDoc](https://pkg.go.dev/badge/github.com/quagmt/udecimal)](https://pkg.go.dev/github.com/quagmt/udecimal)
[![Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go#financial)

High performance, high precision, zero allocation fixed-point decimal number for financial applications.

Expand Down Expand Up @@ -139,7 +140,7 @@ type bint struct {
// For coefficients exceeding u128
bigInt *big.Int

// For coefficients less than 2^128-1
// For coefficients less than 2^128
u128 u128
}
```
Expand Down
12 changes: 10 additions & 2 deletions decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ func NewFromHiLo(neg bool, hi uint64, lo uint64, prec uint8) (Decimal, error) {

// newDecimal return the decimal
func newDecimal(neg bool, coef bint, prec uint8) Decimal {
if coef.IsZero() {
// make Zero consistent and avoid unexpected cases, such as:
// - coef = 0 and neg is true
// - coef = 0 and prec != 0
// These cases results in incorrect comparison between zero values
return Zero
}

return Decimal{neg: neg, coef: coef, prec: prec}
}

Expand Down Expand Up @@ -678,12 +686,12 @@ func (d Decimal) rescale(prec uint8) Decimal {

// Neg returns -d
func (d Decimal) Neg() Decimal {
return Decimal{neg: !d.neg, coef: d.coef, prec: d.prec}
return newDecimal(!d.neg, d.coef, d.prec)
}

// Abs returns |d|
func (d Decimal) Abs() Decimal {
return Decimal{neg: false, coef: d.coef, prec: d.prec}
return newDecimal(false, d.coef, d.prec)
}

// Sign returns:
Expand Down
83 changes: 79 additions & 4 deletions decimal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,9 +520,9 @@ func TestAdd(t *testing.T) {
{"9999999999999999999.9999999999999999999", "999999999999999999.999", false},
{"9999999999999999999.9999999999999999999", "9999999999999999999.9999999999999999999", false},
{"-9999999999999999999.9999999999999999999", "-9999999999999999999.9999999999999999999", false},
{"1234567890123456789012345678901234567890.1234567890123456789", "-1234567890123456789012345678901234567890.1234567890123456789", false},
{"-1234567890123456789012345678901234567890.1234567890123456789", "1234567890123456789012345678901234567890.1234567890123456789", false},
{"1234567890123456789012345678901234567890.1234567890123456789", "1234567890123456789012345678901234567890.1234567890123456789", true},
{"1234567890123456789012345678901234567890.1234567890123456789", "-1234567890123456789012345678901234567890.1234567890123456789", true},
{"-1234567890123456789012345678901234567890.1234567890123456789", "1234567890123456789012345678901234567890.1234567890123456789", true},
{"-1234567890123456789012345678901234567890.1234567890123456789", "-1234567890123456789012345678901234567890.1234567890123456789", true},
}

Expand Down Expand Up @@ -644,10 +644,10 @@ func TestSub(t *testing.T) {
{"-9999999999999999999.9999999999999999999", "0.999", false},
{"0.999", "-9999999999999999999.9999999999999999999", false},
{"-0.999", "9999999999999999999.9999999999999999999", false},
{"1234567890123456789012345678901234567890.1234567890123456789", "1234567890123456789012345678901234567890.1234567890123456789", true},
{"1234567890123456789012345678901234567890.1234567890123456789", "1234567890123456789012345678901234567890.1234567890123456789", false},
{"-1234567890123456789012345678901234567890.1234567890123456789", "-1234567890123456789012345678901234567890.1234567890123456789", false},
{"1234567890123456789012345678901234567890.1234567890123456789", "-1234567890123456789012345678901234567890.1234567890123456789", true},
{"-1234567890123456789012345678901234567890.1234567890123456789", "1234567890123456789012345678901234567890.1234567890123456789", true},
{"-1234567890123456789012345678901234567890.1234567890123456789", "-1234567890123456789012345678901234567890.1234567890123456789", true},
}

for _, tc := range testcases {
Expand Down Expand Up @@ -2215,3 +2215,78 @@ func TestInexactFloat64(t *testing.T) {
})
}
}

func TestCmpZeroResult(t *testing.T) {
testcases := []string{
"0",
"0.123456789",
"-0.123456789",
"-123456789.123456789",
"1234567890123456789.1234567890123456789",
"-1234567890123456789.1234567890123456789",
"123456789123456789123456789.1234567890123456789",
"-123456789123456789123456789.1234567890123456789",
}

for _, tc := range testcases {
t.Run(fmt.Sprintf("cmpZero(%s)", tc), func(t *testing.T) {
a := MustParse(tc)
cmpZero(t, a, a)
})
}
}

func cmpZero(t *testing.T, a, b Decimal) {
a1 := a.Sub(b)
a2 := a.Add(b.Neg())
a3 := Zero.Mul(a)
a4 := a.Mul(Zero)

var (
a5 Decimal
err error
)

if !a.IsZero() {
a5, err = Zero.Div(a)
require.NoError(t, err)
}

d := []Decimal{a1, a2, a3, a4, a5}

for _, dd := range d {
require.True(t, dd.IsZero())
require.False(t, dd.IsNeg())
require.False(t, dd.IsPos())

require.Equal(t, 0, dd.Cmp(Zero))
require.Equal(t, 0, Zero.Cmp(dd))
require.Equal(t, Zero, dd)
}
}

func TestCmpWithDiffPrec(t *testing.T) {
testcases := []struct {
a int64
aprec uint8
}{
{100, 1},
{100, 1},
{123456789, 3},
{-100, 1},
{-123456789, 3},
{0, 10},
{-0, 13},
}

for _, tc := range testcases {
t.Run(fmt.Sprintf("cmpWithDiffPrec(%d, %d)", tc.a, tc.aprec), func(t *testing.T) {
a := MustFromInt64(tc.a, tc.aprec)

for i := tc.aprec; i <= maxPrec; i++ {
b := a.rescale(i)
cmpZero(t, a, b)
}
})
}
}

0 comments on commit 603c3aa

Please sign in to comment.