Calculator Program Using Functions
/********************************************************************** * A version of the calculator program making better use of functions. * Commands are: * <number> Enter <number> into the display. (Number mustn't start * with a + or -, but if it does you can use:) * =<number> Enter <number> into the display. * <op><number> Compute the operation: + - * / ^ * q[uit] Exit * * There is a "display," and after each command is executed, the display * is printed out. Operation commands operate on the display as left * operand and the input number as the right operand, and return the * result to the display. All operations are floating point. EOF on * input is treated as a quit. **********************************************************************/ #include <iostream> #include <string> #include <cctype> #include <cmath> using namespace std; /* * Print the value and prompt for a command. */ void prompt(double disp) { // Display the current value (which we know is zero). cout << " " << disp << endl << " >> "; } // This function tries to clear out after an error. It clears the // standard input stream, then reads and discards the (rest of) the // input line. void clear_input_error() { cin.clear(); string discard; getline(cin, discard); } /* * Read a command and a value. Return the command as normal, and the input * value through the parameter. Returns = if just the number was entered, or q * at end-of-file. */ string read_cmd(double &value) { // Read a command. If the read fails, we treat it as q (return // false). Note that the read skips leading white space, so the // comd is the first non-blank character. string command; cin >> command; if(cin.eof() || command[0] == 'q') return "q"; // Now, the command could actually be a number entered into // the display. Or it could just be a one-letter command, // and the number comes later. Or it could be a one-letter // command followed by a number. Let's find out. We'll // make command exactly the command, arg the number. if(command[0] == '.' || isdigit(command[0])) { // Seems to be a number. Convert it, and set the // command to = which assigns the argument to the // display. value = stod(command); return "="; } else if(command.length() > 1 && (command[1] == '.' || isdigit(command[1]))) { // Now, the character letter didn't look numberish, // but the second does. We think it's a one-letter // command followed by a number. We extract the // number part into value, and return the command part. value = stod(command.substr(1)); return command.substr(0,1); } else { // Well, maybe we just put the command, and the number comes // later. Keep the command, and read the number. If the // conversion fails, complain and try again. while(!(cin >> value)) { // Clear the input and try again. clear_input_error(); cout << "You need to enter a number. Try again." << endl << "> "; } } return command; } /* * Apply the given operation to the two numbers, and return the result, * The op is one of the command characters, =+-* /^. Notice the * dirty trick of returning from the cases, so I don't need break. * Don't count on this happening often, but it does occasionally. */ double apply_op(char op, double first, double second) { switch(op) { case '=': // Enter. return second; case '+': // Add. return first + second; case '-': // Subtract. return first - second; case '*': // Multiply. return first * second; case '/': // Divide. return first / second; case '^': // Raise to power. Pow() is std library function. return pow(first,second); } } int main() { double disp = 0.0; // Display value. // So, do you know why this is not inside the loop? // Loop until exited by a quit command. while(true) { string comd; // Input command. double arg; // Input money argument. // Prompt and read. Exit on quit. prompt(disp); comd = read_cmd(arg); if(comd[0] == 'q') break; // Obey the command. If the command is not legal (not // found in the list of legal ones), whine. Otherwise, // apply the operation to the display and argument. if(string("=+-*/^").find(comd[0]) == string::npos) { cout << "Bad command, " << comd << endl; clear_input_error(); } else { disp = apply_op(comd[0], disp, arg); } } }