Last active
August 29, 2015 14:14
-
-
Save maekawatoshiki/4fe66444b03383c3ff1d to your computer and use it in GitHub Desktop.
Light_RPN_calc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment