diff --git a/flow/datatypes/bigint.go b/flow/datatypes/bigint.go index c33d8506a2..28a3b97148 100644 --- a/flow/datatypes/bigint.go +++ b/flow/datatypes/bigint.go @@ -1,12 +1,33 @@ package datatypes import ( + "math" "math/big" ) +var tenInt = big.NewInt(10) + func CountDigits(bi *big.Int) int { - if bi.Sign() < 0 { - return len(bi.String()) - 1 + if bi.IsInt64() { + i64 := bi.Int64() + // restrict fast path to integers with exact conversion to float64 + if i64 <= (1<<53) && i64 >= -(1<<53) { + if i64 == 0 { + return 1 + } + return int(math.Log10(math.Abs(float64(i64)))) + 1 + } + } + + estimatedNumDigits := int(float64(bi.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 bi.CmpAbs(errorCorrectionUnit) >= 0 { + return estimatedNumDigits + 1 } - return len(bi.String()) + + return estimatedNumDigits } diff --git a/flow/model/qvalue/avro_converter.go b/flow/model/qvalue/avro_converter.go index 2579511fdf..764fd86759 100644 --- a/flow/model/qvalue/avro_converter.go +++ b/flow/model/qvalue/avro_converter.go @@ -4,8 +4,6 @@ import ( "errors" "fmt" "log/slog" - "math" - "math/big" "time" "github.com/google/uuid" @@ -445,33 +443,6 @@ func (c *QValueAvroConverter) processNullableUnion( return value, nil } -var tenInt = big.NewInt(10) - -func countDigits(bi *big.Int) int { - if bi.IsInt64() { - i64 := bi.Int64() - // restrict fast path to integers with exact conversion to float64 - if i64 <= (1<<53) && i64 >= -(1<<53) { - if i64 == 0 { - return 1 - } - return int(math.Log10(math.Abs(float64(i64)))) + 1 - } - } - - estimatedNumDigits := int(float64(bi.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 bi.CmpAbs(errorCorrectionUnit) >= 0 { - return estimatedNumDigits + 1 - } - - return estimatedNumDigits -} - func (c *QValueAvroConverter) processNumeric(num decimal.Decimal) interface{} { num, err := TruncateOrLogNumeric(num, c.Precision, c.Scale, c.TargetDWH) if err != nil {