doujiang5211 2016-04-06 23:25
浏览 54
已采纳

具有%g中的width和precision字段的fmt.Printf表现异常

I am trying to get some floats formatted with the same width using fmt.Printf().

For example, given the float values 0.0606060606060606, 0.3333333333333333, 0.05, 0.4 and 0.1818181818181818, I would like to get each value formatted in, say, 10 runes:

0.06060606
0.33333333
      0.05
       0.4
0.18181818

But I can't understand how it's done. Documentation says that

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.

So, if I use %f a larger number will not fit in 10-character constraint, therefore %g is required. To get a minimum width of 10 is %10g and to get a maximum number of 9 digits (+1 for the dot) it's %.9g, but combining them in %10.9g is not behaving as I expect

0.0606060606
0.333333333
      0.05
       0.4
0.181818182

How come I get strings which are of 10 runes, others that are 11 runes and others that are 12 runes?

In particular, it seems that %.9g does not produce 9 digits in total. See for example: http://play.golang.org/p/ie9k8bYC7r

  • 写回答

2条回答 默认 最新

  • ds122455 2016-04-07 06:49
    关注

    Firstly, we need to understand the documentation correctly:

    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.

    This line is grammatically correct, but the it in the last part of this sentence is really confusing: it actually refers to the precision, not the width.

    Therefore, let's look at some examples:

    123.45
    12312.2
    1.6069
    0.6069
    0.0006069
    

    and you print it like fmt.Printf("%.4g"), it gives you

    123.5
    1.231e+04
    1.607
    0.6069
    0.0006069
    

    only 4 digits, excluding all decimal points and exponent. But wait, what happens to the last 2 example? Are you kidding me isn't that more than 5 digits?

    This is the confusing part in printing: leading 0s won't be counted as digits, and won't be shrunk when there are less than 4 zeros.

    Let's look at 0 behavior using the example below:

    package main
    
    import "fmt"
    
    func main() {
        fmt.Printf("%.4g
    ", 0.12345)
        fmt.Printf("%.4g
    ", 0.012345)
        fmt.Printf("%.4g
    ", 0.0012345)
        fmt.Printf("%.4g
    ", 0.00012345)
        fmt.Printf("%.4g
    ", 0.000012345)
        fmt.Printf("%.4g
    ", 0.0000012345)
        fmt.Printf("%.4g
    ", 0.00000012345)
    
        fmt.Printf("%g
    ", 0.12345)
        fmt.Printf("%g
    ", 0.012345)
        fmt.Printf("%g
    ", 0.0012345)
        fmt.Printf("%g
    ", 0.00012345)
        fmt.Printf("%g
    ", 0.000012345)
        fmt.Printf("%g
    ", 0.0000012345)
        fmt.Printf("%g
    ", 0.00000012345)
    }
    

    and the output:

    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
    

    So you could see, when there are less than 4 leading 0s, they will be counted, and be shrunk if there are more than that.

    Ok, next thing is the width. From the documentation, width only specifies the minimum width, including decimal place and exponent. Which means, if you have more digits than what width specified, it will shoot out of the width.

    Remember, width will be taken account as the last step, which means it needs to first satisfy the precision field.

    Let's go back to your case. You specified %10.9g, that means you want a total digit of 9, excluding the leading 0, and a min width of 10 including decimal place and exponent, and the precision should take priority.

    0.0606060606060606: take 9 digits without leading 0 will give you 0.0606060606, since it's already 12 width, it passes the min width of 10;

    0.3333333333333333: take 9 digits without leading 0 will give you 0.333333333, since it's already 11 width, it passes the min width of 10;

    0.05: take 9 digits without leading 0 will give you 0.05, since it's less than width 10, it will pad with another 6 width to get width of 10;

    0.4: same as above;

    0.1818181818181818: take 9 digits without leading 0 will give you 0.181818182 with rounding, since it's already 11 width, it passes the min width of 10.

    So this explains why you got the funny printing.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥35 MIMO天线稀疏阵列排布问题
  • ¥60 用visual studio编写程序,利用间接平差求解水准网
  • ¥15 Llama如何调用shell或者Python
  • ¥20 谁能帮我挨个解读这个php语言编的代码什么意思?
  • ¥15 win10权限管理,限制普通用户使用删除功能
  • ¥15 minnio内存占用过大,内存没被回收(Windows环境)
  • ¥65 抖音咸鱼付款链接转码支付宝
  • ¥15 ubuntu22.04上安装ursim-3.15.8.106339遇到的问题
  • ¥15 blast算法(相关搜索:数据库)
  • ¥15 请问有人会紧聚焦相关的matlab知识嘛?