具有%g的宽度和精度字段的fmt.Printf意外地表现

Aki*_*oss 5 printf go

我试图得到一些使用相同宽度格式化的浮点数fmt.Printf().

例如,给定浮点值0.0606060606060606,0.3333333333333333,0.05,0.4和0.1818181818181818,我想将每个值格式化为10符文:

0.06060606
0.33333333
      0.05
       0.4
0.18181818
Run Code Online (Sandbox Code Playgroud)

但我无法理解它是如何完成的.文档说

对于浮点值,width设置字段的最小宽度,precision设置小数点后的位数(如果适用),但%g /%G除外,它设置总位数.例如,给定123.45格式%6.2f打印123.45而%.4g打印123.5.%e和%f的默认精度为6; 对于%g,它是唯一标识值所需的最小位数.

因此,如果我使用%f较大的数字将不适合10个字符的约束,因此%g是必需的.要获得最小宽度为10 %10g并获得最大数量的9位数(点的+1)%.9g,但将它们组合起来%10.9g并不像我期望的那样

0.0606060606
0.333333333
      0.05
       0.4
0.181818182
Run Code Online (Sandbox Code Playgroud)

为什么我得到10符文的字符串,其他的符文是11符文,其他符号是12符文?

特别是,似乎%.9g总共不产生9位数.参见例如:http://play.golang.org/p/ie9k8bYC7r

nev*_*ets 1

首先,我们需要正确理解文档:

宽度设置字段的最小宽度,精度设置小数点后的位数(如果适用),但 %g/%G 除外,它设置总位数。

这行在语法上是正确的,但是这句话最后部分的it确实令人困惑:它实际上指的是precision,而不是width

因此,让我们看一些例子:

123.45
12312.2
1.6069
0.6069
0.0006069
Run Code Online (Sandbox Code Playgroud)

你打印它就像fmt.Printf("%.4g"),它给了你

123.5
1.231e+04
1.607
0.6069
0.0006069
Run Code Online (Sandbox Code Playgroud)

仅 4 位数字,不包括所有小数点和指数。但是等等,最后两个例子会发生什么?你开玩笑吧,这不是超过5位数吗?

这是打印中令人困惑的部分:前导 0不会被计为数字,并且当 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)
}
Run Code Online (Sandbox Code Playgroud)

和输出:

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
Run Code Online (Sandbox Code Playgroud)

所以你可以看到,当前导 0 少于 4 个时,它们将被计数,如果超过 4 个,则会被缩小。

好吧,接下来的事情就是width. 从文档中,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:取9位不带前导0的数字给你0.05,因为它小于宽度 10,所以它将用另外 6 个宽度填充以获得宽度 10;

0.4:同上;

0.1818181818181818:取 9 位数字而不带前导0 会给你0.181818182四舍五入,因为它已经是 11 宽度,它超过了最小宽度 10。

这解释了为什么你会得到有趣的印刷。