resolving blocks into functions

• 05-13-2009
Aisthesis
resolving blocks into functions
I apologize in advance for again submitting a lengthy block of code, but I feel somewhat obligated to present the solution that I came up with for the problem posed in the thread "keeping track of code blocks."

For those who didn't read that one but are willing to wade through a fairly long program, the problem is this: Repeatedly ask for employee number, gross wages, state taxes, fed. taxes, FICA (with various obvious validation rules), then use "0" for employee number as sentinel to end data entry and proceed to a printed report of the totals for all employees together. In Gaddis, 6th ed., it's chap. 5, programming challenge 15. And I added my own additional "challenge" of putting in confirmations at strategic points.

So, now that I've learned a little about functions, here's my new solution:
Code:

// payroll report using functions

#include <iostream>
#include <iomanip>
using namespace std;

int getEmployee();
bool confValue(char);
char getConf();
double getGross(int);
double getTax(int, int, double);
void showTaxTypeLower(int);
void showTaxTypeUpper(int);
char confData(int, double, double, double, double);

int main()
{
int Num;
double Gross, State, Fed, FICA, TotGross = 0, TotState = 0, TotFed = 0, TotFICA = 0;

do
{
Num = getEmployee();
if (Num != 0)
{
do
{
Gross = getGross(Num);
State = getTax(Num, 1, Gross);
Fed = getTax(Num, 2, Gross);
FICA = getTax(Num, 3, Gross);
if (State + Fed + FICA > Gross)
cout << "Total taxes cannot exceed gross pay.\n"
<< "Re-enter data for employee " << Num << ".\n";
}
while ((State + Fed + FICA > Gross) || !confValue(confData(Num, Gross, State, Fed, FICA)));
TotGross += Gross;
TotState += State;
TotFed += Fed;
TotFICA += FICA;
}
}
while (Num !=0);

cout << "\nPayroll Report\n\n"
<< setprecision(2) << fixed
<< "Gross pay total:  \$" << setw(12) << right << TotGross << endl
<< "State tax total:  \$" << setw(12) << TotState << endl
<< "Federal tax total: \$" << setw(12) << TotFed << endl
<< "FICA total:        \$" << setw(12) << TotFICA << endl << endl;

return 0;
}
// returns true if answer is Y or y
bool confValue(char X)
{
if ((X == 'Y') || (X == 'y'))
return 1;
else
return 0;
}
// asks for Y/N confirmation
char getConf()
{
char Conf;
cout << "Confirm (Y/N): ";
cin >> Conf;
return Conf;
}

// gets valid employee number
int getEmployee()
{
int Num;
do
{
cout << "Enter employee number or \"0\" to end list: ";
cin >> Num;

// validate
while (cin.fail() || Num < 0)
{
cin.clear();
cin.ignore(100, '\n');
cout << "Invalid input!\n"
<< "Enter employee number or \"0\" to end list: ";
cin >> Num;
}

// confirm
if (Num > 0)
cout << "You wish to enter data for employee " << Num << ".\n";
if (Num == 0)
cout << "You have finished entering employee data.\n";
}
while (!confValue(getConf()));

return Num;
}
// get gross pay
double getGross(int EmpNum)
{
double Gross;

cout << "Employee " << EmpNum << " gross pay: ";
cin >> Gross;

// validate
while (cin.fail() || Gross < 0)
{
cin.clear();
cin.ignore(100, '\n');
cout << "Invalid input!\n"
<< "Employee " << EmpNum << " gross pay: ";
cin >> Gross;
}

return Gross;
}

// converts integer into a tax type message; outputs lower case
void showTaxTypeLower(int Type)
{
switch (Type)
{
case 1:
cout << "state tax";
break;
case 2:
cout << "federal tax";
break;
default:
cout << "FICA";
}

}
// same as TaxTypeLower but in upper case
void showTaxTypeUpper(int Type)
{
switch (Type)
{
case 1:
cout << "State tax";
break;
case 2:
cout << "Federal tax";
break;
default:
cout << "FICA";
}
}

