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;
	}
}