我正在尝试使用 fmt.Printf()
将一些 float 格式化为相同的宽度。
例如,给定浮点值 0.0606060606060606、0.3333333333333333、0.05、0.4 和 0.1818181818181818,我想将每个值格式化为 10 个 rune :
0.06060606
0.33333333
0.05
0.4
0.18181818
但是我不明白它是怎么做到的。文档说
For floating-point values, width sets the minimum width of the field and precision sets the number of places after the decimal, if appropriate, except that for %g/%G it sets the total number of digits. For example, given 123.45 the format %6.2f prints 123.45 while %.4g prints 123.5. The default precision for %e and %f is 6; for %g it is the smallest number of digits necessary to identify the value uniquely.
因此,如果我使用 %f
,则更大的数字将不适合 10 个字符的限制,因此需要 %g
。要获得 10 的最小宽度是 %10g
并且要获得最大数量的 9 位数字(+1 为点)它是 %.9g
,但是将它们组合在 %10.9g
的行为与我预期的不一样
0.0606060606
0.333333333
0.05
0.4
0.181818182
为什么我得到的字符串是 10 个 rune ,其他字符串是 11 个 rune 和其他字符串是 12 个 rune ?
特别是,%.9g
似乎并没有产生总共 9 位数字。参见示例:http://play.golang.org/p/ie9k8bYC7r
最佳答案
首先,我们需要正确理解文档:
width sets the minimum width of the field and precision sets the number of places after the decimal, if appropriate, except that for %g/%G it sets the total number of digits.
这一行在语法上是正确的,但是这句话最后部分的it真的很令人困惑:它实际上指的是精度,而不是宽度.
因此,让我们看一些例子:
123.45
12312.2
1.6069
0.6069
0.0006069
然后你像 fmt.Printf("%.4g")
一样打印它,它给你
123.5
1.231e+04
1.607
0.6069
0.0006069
只有 4 个数字,不包括所有小数点和指数。但是等等,最后两个例子会发生什么?你开玩笑吧,这不是超过 5 位数吗?
这是打印中令人困惑的部分:前导 0 不会算作数字,并且当少于 4 个零时不会收缩。
让我们使用以下示例查看 0 行为:
package main
import "fmt"
func main() {
fmt.Printf("%.4g\n", 0.12345)
fmt.Printf("%.4g\n", 0.012345)
fmt.Printf("%.4g\n", 0.0012345)
fmt.Printf("%.4g\n", 0.00012345)
fmt.Printf("%.4g\n", 0.000012345)
fmt.Printf("%.4g\n", 0.0000012345)
fmt.Printf("%.4g\n", 0.00000012345)
fmt.Printf("%g\n", 0.12345)
fmt.Printf("%g\n", 0.012345)
fmt.Printf("%g\n", 0.0012345)
fmt.Printf("%g\n", 0.00012345)
fmt.Printf("%g\n", 0.000012345)
fmt.Printf("%g\n", 0.0000012345)
fmt.Printf("%g\n", 0.00000012345)
}
和输出:
0.1235
0.01235
0.001234
0.0001234
1.234e-05
1.234e-06
1.235e-07
0.12345
0.012345
0.0012345
0.00012345
1.2345e-05
1.2345e-06
1.2345e-07
所以你可以看到,当前导 0 少于 4 个时,它们将被计算在内,如果多于 4 个,则收缩。
好的,接下来是宽度
。根据文档,width
仅指定最小宽度,包括小数位和指数。这意味着,如果您的位数多于 width
指定的位数,它将超出宽度。
请记住,宽度将被视为最后一步,这意味着它需要首先满足精度字段。
让我们回到您的案例。您指定了 %10.9g
,这意味着您希望总位数为 9,不包括前导 0
,最小宽度为 10
,包括小数位和指数,精度优先。
0.0606060606060606
:取 9 位不带前导 0 将得到 0.0606060606
,因为它已经是 12 宽度,它超过了最小宽度 10;
0.3333333333333333
:取 9 位不带前导 0 将得到 0.333333333
,因为它已经是 11 宽度,它超过了最小宽度 10;
0.05
:取前导 0 的 9 位数字将得到 0.05
,因为它小于宽度 10,它将用另外 6 个宽度填充以获得宽度 10;
0.4
:同上;
0.1818181818181818
:取前导 0 的 9 位数字将得到 0.181818182
和舍入,因为它已经是 11 宽度,它超过了最小宽度共 10 个。
所以这就解释了为什么你得到了有趣的打印。
关于go - %g 中具有宽度和精度字段的 fmt.Printf 行为异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36464068/