5

I'm having a hard time aligning decimal values. I am pretty sure its a combination of right alignment and setprecision/fixed but it doesn't seem to be working. I know other questions have been asked on the topic but I haven't found a clear solution to getting a bunch of columns (unique cout statements to align).

This is a chunk of my code:

double total_collect, sales, country_tax, state_tax, total_tax;
const double STATE_TAX_RATE = 0.04, COUNTRY_TAX_RATE = 0.02; 

// Compute taxes
total_collect = 100;
sales = 100 / 1.06 ;
country_tax = sales * COUNTRY_TAX_RATE;
state_tax = sales * STATE_TAX_RATE;
total_tax = country_tax + state_tax;

//Display

cout << setiosflags(std::ios::right) ;

cout << "Totla Collected: " << setw(7) << "$ " << fixed << setprecision(2) << right << total_collect << endl;
cout << "Sales: " << setw(17) << "$ "  << fixed << setprecision(2) << right << sales  << endl;
cout << "Country Sales Tax: " << setw(5) << "$ " << fixed << setprecision(2) << right << country_tax  << endl;
cout << "State Sales Tax: " << setw(7) << "$ "  << fixed << setprecision(2) << right << state_tax << endl;
cout << "Total Sales Tax: " << setw(7) << "$ " << fixed << setprecision(2) << left  << total_tax << endl << endl; 

This is what it looks like:
enter image description here

This is what I would like it too like:
enter image description here

YelizavetaYR
  • 1,611
  • 6
  • 21
  • 37

1 Answers1

2

You're setting the width on the "$", which aligns them nicely. But you also need to set it for the values themselves. I added a setw(8) before each fixed and that aligned them nicely, except for the last one which has a left instead of a right. You might want a different width value, but it should be the same for each line.

The ideal solution would be to use std::put_money (I see by your comment that you can't, but perhaps this will help someone else reading this answer). I've increased the dollar amounts to illustrate the thousands separator and fixed a bug or two:

#include <locale>
#include <iostream>
#include <iomanip>

int main()
{
    double total_collect, sales, country_tax, state_tax, total_tax;
    const double STATE_TAX_RATE = 0.04, COUNTRY_TAX_RATE = 0.02;
    const auto TAX_WIDTH = 10;
    const auto LABEL_WIDTH = 19;

    // Compute taxes
    total_collect = 10000;
    sales = total_collect / 1.06 ;
    country_tax = sales * COUNTRY_TAX_RATE;
    state_tax = sales * STATE_TAX_RATE;
    total_tax = country_tax + state_tax;

    //Display
    std::cout.imbue(std::locale("en_US.utf8"));
    std::cout << std::setw(LABEL_WIDTH) << std::left << "Total Collected: "
        << std::setw(TAX_WIDTH) << std::right << std::showbase
        << std::put_money(total_collect * 100.0) << std::endl;
    std::cout << std::setw(LABEL_WIDTH) << std::left << "Sales: "
        << std::setw(TAX_WIDTH) << std::right << std::showbase
        << std::put_money(sales * 100.0) << std::endl;
    std::cout << std::setw(LABEL_WIDTH) << std::left << "Country Sales Tax: "
        << std::setw(TAX_WIDTH) << std::right << std::showbase
        << std::put_money(country_tax * 100.0) << std::endl;
    std::cout << std::setw(LABEL_WIDTH) << std::left << "State Sales Tax: "
        << std::setw(TAX_WIDTH) << std::right << std::showbase
        << std::put_money(state_tax * 100.0) << std::endl;
    std::cout << std::setw(LABEL_WIDTH) << std::left << "Total Sales Tax: "
        << std::setw(TAX_WIDTH) << std::right << std::showbase
        << std::put_money(total_tax * 100.0) << std::endl << std::endl;
}

I get this output:

Total Collected:   $10,000.00
Sales:              $9,433.96
Country Sales Tax:    $188.68
State Sales Tax:      $377.36
Total Sales Tax:      $566.04
Fred Larson
  • 60,987
  • 18
  • 112
  • 174
  • I tried your suggestion and it worked. But I'm not sure whats happening. I would really like there to be no spaces between the $$ and dollar amount. With your solution it works well unless i move the dollar sign to right before the variable and then it is all messed up. – YelizavetaYR Sep 19 '14 at 14:33
  • @YelizavetaYR: I think you should try [`std::put_money`](http://en.cppreference.com/w/cpp/io/manip/put_money). I'm working on an example. – Fred Larson Sep 19 '14 at 14:41
  • Thank you - yes I am aware of that one but was told to figure this dilemma out without using put_money. The dilemma is how to align the decimals what combination of things to use to have the string/and variable line up with the decimal amounts. – YelizavetaYR Sep 19 '14 at 14:44
  • 1
    The trick there is you have to get the '$' on the stringified dollar amount before you align it. To do that, I think you'll need to use `std::stringstream`. – Fred Larson Sep 19 '14 at 14:45
  • Thank you - so there is no clean way to say align these variables (right justified with the decimals) and then align the string preceding it to the variable itself? – YelizavetaYR Sep 19 '14 at 14:48
  • I don't know of a way to do it that is cleaner than what I have suggested. – Fred Larson Sep 19 '14 at 15:21
  • put_money only works in c++ 11, and also (when using the following code) **cout << `Totla Collected: " << setw(5) << fixed << setprecision(2) << setw(8) << std::put_money(total_collect) << endl;` the output only shows 100 (no decimals or no dollar signs) – YelizavetaYR Sep 19 '14 at 15:22
  • Yes, this requires C++11. With the US locale, it takes the value as a number of cents, not dollars. That's why I multiply by 100.0 in my example. And you need `std::showbase` to display the currency symbol. – Fred Larson Sep 19 '14 at 15:27
  • You can also use `int(val)` and `int(round(val*x))%x` to find the components left and right of the decimal, where x in the above examples would be 100. (Negative values take slightly more work, and the format of the LHS and decimal point itself should still be done through the locale.) IMHO this is not as elegant, but it's capable of producing the same output as the currency formatting without restriction to values that can be represented in the locale's currency. – John P Oct 21 '17 at 20:29