go - %g 中具有宽度和精度字段的 fmt.Printf 行为异常

标签 go printf

我正在尝试使用 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/

相关文章:

go - 如何使用 paho.mqtt.golang 库订阅多个 MQTT 主题?

c - 为什么我的函数会产生额外的新行?

c - Windows 和 Linux 中 printf 的区别

go - 克服 Go 中不允许的导入周期

go - 类型在Golang Api种类结构创建上发生冲突

Calloc 与 fgets 的交互很奇怪?

c - 只打印 double 的小数位

c - 进行循环工作

nginx - SSL with GoLang 使用反向代理 Nginx

go - 简化 golang 中重复出现的 switch case