Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to display multiple leading zeros for floating point values in C++? [duplicate]

In a C++ program, I want to display a column of floating point values so that the sign, digits, and decimal point all line up. Multiple leading zeros should pad the whole number part of each value, when necessary. For example:

A column of floating point values:
  +000.0012
  -000.0123
  +000.1235
  -001.2346
  +012.3457
  -123.4568

I had an elaborately commented test program that demonstrated the problem. But, as I was editing this post, I found the answer I need here:
- Extra leading zeros when printing float using printf?

The essential problem was that I was using a format code of "%+04.4f" when I should use "%+09.4f", because the total field width I want is 9:

  • 1 for the sign
  • 3 for the whole digits
  • 1 for the decimal point
  • 4 for the fractional digits

I do not have enough reputation points to comment on that post, so thank you from here, @AndiDog.

I still do not know how to get multiple leading zeros using just stream formatting flags. But that is a battle for another day. I will stick with a mixture of printf and stream for now.

like image 252
Mike Finch Avatar asked May 19 '15 15:05

Mike Finch


People also ask

How do you restrict a float to two places after the decimal point in C?

Using %. 2f in printf. It only print 2 decimal points.

What is leading zeros in C?

If the position of zero before bit is set to one, they are termed as leading zeros.

How do I print 2 digits after a decimal?

we now see that the format specifier "%. 2f" tells the printf method to print a floating point value (the double, x, in this case) with 2 decimal places. Similarly, had we used "%. 3f", x would have been printed rounded to 3 decimal places.


2 Answers

A couple of comments have mentioned std::setfill('0') and std::setw. While these are necessary, they're not sufficient to the task. For example, this code:

std::cout << std::setfill('0') << std::setw(7) << std::showpos << 0.012;

will produce: 0+0.012 as its output. This is obviously not quite what we wanted.

We need to add the std::internal flag to tell the stream to insert "internal padding" -- i.e., the padding should be inserted between the sign and the rest of the number, so code like this:

std::cout << std::setfill('0') << std::setw(7) << std::internal << std::showpos << 0.012;

...produces the output we want: +00.012.

Also note that the padding character is "sticky", so if you alternate between using std::setw with numeric and non-numeric types, you'll probably need/want to change it each time. Otherwise, something like std::cout << setw(12) << name; will produce results like: 0000000Jerry, which is rarely desired either.

To assure that we always get the same number of places after the decimal point, we also need to set the std::fixed flag, and specify the number of places with std::setprecision, such as:

#include <iostream>
#include <iomanip>
#include <vector>

int main() {
    std::vector<double> values { 0.1234, 1.234, 1.5555 };

    for (auto d : values)
        std::cout << std::internal << std::showpos << std::setw(9) 
                  << std::setprecision(3) << std::setfill('0') << d << "\n";
}

Which produces the output I believe is desired:

+0000.123
+0001.234
+0001.556

There is one circumstance under which you won't get aligned results this way though: if you have a number too large to fit into the field provided, all the places before the decimal point will still be printed. For example, if we added 1e10 to the list of numbers to be printed by the preceding code, it would be printed out as: +10000000000.000, which obviously won't align with the rest.

The obvious way to deal with that would be to just put up with it, and if it arises often enough to care about, increase the field size to accommodate the larger numbers.

Another possibility would be to use fixed notation only the number is below a certain threshold, and switch to (for example) scientific notation for larger numbers.

At least in my experience, code like this tends to be used primarily for financial data, in which case the latter option usually isn't acceptable though.

like image 128
Jerry Coffin Avatar answered Oct 05 '22 23:10

Jerry Coffin


To show the positive sign, you use std::showpos.

To show the leading zeros, you use std::setw(n) and std::setfill('0').

To show the digits after zero, you use std::setprecision(m).

To show the zeros between the + sign and the first digit, you use std::internal.

To keep the digit at a fixed position, you use std::fixed.

#include <iostream>     // std::cout, std::fixed
#include <iomanip>      // std::setprecision

int main () {
  double f =1.234;
  double g =-12.234;
  std::cout << std::showpos<< std::internal << std::fixed << std::setprecision(4)<<std::setw(9) <<std::setfill('0') << f << '\n';
  std::cout <<std::setw(9)<< std::setfill('0') <<g<<"\n"; //repeat these for a new number
  return 0;
  }


//output: 
//+001.2340
//-012.2340
like image 23
Vincent Ho Avatar answered Oct 05 '22 22:10

Vincent Ho