Basically, you have 2 output formats: either scientific notation or the usual form. The pivot point between the two formats is 1e12 .
So, you can branch out if x >= 1e12 . In both branches you can do formatting with 0-digit digits to find out how long the number will be, so you can calculate how many digits of the digits will correspond to a width of 12, and therefore you can build the final format string using the calculated accuracy.
A preliminary check is also required in scientific notation ( %g ), since the width of the exponent can vary (for example, e+1 , e+10 , e+100 ).
Here is an example implementation. This is necessary for you to start, but this does not mean that you need to handle all cases, and this is not the most effective solution (but relatively simple and does the job):
// format12 formats x to be 12 chars long. func format12(x float64) string { if x >= 1e12 { // Check to see how many fraction digits fit in: s := fmt.Sprintf("%.g", x) format := fmt.Sprintf("%%12.%dg", 12-len(s)) return fmt.Sprintf(format, x) } // Check to see how many fraction digits fit in: s := fmt.Sprintf("%.0f", x) if len(s) == 12 { return s } format := fmt.Sprintf("%%%d.%df", len(s), 12-len(s)-1) return fmt.Sprintf(format, x) }
Testing:
fs := []float64{0, 1234.567890123, 0.1234567890123, 123456789012.0, 1234567890123.0, 9.405090880450127e+9, 9.405090880450127e+19, 9.405090880450127e+119} for _, f := range fs { fmt.Println(format12(f)) }
Conclusion (try on the Go Playground ):
0.0000000000 0.1234567890 1234.5678901 123456789012 1.234568e+12 9405090880.5 9.405091e+19 9.40509e+119