Implement IsInteger method (#179)

This commit is contained in:
Mateusz Woś 2020-07-01 01:20:32 +02:00 committed by GitHub
parent 2568a29459
commit 6fe01c1abd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 0 deletions

View file

@ -583,6 +583,33 @@ func (d Decimal) Pow(d2 Decimal) Decimal {
return temp.Mul(temp).Div(d)
}
// IsInteger returns true when decimal can be represented as an integer value, otherwise, it returns false.
func (d Decimal) IsInteger() bool {
// The most typical case, all decimal with exponent higher or equal 0 can be represented as integer
if d.exp >= 0 {
return true
}
// When the exponent is negative we have to check every number after the decimal place
// If all of them are zeroes, we are sure that given decimal can be represented as an integer
var r big.Int
q := big.NewInt(0).Set(d.value)
for z := abs(d.exp); z > 0; z-- {
q.QuoRem(q, tenInt, &r)
if r.Cmp(zeroInt) != 0 {
return false
}
}
return true
}
// Abs calculates absolute value of any int32. Used for calculating absolute value of decimal's exponent.
func abs(n int32) int32 {
if n < 0 {
return -n
}
return n
}
// Cmp compares the numbers represented by d and d2 and returns:
//
// -1 if d < d2

View file

@ -173,3 +173,13 @@ func Benchmark_decimal_Decimal_Sub_same_precision(b *testing.B) {
d1.Add(d2)
}
}
func BenchmarkDecimal_IsInteger(b *testing.B) {
d := RequireFromString("12.000")
b.ReportAllocs()
b.StartTimer()
for i := 0; i < b.N; i++ {
d.IsInteger()
}
}

View file

@ -2076,6 +2076,34 @@ func TestNegativePow(t *testing.T) {
}
}
func TestDecimal_IsInteger(t *testing.T) {
for _, testCase := range []struct {
Dec string
IsInteger bool
}{
{"0", true},
{"0.0000", true},
{"0.01", false},
{"0.01010101010000", false},
{"12.0", true},
{"12.00000000000000", true},
{"12.10000", false},
{"9999.0000", true},
{"99999999.000000000", true},
{"-656323444.0000000000000", true},
{"-32768.01234", false},
{"-32768.0123423562623600000", false},
} {
d, err := NewFromString(testCase.Dec)
if err != nil {
t.Fatal(err)
}
if d.IsInteger() != testCase.IsInteger {
t.Errorf("expect %t, got %t, for %s", testCase.IsInteger, d.IsInteger(), testCase.Dec)
}
}
}
func TestDecimal_Sign(t *testing.T) {
if Zero.Sign() != 0 {
t.Errorf("%q should have sign 0", Zero)