Go %g中带有宽度和精度字段的fmt.Printf的行为异常
我正在尝试使用Go %g中带有宽度和精度字段的fmt.Printf的行为异常,go,printf,Go,Printf,我正在尝试使用fmt.Printf()将一些浮点数格式化为相同的宽度 例如,给定浮点值0.06060606、0.3333333、0.05、0.4和0.181818,我希望将每个值格式化为10个符文: 0.06060606 0.33333333 0.05 0.4 0.18181818 但我不明白是怎么做到的。文件上说, 对于浮点值,“宽度”设置字段的最小宽度 和精度设置小数点后的位数,如果 适当,但对于%g/%g,它设置了总位数。 例如,给定123.45,格式%6.2f
fmt.Printf()
将一些浮点数格式化为相同的宽度
例如,给定浮点值0.06060606、0.3333333、0.05、0.4和0.181818,我希望将每个值格式化为10个符文:
0.06060606
0.33333333
0.05
0.4
0.18181818
但我不明白是怎么做到的。文件上说,
对于浮点值,“宽度”设置字段的最小宽度
和精度设置小数点后的位数,如果
适当,但对于%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
为什么我得到的字符串是10个符文,其他的是11个符文,其他的是12个符文
特别是,
%.9g
似乎总共不产生9位数字。参见示例:是的,我同意:它优先于“精度字段”,而不是“宽度”。
因此,当我们需要修复打印列时,我们需要编写新的格式化函数。首先,我们需要正确理解文档: 宽度设置字段的最小宽度,精度设置小数点后的位数(如果适用),但%g/%g设置的是总位数 这一行在语法上是正确的,但这句话最后一部分的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位,不包括所有小数点和指数。但是等等,最后2个例子会发生什么?你在开玩笑吧,那不是超过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时,它们将被计数,如果前导0多于4,它们将被缩小
好的,接下来是宽度。从文档中,width
仅指定最小宽度,包括小数位和指数。这意味着,如果您的位数超过指定的宽度
,它将超出宽度
请记住,宽度将被视为最后一步,这意味着它需要首先满足精度字段的要求
让我们回到你的案子。您指定了%10.9g
,这意味着您希望总数字为9,不包括前导的0
,最小宽度为10
,包括小数位和指数,精度应优先
0.060606
:不带前导0的9位数字将给出0.0606
,因为它已经是12个宽度,它通过了最小宽度10
0.3333333
:不带前导0的9位数字将给出0.333333
,因为它已经是11个宽度,它通过了最小宽度10
0.05
:不带前导0的9位数字将为您提供0.05
,因为它小于宽度10,所以它将用另外6个宽度填充以获得宽度10
0.4
:同上
0.181818
:不带前导0的9位数字将给出0.1818182
的四舍五入,因为它已经是11个宽度,所以它通过了最小宽度10
因此,这就解释了为什么要进行有趣的打印。精度(如%.9g
)是科学符号中的位数(即忽略前导零)。这并没有很好的文档记录,我建议在github.com/golang/go上提交一个bug。宽度(如%10g
)是根据文档输出的最小符文数。因此,输出看起来是正确的。啊,因此,0.000123456789
仍然使用13位数字进行格式化,使用%.9g
!该死,从文件上看不清楚。。。“总位数”有点误导人@AkiRoss您是对的,Go的官方文档在这方面确实令人困惑:(我相信这个问题会帮助很多人。我希望它会有用。总的来说,我觉得格式化不是一个简单的话题。以下是与问题报告相关的/可能重复的简单答案是“%10.5g”但是它不会返回浮点数的最大有效位数OP是在问为什么,而不是在寻找解决方案:pYes,我同意。我认为Printf的fmt库需要重写以提供更多有效位数。对于提供16位有效位数的float64,出于任何原因丢失有效位数都有点奇怪.并在%L.Dg中对长度提交多一点尊重