Implementing cmath functions in RPN calculator

I am trying to implement some scientific functions into this rpn calculator(meant to be a hp-35 sim) but i'm having trouble being able to use pi in calculations or how to implement log, sin or pow into the code. It currently works with basic algebra.


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cmath>
#include "HPStack.h"
#include <cstdlib>
#include <cctype>

const double PI = 3.1415926535897;

using namespace std;

void convertToUpper(string &s);

int main()
{
	HPStack stack;
	string line;
	while (getline(cin, line)) {
		convertToUpper(line);
		stringstream expression(line);
		string token;
		while (expression >> token) {
			if (isdigit(token[0])) {
				stack.push(atof(token.data()));
			}
			else if (token == "+") {
				double x = stack.pop();
				double y = stack.pop();
				stack.push(y + x);
			}
			else if (token == "-") {
				double x = stack.pop();
				double y = stack.pop();
				stack.push(y - x);
			}
			else if (token == "*") {
				double x = stack.pop();
				double y = stack.pop();
				stack.push(y * x);
			}
			else if (token == "/") {
				double x = stack.pop();
				double y = stack.pop();
				stack.push(y / x);
			}
		}
		cout << stack.peek();
	}
	return 0;
}

void convertToUpper(string &s) {
	for (int i = 0; i < s.length(); i++) {
		s[i] = toupper(s[i]);
	}
}



HPStack.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cmath>
#include "HPStack.h"

using namespace std;

void HPStack::push(double num) {
	t = z;
	z = y;
	y = x;
	x = num;
}

double HPStack::peek() {
	return x;
}

double HPStack::pop() {
	double dispNum;
	dispNum = x;
	x = y;
	y = z;
	z = t;
	return dispNum;
}




my stack header filer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef HPSTACK_H
#define HPSTACK_H

class HPStack {

public:
	double pop();
	double peek();
	void push(double num);


private:
	double x, y, z, t;
};

#endif /*HPSTACK_H*/ 



Any help will be greatly appreciated.
if I enter cin pi 2 *, I'm getting 3.5762e-307 which isn't right
I don't see any code in your main() to handle pi.

Here's something I tried:
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cmath>
#include "HPStack.h"
#include <cstdlib>
#include <cctype>

const double PI = 3.1415926535897;

using namespace std;

void convertToUpper(string &s);
bool getNumber(string s, double & n);

int main()
{   
    HPStack stack;
    string line;
    
    while (getline(cin, line)) {
        convertToUpper(line);
        stringstream expression(line);
        string token;
        double num;
        
        while (expression >> token) {            
            if (getNumber(token, num)) {
                stack.push(num);
            }
            else if (token == "PI")
            {
                stack.push(PI); 
            }
            else if (token == "+") {
                double x = stack.pop();
                double y = stack.pop();
                stack.push(y + x);
            }
            else if (token == "-") {
                double x = stack.pop();
                double y = stack.pop();
                stack.push(y - x);
            }
            else if (token == "*") {
                double x = stack.pop();
                double y = stack.pop();
                stack.push(y * x);
            }
            else if (token == "/") {
                double x = stack.pop();
                double y = stack.pop();
                stack.push(y / x);
            }
            else {
                cout << "Unrecognised token: " << token << '\n';
            }
        }
        cout << stack.peek() << ' ';
    }
    
    return 0;
}

void convertToUpper(string &s) {
    for (size_t i = 0; i < s.length(); i++) {
        s[i] = toupper(s[i]);
    }
}

bool getNumber(string s, double & n)
{
    istringstream ss(s);
    if (ss >> n)
        return true;
    return false;        
}

It handles negative numbers and at least tries to give a message if the input is unrecognised.

Sample run:
-6 -3 /
2 pi *
6.28319 pi /
2 z
Unrecognised token: Z
2

Thanks worked perfectly. Also made it much simpler to implement other functions such as sin(), cos() etc. Appreciate the help
One suggestion. It would probably be a good idea to add a constructor to initialise the variables in your stack class.
In the header:
1
2
3
4
5
6
7
8
9
10
11
12
13
class HPStack {

public:
    HPStack();
    ~HPStack();
    
    double pop();
    double peek();
    void push(double num);

private:
    double x, y, z, t;
};


In HPStack.cpp
1
2
3
4
5
6
HPStack::HPStack() : x(0.0), y(0.0), z(0.0), t(0.0)
{ }


HPStack::~HPStack()
{ }

The constructor sets all the variables to zero, it stops the strange numbers appearing, you should see zero instead. The destructor doesn't need to do anything. But I put it there in case it might be needed later.

Oh yeah that's a good idea. This is actually my first class. What does the virtual constructor do?
It isn't virtual. Are you unfamiliar with this syntax?
1
2
HPStack::HPStack() : x(0.0), y(0.0), z(0.0), t(0.0)
{ }


it achieves the same outcome as
1
2
3
4
5
6
7
HPStack::HPStack() 
{ 
    x = 0.0;
    y = 0.0; 
    z = 0.0;
    t = 0.0;
}

but the first form is preferred.

Try googling for "c++ constructor initialization list".
Nah not the initialization bit just the constructor with ~. I'll google it, thanks for the help
The tilde ~ indicates the destructor. It is called when an object is destroyed at the end of its lifetime.
https://www.tutorialspoint.com/cplusplus/cpp_constructor_destructor.htm
Thanks makes more sense now after reading through the page.
do you want to write your own pow/sin/log? Or work them into your code using the defaults?

sin is just a series.
not sure how to do fractional pow off the top of my head
logs have tons of tricks; not sure best way here but you can use a log table / interpolate same as engineers used to do with a slide rule. If you have one log, you have them all via change of base trick.

fractional powers give roots, so once that works you have sqrt etc too.

you may want a integer power routine as well.
Last edited on
I wanted to work them into my code from the cmath library. I've been able to do that succesfully but currently I'm trying to implement a way of string the value in stack x into memory and being able to recall it. Not sure if I should use pointers

This is what I have at the moment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
else if (token == "STO") {
		double x = stack.peek();
		double y = stack.peek();
		double z = stack.peek();
		double t = stack.peek();
		t = x;
	}
else if (token == "RCL") {
		double x = stack.peek();
		double y = stack.peek();
		double z = stack.peek();
		double t = stack.peek();
		x = t;
	}
For that very reason I tend to make my stacks (and most other data structures) have a 'back door' for iteration. That is, any stack I have would double as an array, so I could just look at everything on it in a loop. One way to do that is just to use a vector ... it has the push-back which everyone knows, but it also has the somewhat under-used pop-back ... making the standard vector a simple stack. Then you don't need a peek (peek is just stack[stack.size()-1]) and you can look at any of the entries directly...

so you would not need a pointer this way, you can copy out of the stack to local variables on demand, and reverse-iterate on demand, etc.

depending on how you implemented your hpstack adding that functionality may be easy or difficult. If difficult, consider just swapping to a vector. If you need more advanced stack stuffs, there is std::stack, though I have not needed it and am unsure of what major differences there are between it and a vector as a stack.

Last edited on
It's a long time since I did any serious stuff with RPN, but I was just playing around with ideas, based on Pythagoran triples, something like this:
3 3 * 4 4 * 12 12 * 84 84 * 77 77 * - + + + + SQRT SQRT
or line-by-line
1
2
3
4
5
6
7
8
9
10
11
12
3 3 *
4 4 *
12 12 *
84 84 *
77 77 *
-
+
+
+
+
sqrt
sqrt 

should give the result: 6

It requires a stack depth of at least six , which is no problem with something like a vector, but malfunctions with the original design using separate variables.
Topic archived. No new replies allowed.