fix(v2): money 去 float 进制 + 溢出防护 + 补 Format/负数/溢出测试

- money.go: 用纯 int64 循环乘法替代 int64(math.Pow10(exp)) 计算进制因子
- Parse: whole*mult+frac 前加溢出检查(math.MaxInt64 仅作整型常量参与比较,无 float 参与)
- money_test.go: 补 Format 未知币种错误分支(errors.Is ErrUnknownCurrency)、
  Parse 溢出(整数部分过大)、负数往返测试
This commit is contained in:
wangjia
2026-07-10 08:10:36 +08:00
parent 8555368785
commit 7da15c00a1
2 changed files with 58 additions and 2 deletions
+16 -2
View File
@@ -24,6 +24,16 @@ func Exponent(currency string) (int, bool) {
return e, ok
}
// pow10Int64 computes 10^exp as a pure int64 (no float), matching the
// currency exponents above which never exceed a handful of digits.
func pow10Int64(exp int) int64 {
mult := int64(1)
for i := 0; i < exp; i++ {
mult *= 10
}
return mult
}
// Format renders minor units as a decimal string, trailing zeros trimmed.
func Format(minor int64, currency string) (string, error) {
exp, ok := Exponent(currency)
@@ -37,7 +47,7 @@ func Format(minor int64, currency string) (string, error) {
if neg {
minor = -minor
}
div := int64(math.Pow10(exp))
div := pow10Int64(exp)
whole := minor / div
frac := minor % div
s := fmt.Sprintf("%d.%0*d", whole, exp, frac)
@@ -81,7 +91,11 @@ func Parse(s, currency string) (int64, error) {
return 0, fmt.Errorf("money.Parse frac %q: %w", s, err)
}
}
minor := whole*int64(math.Pow10(exp)) + frac
mult := pow10Int64(exp)
if mult > 0 && whole > (math.MaxInt64-frac)/mult {
return 0, fmt.Errorf("money.Parse: %q overflows int64 for %s", s, currency)
}
minor := whole*mult + frac
if neg {
minor = -minor
}