package utils import ( "bytes" "math" "math/big" "strconv" "strings" ) // Comma 以逗号分隔开整数 // e.g. Comma(834142) -> 834,142 func Comma(v int64) string { sign := "" // Min int64 can't be negated to a usable value, so it has to be special cased. if v == math.MinInt64 { return "-9,223,372,036,854,775,808" } if v < 0 { sign = "-" v = 0 - v } parts := []string{"", "", "", "", "", "", ""} j := len(parts) - 1 for v > 999 { parts[j] = strconv.FormatInt(v%1000, 10) switch len(parts[j]) { case 2: parts[j] = "0" + parts[j] case 1: parts[j] = "00" + parts[j] } v = v / 1000 j-- } parts[j] = strconv.Itoa(int(v)) return sign + strings.Join(parts[j:], ",") } // Commaf 以逗号分隔开浮点数 // e.g. Commaf(834142.32) -> 834,142.32 func Commaf(v float64) string { buf := &bytes.Buffer{} if v < 0 { buf.Write([]byte{'-'}) v = 0 - v } comma := []byte{','} parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".") pos := 0 if len(parts[0])%3 != 0 { pos += len(parts[0]) % 3 buf.WriteString(parts[0][:pos]) buf.Write(comma) } for ; pos < len(parts[0]); pos += 3 { buf.WriteString(parts[0][pos : pos+3]) buf.Write(comma) } buf.Truncate(buf.Len() - 1) if len(parts) > 1 { buf.Write([]byte{'.'}) buf.WriteString(parts[1]) } return buf.String() } // CommafWithDigits 以逗号分隔开浮点数, 且限制小数位 // e.g. CommafWithDigits(834142.32, 1) -> 834,142.3 func CommafWithDigits(f float64, decimals int) string { return stripTrailingDigits(Commaf(f), decimals) } // BigComma 以逗号分隔开超长整数 func BigComma(b *big.Int) string { sign := "" if b.Sign() < 0 { sign = "-" b.Abs(b) } athousand := big.NewInt(1000) c := (&big.Int{}).Set(b) _, m := oom(c, athousand) parts := make([]string, m+1) j := len(parts) - 1 mod := &big.Int{} for b.Cmp(athousand) >= 0 { b.DivMod(b, athousand, mod) parts[j] = strconv.FormatInt(mod.Int64(), 10) switch len(parts[j]) { case 2: parts[j] = "0" + parts[j] case 1: parts[j] = "00" + parts[j] } j-- } parts[j] = strconv.Itoa(int(b.Int64())) return sign + strings.Join(parts[j:], ",") } func stripTrailingDigits(s string, digits int) string { if i := strings.Index(s, "."); i >= 0 { if digits <= 0 { return s[:i] } i++ if i+digits >= len(s) { return s } return s[:i+digits] } return s } // total order of magnitude // (same as above, but with no upper limit) func oom(n, b *big.Int) (float64, int) { mag := 0 m := &big.Int{} for n.Cmp(b) >= 0 { n.DivMod(n, b, m) mag++ } return float64(n.Int64()) + (float64(m.Int64()) / float64(b.Int64())), mag }