Fmt.Printf behaves unexpectedly with width and precision fields in% g

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

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

 0.06060606 0.33333333 0.05 0.4 0.18181818 

But I do not understand how this is done. The documentation says that

For floating point values, the width sets the minimum field width and the precision sets the number of places after the decimal fraction, if, respectively, except for% g /% G it sets the total number of digits. For example, given 123.45, the% 6.2f format prints 123.45, and the% .4g prints 123.5. The default precision for% e and% f is 6; for% g, this is the smallest number of digits needed to identify the value uniquely.

So, if I use %f , a larger number will not fit into the 10-character limit, so %g is required. To get a minimum width of 10 %10g and to get a maximum of 9 digits (+1 for a point) this is %.9g , but combining them in %10.9g does not behave as I expect

 0.0606060606 0.333333333 0.05 0.4 0.181818182 

Why do I get strings of 10 runes, others 11 runes, and others 12 runes?

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

+5
source share
2 answers

First, we need to understand the documentation correctly:

width sets the minimum field width, and precision sets the number of places after the decimal number, if necessary, except that for% g /% G it sets the total number of digits.

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

Therefore, consider a few examples:

 123.45 12312.2 1.6069 0.6069 0.0006069 

and you print it as 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 will happen to the last 2 example? Are you kidding me by no more than 5 digits?

This is a confusing part in print: leading 0s will not be considered digits, and will not be reduced if less than 4 zeros remain .

Look at behavior 0 using the example below:

 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) } 

and conclusion:

 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 

Thus, you could see that when the number is less than 4 leading 0, they will be counted and reduced if there are more.

Well, the next thing is width . From the documentation, width indicates only the minimum width,, including decimal place and exponent . This means that if you have more digits than the specified width , it will shoot from the width.

Remember that the width will be taken into account as the last step, which means that it needs to first fulfill the accuracy field .

Let's get back to your business. You specified %10.9g , which means you want the total digit to be 9, excluding the leading 0 and the minimum width of 10 , including decimal place and exponent, and precision should take precedence.

0.0606060606060606 : take 9 digits without a leading 0, will give you 0.0606060606 , since it is already 12 wide, it skips a minimum width of 10;

0.3333333333333333 : take 9 digits without a leading 0, will give you 0.333333333 , since it is already 11 wide, it skips a minimum width of 10;

0.05 : take 9 digits without a leading 0, will give you 0.05 , since it will be less than 10 wide, it will fill 6 more with width to get 10 wide;

0.4 : the same as above;

0.1818181818181818 : take 9 digits without a leading 0, will give you 0.181818182 with rounding , since it is already 11 wide, it skips a minimum width of 10.

So this explains why you got a funny print.

+1
source

Yes, I agree: it prevails "precision fields" rather than "width." Therefore, when we need column corrections for printing, we need to write a new formatting function.

+1
source

Source: https://habr.com/ru/post/1246595/


All Articles