maekawatoshiki
1/29/2015 - 11:12 AM

## Light_RPN_calc

Light_RPN_calc

``````#define _CALC_Calculator_B
#ifdef _CALC_Calculator_B

// C++ Libaries
#include <iostream>
#include <string>
#include <stack>
#include <vector>
#include <sstream>
#include <iomanip>
// C Libaries
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;

/*
Calculator 計算クラス

Calculator::str に代入された中間記法形式の計算式を計算します。

Calculator class

This class will calculate the formula of intermediate
notation format that has been assigned to Calculator::str.

Licence: GPL
Copyright (C) 2015 MAEKAWA TOSHIKI.
*/
class Calculator
{
private:
vector<string> array;
vector<string> ans;
public:
char *str;
string Strexpr;
double answer;

int expression();
int fac();
int term();
int toRpn();
double calc();
char *setp(double, char *);
double operator()();
string replaceFunc(string);
Calculator();
~Calculator();
};

Calculator::Calculator()
{
str = new char[0xFFFF]();
}

Calculator::~Calculator()
{
delete[] str;
}

int Calculator::fac()
{
if (array.back() == "(")
{
if (array.size() >= 2) array.pop_back();
expression();
if (array.back() == ")")
if (array.size() >= 2)
array.pop_back();
}
else {
ans.push_back(array.back());
if (array.size() >= 2)
array.pop_back();
}
return 0;
}

int Calculator::term()
{
fac();
while (1)
{
string c = array.back();
if (c == "*" || c == "/" && array.size() >= 1)
{
array.pop_back();
fac();
ans.push_back(c);
}
else
break;
}
return 0;
}

int Calculator::expression()
{
term();
while (1)
{
string c = array.back();
if ((c == "+" || c == "-") && array.size())
{
array.pop_back();
term();
ans.push_back(c);
}
else
break;
}
return 0;
}

/*
int Calculator :: toRpn()

Calculator::Strexpr の計算式をトークンわけして、Vector に代入します。
そして、逆ポーランド法形式に変換します。
*/
int Calculator::toRpn()
{
string olds = "";
bool nm = false;
vector<string> siki2;

for (int i = 0; i < Strexpr.length(); i++)
{
switch (Strexpr[i])
{
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':
if (nm == true)
{
siki2.push_back(olds);
olds = "";
nm = false;
}
olds = Strexpr[i];
siki2.push_back(olds);
olds = "";
break;
default:
olds += Strexpr[i];
nm = true;
}
}
if (nm == true) siki2.push_back(olds);

// vector の順番を反対にします。
for (int i = 0; siki2.empty() != true; i++)
{
array.push_back(siki2.back());
siki2.pop_back();
}
expression();

return 0;
}

/*
int Calculator :: calc()

Calculator::toRpn() で得られた逆ポーランド法を計算して、
浮動小数点(double)で返します。
*/
double Calculator::calc()
{
double num = 0, num2 = 0;
int i = 0, pos = 0;
stack<double> arr;
string s; char c;

Strexpr = str;
Strexpr = replaceFunc(Strexpr);
toRpn();
while (i < ans.size())
{
switch (ans[i][0])
{
case '+':
num = arr.top(); arr.pop();
num2 = arr.top(); arr.pop();
arr.push(num2 + num);
break;
case '-':
num = arr.top(); arr.pop();
num2 = arr.top(); arr.pop();
arr.push(num2 - num);
break;
case '*':
num = arr.top(); arr.pop();
num2 = arr.top(); arr.pop();
arr.push(num2 * num);
break;
case '/':
num = arr.top(); arr.pop();
num2 = arr.top(); arr.pop();
arr.push(num2 / num);
break;
default:
arr.push(atof(ans[i].c_str()));
}
i++; pos++;
}
return answer = arr.top();
}

string Calculator::replaceFunc(string str)
{
int pos = 0, i = 0;
double fnum = 0;
string num;
char Sin[64] = { 0 };

while(1)
{
num.clear();
memset(Sin, 0, sizeof(Sin));

pos = str.find("e", pos);
if(pos == string::npos)
break;
str.replace(pos, pos+1, "2.71828182845904523536028747135266249");
}
pos = 0;
while(1)
{
num.clear();
memset(Sin, 0, sizeof(Sin));

pos = str.find("pi", pos);
if(pos == string::npos)
break;
str.replace(pos, pos+2, "3.1415926535897932384626433832795028");
}
pos = 0;
while(1)
{
num.clear();
memset(Sin, 0, sizeof(Sin));

pos = str.find("sin", pos);
if(pos == string::npos)
break;
for(pos += 3, i = pos;
str[i] != '+' && str[i] != '-' &&
str[i] != '*' && str[i] != '/' &&
str[i] != '\0'; i++)
num.push_back(str[i]);
fnum = atof(num.c_str());
fnum = sin(fnum);
sprintf(Sin, "(0%.8lf)", fnum);
str.replace(pos-3, pos-1+num.length()+1, Sin);
}
pos = 0;
while(1)
{
num.clear();
memset(Sin, 0, sizeof(Sin));

pos = str.find("sqrt", pos);
if(pos == string::npos)
break;
for(pos += 4, i = pos;
str[i] != '+' && str[i] != '-' &&
str[i] != '*' && str[i] != '/' &&
str[i] != '\0'; i++)
num.push_back(str[i]);
fnum = atof(num.c_str());
fnum = sqrt(fnum);
sprintf(Sin, "(0%.8lf)", fnum);
str.replace(pos-4, pos-1+num.length()+1, Sin);
}
pos = 0;
while(1)
{
num.clear();
memset(Sin, 0, sizeof(Sin));

pos = str.find("cos", pos);
if(pos == string::npos)
break;
for(pos += 3, i = pos;
str[i] != '+' && str[i] != '-' &&
str[i] != '*' && str[i] != '/' &&
str[i] != '\0'; i++)
num.push_back(str[i]);
fnum = atof(num.c_str());
fnum = cos(fnum);
sprintf(Sin, "(0%.8lf)", fnum);
str.replace(pos-3, pos-1+num.length()+1, Sin);
}

// s i n 1 0 0
// 0 1 2 3 4 5
return str;
}

/*
char *Calculator :: setp(double d, char *out)

d を小数点以下15桁に丸めて、out に代入します。
返却値は、out のポインタです。

#Sample:
d = 12.12345678901234567890
out = "12.123456789012345"
*/
inline char *Calculator::setp(double d, char *out)
{
stringstream ss;
ss << setprecision(15) << d;
strcpy(out, ss.str().c_str());
return out;
}

#endif

int main()
{
Calculator calc;
while(1)
{
cin.getline(calc.str, 1000);
cout << setprecision(20) << calc.calc() << endl;
}
}``````