// get values for various taxes
double getTax(int EmpNum, int Type, double Gross)
{
double Tax;

cout << "Employee " << EmpNum << " ";
showTaxTypeLower(Type);
cout << ": ";
cin >> Tax;

// validate
while (cin.fail() || Tax < 0 || Tax > Gross)
{
cin.clear();
cin.ignore(100, '\n');
cout << "Invalid input!\n";
if (Tax < 0)
{
showTaxTypeUpper(Type);
cout << " cannot be negative.\n";
}
if (Tax > Gross)
{
showTaxTypeUpper(Type);
cout << " cannot exceed gross pay.\n";
}
cout << "Employee " << EmpNum << " ";
showTaxTypeLower(Type);
cout << ": ";
cin >> Tax;
}

return Tax;
}

// confirms data after entry
char confData(int Num, double Gross, double State, double Fed, double FICA)
{
cout << setprecision(2) << fixed
<< "Wages and taxes for employee " << Num << ":\n"
<< "  Gross wages: \$" << setw(10) << right << Gross << endl
<< "  State tax:  \$" << setw(10) << State << endl
<< "  Federal tax: \$" << setw(10) << Fed << endl
<< "  FICA:        \$" << setw(10) << FICA << endl;

return getConf();
}

Critique is much appreciated, but bear in mind that I'm working with a very limited vocabulary in the language at this point.
• 05-13-2009
Salem
Good job.
That looks a lot better than the previous version.
• 05-14-2009
Aisthesis
tx, I think the whole functions thing ended up cleaning up the logic of the program as well, because with the resolution into functions, I could finally see pretty easily where I was actually at in the various loops.
• 05-14-2009
brewbuck
Quote:

Originally Posted by Aisthesis
tx, I think the whole functions thing ended up cleaning up the logic of the program as well, because with the resolution into functions, I could finally see pretty easily where I was actually at in the various loops.

I think you did a great job as well. There is an additional simplification you can make to one of the loops, which removes another level of bracing.

Code:

do
{
Num = getEmployee();
if (Num != 0)
{
do
{
Gross = getGross(Num);
State = getTax(Num, 1, Gross);
Fed = getTax(Num, 2, Gross);
FICA = getTax(Num, 3, Gross);
if (State + Fed + FICA > Gross)
cout << "Total taxes cannot exceed gross pay.\n"
<< "Re-enter data for employee " << Num << ".\n";
}
while ((State + Fed + FICA > Gross) || !confValue(confData(Num, Gross, State, Fed, FICA)));
TotGross += Gross;
TotState += State;
TotFed += Fed;
TotFICA += FICA;
}
}
while (Num !=0);

Code:

for( Num = getEmployee(); Num != 0; Num = getEmployee() )
{
do
{
Gross = getGross(Num);
State = getTax(Num, 1, Gross);
Fed = getTax(Num, 2, Gross);
FICA = getTax(Num, 3, Gross);
if (State + Fed + FICA > Gross)
cout << "Total taxes cannot exceed gross pay.\n"
<< "Re-enter data for employee " << Num << ".\n";
}
while ((State + Fed + FICA > Gross) || !confValue(confData(Num, Gross, State, Fed, FICA)));
TotGross += Gross;
TotState += State;
TotFed += Fed;
TotFICA += FICA;
}

EDIT: Are you sure you haven't done this before? This is actually quite good.
• 05-14-2009
laserlight
I agree, it does look pretty good.

One possible stylistic improvement would be to include the parameter names in your function declarations. Although they are unnecessary for function prototypes, they can help to indicate what the parameters are for.

Another possible improvement, again a matter of style, would be to change this:
Code:

// returns true if answer is Y or y
bool confValue(char X)
{
if ((X == 'Y') || (X == 'y'))
return 1;
else
return 0;
}

to:
Code:

// returns true if answer is Y or y
bool confValue(char Value)
{
return (Value == 'Y') || (Value == 'y');
}

Personally, I feel that the relative precedence of == and || are generally well known and hence the parentheses should be left out to remove noise, but if you feel that the parentheses should be present as they remove all possible ambiguity, that is fine.