### Help with Factorial

I'm trying to do the following exercise from Programming: Principles and Practices Using C++ 2Ed.

Ch6 Ex3

Add a factorial operator: use a suffix '!' operator to represent "factorial". For example, the expression 7! means 7*6*5*4*3*2*1. Make ! bind tighter than * and /; that is 7*8! means 7*(8!) rather than (7*8)!. Begin by modifying the grammar to account for a higher-level operator. To agree with standard mathematical definition of factorial, let 0! evaluate to 1. Hint: The calculator functions deal with doubles, but factorial is defined only for ints, so just for x!, assign x to an int and calculate the factorial of that int.

Prior to this question I had to clean up some errors and add the use of { and } along with ( and ), so the following code reflects those changes.

This is done within Visual Studio 2017. Grammar outline is after code.

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214`` ``````// Chapter 6 // #include "stdafx.h" #include "std_lib_facilities.h" class token // Creating a new class called token { // The token is a character/value pair public: char kind; double value; token(char ch) :kind(ch), value(0) {} token(char ch, double val) :kind(ch), value(val) {} }; class token_stream // Creating a new class called token_stream { // This is where token info can be pulled from public: // and put back as needed token_stream(); token get(); void putback(token t); private: bool full; token buffer; }; token_stream::token_stream() // token_stream function is a member of :full(false), buffer(0) {} // token_stream class void token_stream::putback(token t) // putback() function is a member of { // token_stream if (full) error("Can't put back into a full buffer"); buffer = t; full = true; } token token_stream::get() // get() function is a member of token_stream { // and returns a token if (full) { full = false; return buffer; } char ch; cin >> ch; switch (ch) { case '=': case 'x': case '{': case '}': case '(': case ')': case '+': case '-': case '*': case '/': case '!': return token(ch); case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { cin.putback(ch); double val; cin >> val; return token('8', val); } default: error("Bad token"); } } token_stream ts; // Declare a new token_stream named ts double expression(); // Declare a new function named expression() double primary() // Function deals with brackets or { // Swaps the character out for it's value token t = ts.get(); switch (t.kind) { case '{': { double d = expression(); t = ts.get(); if (t.kind != '}') error("'}' expected"); return d; } case '(': { double d = expression(); t = ts.get(); if (t.kind != ')') error("')' expected"); return d; } case '8': return t.value; default: error("Primary expected"); } } double factorial() // Factorial function that's not working { double left = primary(); token t = ts.get(); while (true) { switch (t.kind) { case '!': { int x = left; if (x == 0) { left = 1; } else if (x < 0) error("Factorial must be a positive integer"); else for (; x > 0; x--) { x *= x; left = x; } t = ts.get(); break; } default: ts.putback(t); return left; } } } double term() // Function deals with multiplication and division { double left = factorial(); token t = ts.get(); while (true) { switch (t.kind) { case '*': left *= factorial(); t = ts.get(); break; case '/': { double d = factorial(); if (d == 0) error("Can't divide by 0"); left /= d; t = ts.get(); break; } default: ts.putback(t); return left; } } } double expression() // Function deals with addition and subtraction { double left = term(); token t = ts.get(); while (true) { switch (t.kind) { case '+': left += term(); t = ts.get(); break; case '-': left -= term(); t = ts.get(); break; default: ts.putback(t); return left; } } } int main() try { double val = 0; cout << "Welcome to our simple calculator.\n" << "Please enter expressions using floating-point numbers.\n" << "Note: Only +, -, *, /, (, ), { and } can be used in the expressions.\n" << "Hint: Use = at the end of an expression to get the result and use x at any time to quit.\n" << "Example: {2+(2+3-1)}*2/1=\n" << '\n'; while (cin) { token t = ts.get(); if (t.kind == 'x') break; else if (t.kind == '=') cout << "= " << val << '\n'; else ts.putback(t); val = expression(); } keep_window_open(); return 0; } catch (exception& e) { cerr << "Error: " << e.what() << '\n'; keep_window_open(); return 1; } catch (...) { cerr << "Oops: Unknown Exception!\n"; keep_window_open(); return 2; }``````

The grammar is as follow;

Expression:
Term
Expression "+" Term
Expression "-" Term
Term:
Factorial
Term "*" Factorial
Term "/" Factorial
Factorial:
Primary
Integer "!"
Primary:
Number
"(" Expression ")"
Number:
Floating-point-literal

So the order in which the functions call upon each other is;

Main -> Expression -> Term -> Factorial -> Primary

I know that the factorial() function is mostly working. It will correctly call upon information from primary(). It will correctly give me 1 when I input 0!. It'll give me the error when I input a negative number (eg. -2!). It just doesn't work right with any positive integer other than 1. I tried some numbers and get the following;

-2! = Factorial must be a positive integer (works)
0! = 1 (works)
1! = 1 (works)
2! = -2.1478e+09 (problem)
4! = -1.77744e+09 (problem)
7! = -1.65649e+09 (problem)

I've been at it for hours and this is the closest I've got it to work. Any help would be greatly appreciated.

Thank You.
line 114, `x' is the number that you want to compute its factorial
`left' is the result.
 ``12345`` ``````for (; x > 0; x--) { x *= x; //¡¿?! left = x; }``````
get pencil and paper and do a desk test
edit: it seems to be called desk check. run the code manually, line by line and write the values that `x' takes.
suppose that at the start x=4

also, ¿why your functions don't recibe a parameter?
Last edited on
Thanks for the reply. I was out of town (and away from my computer) for the weekend so I basically thought it over and over. Manually tracking various inputs through the code line by line is basically how I narrowed the issue to the part you pointed out.

I got it to work by changing the code to the following.

 ``12345678910111213141516171819202122232425262728293031`` ``````double factorial() { double left = primary(); // I knew this worked by using equations with brackets token t = ts.get(); while (true) { switch (t.kind) { case '!': { int x = left; if (x == 0) { x = 1; } // I tested this and knew it worked else if (x < 0) // I tested this and knew it worked { error("Factorial must be a positive integer"); keep_window_open(); } else for (int y = x - 1; y > 0; --y) // So this is where the error was { x = x * y; } t = ts.get(); double left = x; ts.putback(t); return left; } default: ts.putback(t); return left; } } }``````

I needed to convert the double to an int such that an input of 3.4! would evaluate as 3!. So I used int x = left. I knew that I needed to increase the value of x by multiplying it by a decrementing value starting with x - 1 so I went with y = x - 1. Now each time around, as long as y > 0 remained true, a new value of x would come from the old value of x multiplied by the value of y which reduces by 1 each cycle. I then turn the int result into a double and return the double.

 why your functions don't describe a parameter

It's not required. Honestly I don't know. Functions were introduced in ch 4 and here's what it had to say on it.

The list of arguments required by the function is called a parameter list and its elements are called parameters (or formal arguments). The list of parameters can be empty, and if we don’t want to return a result we give void (meaning “nothing”) as the return type. For example:

 ``12345`` `````` void write_sorry() { cout << "Sorry\n"; }``````

The language-technical aspects of functions will be examined more closely in
Chapter 8.

Topic archived. No new replies allowed.