formatter下的DecimalBytes非整数
DecimalBytes : 返回十进制标准(以 1000 为基数)下的可读字节单位字符串。precision 参数指定小数点后的位数,默认为 4。
根据描述precision参数为控制小数点的位数,但某些情况下会变成科学计数法 例如
// 测试6000万这个数
formatter.DecimalBytes(61812496)
// 61.812MB
formatter.DecimalBytes(61812496, 2)
// 61.8MB
formatter.DecimalBytes(61812496, 1)
// 62MB
formatter.DecimalBytes(61812496, 0)
// 6e+01MB
//再测试4亿这个数
formatter.DecimalBytes(401000000)
//401MB
formatter.DecimalBytes(4010000, 0)
//4e+02MB
最后我的解决办法,不知道合不合理 缺点就是在401.00000MB整数的时候还是会带上小数位数,不知道如何优化了。但不会出现科学计数法的表示,可以接受
func DecimalBytes(size float64, precision ...int) string {
p := 5
if len(precision) > 0 {
p = precision[0]
}
size, unit := calculateByteSize(size, 1000.0, decimalByteUnits)
position := fmt.Sprintf("%%.%df", p)
return fmt.Sprintf(position+"%s", size, unit)
}
// 测试6000万这个数
utils.DecimalBytes(61812496)
// 61.81250MB
utils.DecimalBytes(61812496, 2)
// 61.81MB
utils.DecimalBytes(61812496, 1)
// 61.8MB
utils.DecimalBytes(61812496, 0)
// 62MB
//再测试4亿这个数
utils.DecimalBytes(401000000)
//401.00000MB
utils.DecimalBytes(4010000, 0)
//4MB
@imyuanandyou 可以对格式化之后的数字字符串进行处理,根据需要去除'.'和'0', 参考以下代码:
func DecimalBytes(size float64, precision ...int) string {
pointPosition := 4
if len(precision) > 0 {
pointPosition = precision[0]
}
size, unit := calculateByteSize(size, 1000.0, decimalByteUnits)
format := fmt.Sprintf("%%.%df", pointPosition)
result := fmt.Sprintf(format, size)
for i := len(result); i > 0; i-- {
s := result[i-1]
if s == '0' || s == '.' {
result = result[:i-1]
} else {
break
}
}
return result + unit
}
thanks! 后续会考虑将这部分改动,放入正式版本吗?目的是DecimalBytes时不会出现科学计数法
@imyuanandyou, 会放入正式版,这个已经在v2分支上修复,会在下个版本(v2.3.3)发布。
后续测试后发现 (根据需要去除'.'和'0', 参考以下代码)这段代码会将整数0结尾也一同去掉
func main() {
fmt.Println(DecimalBytes(40, 0))
// 理论得到40B,但结果是4B
}
var (
decimalByteUnits = []string{"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
binaryByteUnits = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
)
func DecimalBytes(size float64, precision ...int) string {
pointPosition := 4
if len(precision) > 0 {
pointPosition = precision[0]
}
size, unit := calculateByteSize(size, 1000.0, decimalByteUnits)
format := fmt.Sprintf("%%.%df", pointPosition)
result := fmt.Sprintf(format, size)
for i := len(result); i > 0; i-- {
s := result[i-1]
if s == '0' || s == '.' {
result = result[:i-1]
} else {
break
}
}
return result + unit
}
func calculateByteSize(size float64, base float64, byteUnits []string) (float64, string) {
i := 0
unitsLimit := len(byteUnits) - 1
for size >= base && i < unitsLimit {
size = size / base
i++
}
return size, byteUnits[i]
}
另外科学计数法同样会出现在formatter.BinaryBytes返回binary标准(以1024为基数) 这个方法
然后贴一下我自己FloorToString的方法,max为想要保留的最大小数位,默认是两位。BinaryBytes、DecimalBytes感觉上是相同的需求
func FloorToString(x float64, max ...int) string {
pointPosition := 2
if len(max) > 0 {
pointPosition = max[0]
}
result := mathutil.FloorToString(x, pointPosition)
// 删除小数位结尾的0
decimal := strings.TrimRight(strutil.After(result, "."), "0")
if decimal == "" || pointPosition == 0 {
// 没有小数位直接返回整数
return strutil.Before(result, ".")
}
// 小数位大于想要设置的位数,按需要截断
if len(decimal) > pointPosition {
return strutil.Before(result, ".") + "." + decimal[:pointPosition]
}
// 小数位小于等于想要的位数,直接拼接返回
return strutil.Before(result, ".") + "." + decimal
}
func main() {
fmt.Println(utils.FloorToString(1000.0001, 2))
// 输出1000
fmt.Println(utils.FloorToString(1000.1001, 2))
// 输出1000
fmt.Println(utils.FloorToString(1000.1, 2))
// 输出1000.1
fmt.Println(utils.FloorToString(1000, 0))
// 输出1000
}
@imyuanandyou, 👍 这些解决方案,你可以提PR,merge到rc分支。
v2.3.3版本已修复