PaesslerAG/gval

Handle decimal/money arithmetic

machship-mm opened this issue · 2 comments

This library is fantastic!

The one issue I've found is that the Arithmetic is done as floating point numbers (which is fine for that use case) but this falls short when doing math involving decimals.

An example:

func TestDecimalArithmetic(t *testing.T) {
	input := ArithmeticVariables{
		NumberMap: map[string]float64{
			"x": 12.5,
			"y": -5,
		},
		Expression: "(x * 12.146) - y",
	}

	result, _ := gval.Arithmetic().Evaluate(input.Expression, input.NumberMap)

	want := 156.825
	if result != want {
		t.Errorf("wanted %f; got %f", want, result)
		t.FailNow()
	}

	t.Log(result)
}

This results in this output:

=== RUN   TestDecimalArithmetic
    arithmetic_test.go:46: wanted 156.825000; got 156.825000
--- FAIL: TestDecimalArithmetic (0.00s)

When inspecting the variable values, I can see that result has the actual value of 156.82500000000002.

Do you have any suggestions for what I should do, or is this even a solvable problem?

I was thinking that there could be an EvaluateDecimal method, which instead of treating numbers as floats, would treat them as a decimal type? For decimals, I use github.com/shopspring/decimal.

Thanks.

You can Override the == Operator and use a small delta for comparing float64 zu each other. a + delta <= b && a - delta >= b that should solve your problem.

If you want you can make a push request for func DecimalEqual(delta float64) Language
That could help others, too.

Thanks @generikvault, I've now pushed a pull request that fixes this issue. I've tested it both in the gval repo and in my code base which is using this code and can confirm that this handles decimal arithmetic and logic appropriately.