-2

I would like to print a slice of float64 values line by line having all decimal points at the same position in each line. I could print the integer part right justified, the decimal point and then the fractional part left justified. I assume, there is a better way, but I could not find it so far. Any proposals?

2
  • Please post an example value and an example desired output to demo your goal. Commented Apr 4 at 0:59
  • 1
    Try a variation of "%9.3f". Commented Apr 4 at 4:32

2 Answers 2

1

We have two cases here: either we want to keep the original precision of the float (which imho does not make sense, more on that later), or we have a fixed precision.

Printf in general

You can do a fmt.Printf("%<width>.<precision>f\n",someFloat), where <width> would denote the overall length of the printed result and precision the number of decimal places, right-padded with 0 if there are less decimal places in someFloat.

Original precision

What you want to do is to calculate the length of the longest decimal digit in your slice and calculate <width> accordingly, since the decimal places really do not matter much once the decimal point is aligned. We only have to ensure that we are aware of the number of decimal places in order to not have them padded.

That would look something like this:

package main import ( "fmt" "strings" ) func printJustifyFloats(floats []float64) { indent := 0 // Find the longest decimal digit. // We need to do this beforehand, as the longest decimal dictates // our padding, since in "%n.mf" the n would be all the places, including // the decimal point. for _, f := range floats { if l := len(strings.Split(fmt.Sprintf("%f", f), ".")[0]); l > indent { indent = l } } for _, p := range floats { // In order to prevent unnecessary trailing 0, we calculate the precision actually needed. precision := len(strings.TrimRight(strings.Split(fmt.Sprintf("%f", p), ".")[1], "0")) if precision == 0 { // We need to do this, otherwise a float with only a 0 in decimal places would // only have its decimal digit printed precision = 1 } // Here is where the magic happens: // We plainly use the calculated length of the decimal digit plus the precision // specific to the current p and add 2 (one for the decimal point, one for the leading space), // and print the current p according to the resulting format string. fmt.Printf("% *.*f\n", indent+precision+2, precision, p) } } func main() { printJustifyFloats([]float64{1.0, 11.9, 111.001, 1111.01}) } 

Result:

 1.0 11.9 111.001 1111.01 

Run on playground

Fixed precision

That being said: The above approach does not make much sense, imho. I cannot think of a use case where 0-padding to the right would be harmful and where the order of magnitude of the maximum results are unknown. With fixed width and precision, floats are automatically printed right justified:

package main import "fmt" var floats = []float64{ 1.0, 11.9, 111.001, 1111.01, } func main() { for _, f := range floats { fmt.Printf("%9.3f\n", f) } } 

Result:

 1.000 11.900 111.001 1111.010 

Run on playground

Sign up to request clarification or add additional context in comments.

Comments

0
 f := []float64{ 1.0, 11.9, 111.001, 1111.01, } // To determine how much we want to ident. stringIdent := 0 for i := range f { r := int64(math.Floor(f[i])) integerPart := fmt.Sprintf("%d", r) if stringIdent < len(integerPart) { stringIdent = len(integerPart) } } format := "%d: %" + fmt.Sprintf("%d", stringIdent) + "d.%s\n" for i := range f { d := int64(f[i]) r := f[i] - math.Floor(f[i]) reminderCleaned := fmt.Sprintf("%f", r) reminderCleaned = strings.TrimRight(reminderCleaned[2:], "0") if len(reminderCleaned) == 0 { reminderCleaned = "0" } fmt.Printf(format, i, d, reminderCleaned) } 

Technically fmt.SprintF("%5s","abc") would result in abc (space space "abc").

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.