3.5.4.格式化浮点数
对于浮点数,我们可以指定其整体宽度、小数点后的位数及是否使用标准计数法和科学计数法。
1 2 3 | for _, x := range []float64{-.258, 7194.84, -60897162.0218, 1.500089e-8} { fmt.Printf("|%20.5e|%20.5f|%s|\n", x, x, Humanize(x, 20, 5, '*', ',')) } |
1 2 3 4 | |········-2.58000e-01|············-0.25800|************-0.25800| |·········7.19484e+03|··········7194.84000|*********7,194.84000| |········-6.08972e+07|·····-60897162.02180|***-60,897,162.02180| |·········1.50009e-08|·············0.00000|*************0.00000| |
在这里我们使用了for …range循环来遍历float64类型切片中的数字。自定义的Humanize() 函数返回了一个以字符串表示包含分组分隔符(简单的三位数字一组)和填充符的数字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | func Humanize(amount float64, width, decimals int, pad, separator rune) string { dollars, cents := math.Modf(amount) whole := fmt.Sprintf("%+.0f", dollars)[1:] // Strip "±" fraction := "" if decimals > 0 { fraction = fmt.Sprintf("%+.*f", decimals, cents)[2:] // Strip "±0" } sep := string(separator) for i := len(whole) - 3; i > 0; i -= 3 { whole = whole[:i] + sep + whole[i:] } if amount < 0.0 { whole = "-" + whole } number := whole + fraction gap := width - utf8.RuneCountInString(number) if gap > 0 { return strings.Repeat(string(pad), gap) + number } return number } |
math.Modf()函数可以返回一个float64类型的值的整数部分和小数部分,且其整数部分和小数部分都是float64类型。为了得到以字符串表示的整数部分,我们使用fmt.sprintf()函数和格式化动作来强制输出正号,然后立即切片该得到的字符串以去除正号。对于小数部分,我们也使用了类似的方式,只不过这次我们使用了.m格式化动作修饰符来指定使用*占位符的小数位数(所以在这种情况下,如果小数位数为2,则格式化动作应该是%+.2f)。对于小数部分,我们去除了其开头-0 或+0。
整个字符串被从右到左插入了分组分隔符,然后,如果值为负数,则插入一个“-”符号。最后,我们将整数部分和小数部分连接起来并将其返回,必要时可使用空格填充。
%e,、%E、 %f、 %g和%G可以用于复数和浮点数。%e 和%E是科学计算法格式的(指数的)格式化动作,%f是浮点数格式的格式化动作,%g 和%G是常规浮点数格式的格式化动作。
然而,需要记住的一点是,修饰符会同时应用于复数的实部和虚部,例如,如果参数是一个复数,%6f格式产生的结果会占用至少20个字符。
1 2 3 4 5 | for _, x := range []complex128{2 + 3i, 172.6 - 58.3019i, -.827e2 + 9.04831e-3i} { fmt.Printf("|%15s|%9.3f|%.2f|%.1e|\n", fmt.Sprintf("%6.2f%+.3fi", real(x), imag(x)), x, x, x) } |
1 2 3 | |····2.00+3.000i|(····2.000···+3.000i)|(2.00+3.00i)|(2.0e+00+3.0e+00i)| |·172.60-58.302i|(··172.600··-58.302i)|(172.60-58.30i)|(1.7e+02-5.8e+01i)| |··-82.70+0.009i|(··-82.700···+0.009i)|(-82.70+0.01i)|(-8.3e+01+9.0e-03i)| |
对于上例中结果的第一列,我们希望小数点后具有不同的小数位数。为此,我们使用fmt.Sprintf()函数分别格式化复数的实部和虚部部分,然后使用%15s格式将结果以字符串的形式输出。对于其他的复数,我直接使用%f和%e格式化动作,其在输出时总会以圆括号将结果括起来。