Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize NumDigits #356

Merged
merged 5 commits into from Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 25 additions & 6 deletions decimal.go
Expand Up @@ -1224,14 +1224,33 @@ func (d Decimal) Ln(precision int32) (Decimal, error) {
}

// NumDigits returns the number of digits of the decimal coefficient (d.Value)
// Note: Current implementation is extremely slow for large decimals and/or decimals with large fractional part
func (d Decimal) NumDigits() int {
d.ensureInitialized()
// Note(mwoss): It can be optimized, unnecessary cast of big.Int to string
if d.IsNegative() {
return len(d.value.String()) - 1
if d.value == nil {
return 1
}

if d.value.IsInt64() {
i64 := d.value.Int64()
// restrict fast path to integers with exact conversion to float64
if i64 <= (1<<53) && i64 >= -(1<<53) {
serprex marked this conversation as resolved.
Show resolved Hide resolved
if i64 == 0 {
return 1
}
mwoss marked this conversation as resolved.
Show resolved Hide resolved
return int(math.Log10(math.Abs(float64(i64)))) + 1
}
}

estimatedNumDigits := int(float64(d.value.BitLen()) / math.Log2(10))

// estimatedNumDigits (lg10) may be off by 1, need to verify
digitsBigInt := big.NewInt(int64(estimatedNumDigits))
errorCorrectionUnit := digitsBigInt.Exp(tenInt, digitsBigInt, nil)

if d.value.CmpAbs(errorCorrectionUnit) >= 0 {
return estimatedNumDigits + 1
}
return len(d.value.String())

return estimatedNumDigits
}

// IsInteger returns true when decimal can be represented as an integer value, otherwise, it returns false.
Expand Down
36 changes: 32 additions & 4 deletions decimal_bench_test.go
Expand Up @@ -121,6 +121,34 @@ func BenchmarkDecimal_RoundCash_Five(b *testing.B) {
}
}

func numDigits(b *testing.B, want int, val Decimal) {
b.Helper()
for i := 0; i < b.N; i++ {
if have := val.NumDigits(); have != want {
b.Fatalf("\nHave: %d\nWant: %d", have, want)
}
}
}

func BenchmarkDecimal_NumDigits10(b *testing.B) {
numDigits(b, 10, New(3478512345, -3))
}

func BenchmarkDecimal_NumDigits100(b *testing.B) {
s := make([]byte, 102)
for i := range s {
s[i] = byte('0' + i%10)
}
s[0] = '-'
s[100] = '.'
d, err := NewFromString(string(s))
if err != nil {
b.Log(d)
b.Error(err)
}
numDigits(b, 100, d)
}

func Benchmark_Cmp(b *testing.B) {
decimals := DecimalSlice([]Decimal{})
for i := 0; i < 1000000; i++ {
Expand All @@ -132,7 +160,7 @@ func Benchmark_Cmp(b *testing.B) {
}
}

func Benchmark_decimal_Decimal_Add_different_precision(b *testing.B) {
func BenchmarkDecimal_Add_different_precision(b *testing.B) {
mwoss marked this conversation as resolved.
Show resolved Hide resolved
d1 := NewFromFloat(1000.123)
d2 := NewFromFloat(500).Mul(NewFromFloat(0.12))

Expand All @@ -143,7 +171,7 @@ func Benchmark_decimal_Decimal_Add_different_precision(b *testing.B) {
}
}

func Benchmark_decimal_Decimal_Sub_different_precision(b *testing.B) {
func BenchmarkDecimal_Sub_different_precision(b *testing.B) {
d1 := NewFromFloat(1000.123)
d2 := NewFromFloat(500).Mul(NewFromFloat(0.12))

Expand All @@ -154,7 +182,7 @@ func Benchmark_decimal_Decimal_Sub_different_precision(b *testing.B) {
}
}

func Benchmark_decimal_Decimal_Add_same_precision(b *testing.B) {
func BenchmarkDecimal_Add_same_precision(b *testing.B) {
d1 := NewFromFloat(1000.123)
d2 := NewFromFloat(500.123)

Expand All @@ -165,7 +193,7 @@ func Benchmark_decimal_Decimal_Add_same_precision(b *testing.B) {
}
}

func Benchmark_decimal_Decimal_Sub_same_precision(b *testing.B) {
func BenchmarkDecimal_Sub_same_precision(b *testing.B) {
d1 := NewFromFloat(1000.123)
d2 := NewFromFloat(500.123)

Expand Down