Native/C
계산기 (삼각함수 완료 bugfix)
aucd29
2013. 10. 2. 18:51
/***************************************************************************
*
* Date : 2005-05-03
* Copyright : aucd29
* E-mail : aucd29@daum.net
*
* 열라 짜증나게 만드는 계산기
*
***************************************************************************/
// 중위 -> 후위로 그리고 과정 보여주고 계산값 보여주고
// -10*----5 ok
// -10*-(-9.1--(--0.8--0.1)) ok
// -10*-(-9.1(--0.8--0.1)) ok
// -10*-cos(--sin(--45--45)/2-sin(30)) ok
// -10*-(-9.1--(--0.8--0.1)) ok
// -10*-(-9.1(--0.8--0.1)) ok
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
//
// defintion
//
#define MAX_STACK_SIZE 100
#define MAX_EXPR_SIZE 100
typedef enum{
lparen, rparen, plus, minus, times, divide, mod, eos, operand, blank, minus_val, _cos, _tan, _sin
}precedence;
//
// variant value
//
int stack[MAX_STACK_SIZE];
double dbl_stack[MAX_STACK_SIZE];
char expr[MAX_EXPR_SIZE];
char post_expr[MAX_EXPR_SIZE];
int post_i=0;
int rtnM;
static int isp[] = {0, 19, 12, 12, 13, 13, 13, 0, 0, 0, 0, 14, 14, 14};
static int icp[] = {20, 19, 12, 12, 13, 13, 13, 0, 0, 0, 0, 14, 14, 14};
//
// function
//
void add(int*, int);
char put_token(int n);
double eval(void);
int get_token(char *, int*, int*);
int get_token2(char* , int*);
void postfix(void);
void getline(char *);
void print_token(int);
int rmstack(int *);
double pop(int* top);
void SCTInput(int);
int is_tfunc(char*, int*);
double ConvertRadian(double);
int is_tfunc2(char*, int*);
void InsertPostFix(int token2);
void InsertMinus(void);
int main(int argc, char *argv[])
{
//
// 중위 표기식 입력 받고
//
getline(expr);
//
// 중위식을 후위식으로 바꾸고
//
postfix();
//
// 바뀐 표기식을 출력
//
printf("==== PostFix ===\n%s\n================\n",post_expr);
//
// 후위 표기식인걸 계산하자.
//
printf("%lf",eval());
printf("\n");
return 0;
}
//
// 배열에 주소에 내용을 입력 받는다.
//
void getline(char *s)
{
int c, i;
for(i=0;(c=getchar()) !='\n'; ++i)
if(c!=' ' && MAX_EXPR_SIZE>i) *s++ = c;
s = '\0';
}
//
// 중위 표기를 후위표기로 변환한다.
//
void postfix(void)
{
char symbol;
int token;
int token2=0;
int n = 0;
int top = 0; // insert eos
stack[0] = eos;
int x=0;
while((token = get_token(&symbol, &n, &top)) != eos)
{
// printf("### %d : token %d, N: %d ###\n", ++x, token, n);
if(token == operand)
{
post_expr[post_i++] = symbol;
while((token2 = get_token(&symbol, &n, &top)) == operand)
post_expr[post_i++] = symbol;
--n;
if(expr[n]=='(' && isdigit(expr[n-1])) add(&top,times); // 숫자뒤 가로 일 경우 곱하기를 하자.
post_expr[post_i++] = ' ';
}
else if(token == rparen)
{
token2 = rmstack(&top);
if(token2 != lparen) InsertPostFix(token2);
token2 = rmstack(&top);
if(token2 != lparen) InsertPostFix(token2);
}
else
{
// symbol 의 isp가 token의 icp보다 크거나 작으면 symbol을 제거하고 출력한다.
while(isp[stack[top]] >= icp[token])
{
token2 = rmstack(&top);
InsertPostFix(token2);
}
add(&top, token);
}
}
while((token = (precedence)rmstack(&top)) != eos)
if(token != lparen) InsertPostFix(token);
post_expr[--post_i] = '\0';
printf("\n");
}
void InsertPostFix(int token2)
{
if(token2 == _cos || token2 == _sin || token2 == _tan)
SCTInput(token2);
else
post_expr[post_i++] = put_token(token2);
post_expr[post_i++] = ' ';
}
void SCTInput(int token2)
{
if(token2 == _cos)
{
post_expr[post_i++] = 'c';
post_expr[post_i++] = 'o';
post_expr[post_i++] = 's';
}
else if(token2 == _sin)
{
post_expr[post_i++] = 's';
post_expr[post_i++] = 'i';
post_expr[post_i++] = 'n';
}
else if(token2 == _tan)
{
post_expr[post_i++] = 't';
post_expr[post_i++] = 'a';
post_expr[post_i++] = 'n';
}
}
int CountMark(int *n)
{
int i;
for(i=0;'-'==expr[(*n)++];++i);
return i;
}
void InsertMinus(void)
{
post_expr[post_i++] = '-';
post_expr[post_i++] = '1';
post_expr[post_i++] = ' ';
}
int get_token(char* symbol, int* n, int* top)
{
int tmpN=0;
int is_tFunc=0;
*symbol = expr[(*n)++];
switch(*symbol)
{
case '-':
if(*n==1) // 첫번째가 음수면 음수숫자이다.
{
if(isdigit(expr[*n]))
return operand;
else
{
tmpN = *n; // 카운트 세기 전의 N값
rtnM = CountMark(n); // 여기서 n이 증가한다.
if(rtnM % 2)
{
*symbol = expr[*n-1]; // -10*----5 일경우 5를 리턴
if(*symbol == '(')
return false;
else
return operand;
}
else
{
if(expr[*n-1] == '(')
{
InsertMinus();
add(top,times);
}
else
{
--*n;
return operand;
}
}
}
}
////////////////////////////////////////////
else if(expr[*n] == '-') // 음수가 연속으로 들어간경우 최소 2개
{
tmpN = *n; // 카운트 세기 전의 N값
rtnM = CountMark(n); // 여기서 n이 증가한다.
//printf(" === %d === ",rtnM);
//
// 홀수가 들어오면 양수로 바뀐다...
//
if(rtnM % 2)
{
// 앞부분이 숫자가 아닌경우
if(!isdigit(expr[tmpN-2]))
{
*symbol = expr[*n-1]; // -10*----5 일경우 5를 리턴
if(*symbol == 's' || *symbol == 'c' || *symbol == 't')
{
if((is_tFunc = is_tfunc(symbol, n)))
{
++*n;
return is_tFunc;
}
else
return false;
}
else if(*symbol == '(')
{
add(top,plus);
return false;
}
return operand;
}
else
{
add(top,plus); // +로 바뀐다...
//--*n;
// 리턴 값을 안먹는다 ㅡ.ㅡ;
// 원랜 return plus;였음...
return false;
}
}
else
{
if(isdigit(expr[tmpN-2])) // 연속된 음수 앞이 숫자가 아닌 경우
{
add(top,minus);
// 리턴 값을 안먹는다 ㅡ.ㅡ;
return false;
}
else
{
*symbol = expr[*n-1]; // -10*----5 일경우 5를 리턴
if(*symbol == 's' || *symbol == 'c' || *symbol == 't')
{
InsertMinus();
add(top,times);
--*n;
return false;
}
else
{
--*n;
return operand;
}
}
}
}
////////////////////////////////////////
else if(expr[*n]=='(')
{
InsertMinus();
add(top,times);
++*n;
return false;
}
/////////////////////////////////////////
else if((expr[*n]=='c' || expr[*n]=='t' || expr[*n]=='s') && !isdigit(expr[*n-2]))
{
InsertMinus();
add(top,times);
return false;
}
///////////////////////////////////////
else if(!isdigit(expr[*n-2])) // 음수 앞이 숫자가 아닌경우
{
return operand;
}
//////////////////////////////////////
else // 일반적인 빼기
{
return minus;
}
case '(': return lparen;
case ')': return rparen;
case '+': return plus;
case '/': return divide;
case '*': return times;
case '%': return mod;
case '\0': return eos;
default:
if((is_tFunc=is_tfunc(symbol, n)))
return is_tFunc;
else
return operand;
}
}
int is_tfunc(char* symbol, int* n)
{
if(*symbol == 's' && expr[*n] == 'i' && expr[*n+1] == 'n')
{
*n+=2;
return _sin;
}
else if(*symbol == 'c' && expr[*n] == 'o' && expr[*n+1] == 's')
{
*n+=2;
return _cos;
}
else if(*symbol == 't' && expr[*n] == 'a' && expr[*n+1] == 'n')
{
*n+=2;
return _tan;
}
return false;
}
int is_tfunc2(char* symbol, int* n)
{
if(*symbol == 's' && post_expr[*n] == 'i' && post_expr[*n+1] == 'n')
{
*n+=2;
return _sin;
}
else if(*symbol == 'c' && post_expr[*n] == 'o' && post_expr[*n+1] == 's')
{
*n+=2;
return _cos;
}
else if(*symbol == 't' && post_expr[*n] == 'a' && post_expr[*n+1] == 'n')
{
*n+=2;
return _tan;
}
return false;
}
int get_token2(char* symbol, int* n)
{
int is_tFunc = 0;
*symbol = post_expr[(*n)++];
if(*symbol == 'c' || *symbol == 's' || *symbol == 't')
if((is_tFunc=is_tfunc2(symbol, n)))
return is_tFunc;
switch(*symbol)
{
case '-':
if(*n==1)
return operand;
else if(isdigit(post_expr[*n]))
{
return minus_val;
}
else
{
return minus;
}
case '(': return lparen;
case ')': return rparen;
case '+': return plus;
case '/': return divide;
case '*': return times;
case '%': return mod;
case '\0': return eos;
case ' ': return blank;
default: return operand;
}
}
void print_token(int n)
{
printf("%c ",put_token(n));
}
char put_token(int n)
{
switch(n)
{
case minus: return '-';
case lparen: return '(';
case rparen: return ')';
case plus: return '+';
case divide: return '/';
case times: return '*';
case mod: return '%';
case eos: return '\0';
default: return '\0';
}
}
int rmstack(int* top)
{
return stack[(*top)--];
}
double pop(int* top)
{
return dbl_stack[(*top)--];
}
void add(int* top, int token)
{
stack[++*top] = token;
}
//
// overloading
//
void add(int* top, double token)
{
dbl_stack[++*top] = token;
}
double eval(void)
{
int token;
char symbol;
double op1, op2;
int n = 0;
int top = -1;
char szLine[100];
int cnt=0;
while((token = get_token2(&symbol, &n)) != eos)
{
if(token == blank) continue;
if(token == minus_val || token == operand)
{
szLine[cnt++] = symbol;
while((token = get_token2(&symbol, &n)) != blank)
szLine[cnt++] = symbol;
szLine[cnt] = '\0';
add(&top, atof(szLine));
cnt = 0;
}
else if(token == _sin || token == _cos || token == _tan)
{
op1 = ConvertRadian(pop(&top));
switch(token)
{
case _sin: add(&top, sin(op1)); break;
case _cos: add(&top, cos(op1)); break;
case _tan: add(&top, tan(op1)); break;
}
}
else
{
op2 = pop(&top); // delete stack
op1 = pop(&top);
switch(token)
{
case plus:
add(&top, op1+op2);
break;
case minus :
add(&top, op1 - op2);
break;
case times :
add(&top, op1 * op2);
break;
case divide:
add(&top, op1 / op2);
break;
case mod :
add(&top, (int)op1 % (int)op2);
break;
}
}
}
return pop(&top); // return result
}
double ConvertRadian(double d)
{
return (d*3.141592/180);
}
*
* Date : 2005-05-03
* Copyright : aucd29
* E-mail : aucd29@daum.net
*
* 열라 짜증나게 만드는 계산기
*
***************************************************************************/
// 중위 -> 후위로 그리고 과정 보여주고 계산값 보여주고
// -10*----5 ok
// -10*-(-9.1--(--0.8--0.1)) ok
// -10*-(-9.1(--0.8--0.1)) ok
// -10*-cos(--sin(--45--45)/2-sin(30)) ok
// -10*-(-9.1--(--0.8--0.1)) ok
// -10*-(-9.1(--0.8--0.1)) ok
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
//
// defintion
//
#define MAX_STACK_SIZE 100
#define MAX_EXPR_SIZE 100
typedef enum{
lparen, rparen, plus, minus, times, divide, mod, eos, operand, blank, minus_val, _cos, _tan, _sin
}precedence;
//
// variant value
//
int stack[MAX_STACK_SIZE];
double dbl_stack[MAX_STACK_SIZE];
char expr[MAX_EXPR_SIZE];
char post_expr[MAX_EXPR_SIZE];
int post_i=0;
int rtnM;
static int isp[] = {0, 19, 12, 12, 13, 13, 13, 0, 0, 0, 0, 14, 14, 14};
static int icp[] = {20, 19, 12, 12, 13, 13, 13, 0, 0, 0, 0, 14, 14, 14};
//
// function
//
void add(int*, int);
char put_token(int n);
double eval(void);
int get_token(char *, int*, int*);
int get_token2(char* , int*);
void postfix(void);
void getline(char *);
void print_token(int);
int rmstack(int *);
double pop(int* top);
void SCTInput(int);
int is_tfunc(char*, int*);
double ConvertRadian(double);
int is_tfunc2(char*, int*);
void InsertPostFix(int token2);
void InsertMinus(void);
int main(int argc, char *argv[])
{
//
// 중위 표기식 입력 받고
//
getline(expr);
//
// 중위식을 후위식으로 바꾸고
//
postfix();
//
// 바뀐 표기식을 출력
//
printf("==== PostFix ===\n%s\n================\n",post_expr);
//
// 후위 표기식인걸 계산하자.
//
printf("%lf",eval());
printf("\n");
return 0;
}
//
// 배열에 주소에 내용을 입력 받는다.
//
void getline(char *s)
{
int c, i;
for(i=0;(c=getchar()) !='\n'; ++i)
if(c!=' ' && MAX_EXPR_SIZE>i) *s++ = c;
s = '\0';
}
//
// 중위 표기를 후위표기로 변환한다.
//
void postfix(void)
{
char symbol;
int token;
int token2=0;
int n = 0;
int top = 0; // insert eos
stack[0] = eos;
int x=0;
while((token = get_token(&symbol, &n, &top)) != eos)
{
// printf("### %d : token %d, N: %d ###\n", ++x, token, n);
if(token == operand)
{
post_expr[post_i++] = symbol;
while((token2 = get_token(&symbol, &n, &top)) == operand)
post_expr[post_i++] = symbol;
--n;
if(expr[n]=='(' && isdigit(expr[n-1])) add(&top,times); // 숫자뒤 가로 일 경우 곱하기를 하자.
post_expr[post_i++] = ' ';
}
else if(token == rparen)
{
token2 = rmstack(&top);
if(token2 != lparen) InsertPostFix(token2);
token2 = rmstack(&top);
if(token2 != lparen) InsertPostFix(token2);
}
else
{
// symbol 의 isp가 token의 icp보다 크거나 작으면 symbol을 제거하고 출력한다.
while(isp[stack[top]] >= icp[token])
{
token2 = rmstack(&top);
InsertPostFix(token2);
}
add(&top, token);
}
}
while((token = (precedence)rmstack(&top)) != eos)
if(token != lparen) InsertPostFix(token);
post_expr[--post_i] = '\0';
printf("\n");
}
void InsertPostFix(int token2)
{
if(token2 == _cos || token2 == _sin || token2 == _tan)
SCTInput(token2);
else
post_expr[post_i++] = put_token(token2);
post_expr[post_i++] = ' ';
}
void SCTInput(int token2)
{
if(token2 == _cos)
{
post_expr[post_i++] = 'c';
post_expr[post_i++] = 'o';
post_expr[post_i++] = 's';
}
else if(token2 == _sin)
{
post_expr[post_i++] = 's';
post_expr[post_i++] = 'i';
post_expr[post_i++] = 'n';
}
else if(token2 == _tan)
{
post_expr[post_i++] = 't';
post_expr[post_i++] = 'a';
post_expr[post_i++] = 'n';
}
}
int CountMark(int *n)
{
int i;
for(i=0;'-'==expr[(*n)++];++i);
return i;
}
void InsertMinus(void)
{
post_expr[post_i++] = '-';
post_expr[post_i++] = '1';
post_expr[post_i++] = ' ';
}
int get_token(char* symbol, int* n, int* top)
{
int tmpN=0;
int is_tFunc=0;
*symbol = expr[(*n)++];
switch(*symbol)
{
case '-':
if(*n==1) // 첫번째가 음수면 음수숫자이다.
{
if(isdigit(expr[*n]))
return operand;
else
{
tmpN = *n; // 카운트 세기 전의 N값
rtnM = CountMark(n); // 여기서 n이 증가한다.
if(rtnM % 2)
{
*symbol = expr[*n-1]; // -10*----5 일경우 5를 리턴
if(*symbol == '(')
return false;
else
return operand;
}
else
{
if(expr[*n-1] == '(')
{
InsertMinus();
add(top,times);
}
else
{
--*n;
return operand;
}
}
}
}
////////////////////////////////////////////
else if(expr[*n] == '-') // 음수가 연속으로 들어간경우 최소 2개
{
tmpN = *n; // 카운트 세기 전의 N값
rtnM = CountMark(n); // 여기서 n이 증가한다.
//printf(" === %d === ",rtnM);
//
// 홀수가 들어오면 양수로 바뀐다...
//
if(rtnM % 2)
{
// 앞부분이 숫자가 아닌경우
if(!isdigit(expr[tmpN-2]))
{
*symbol = expr[*n-1]; // -10*----5 일경우 5를 리턴
if(*symbol == 's' || *symbol == 'c' || *symbol == 't')
{
if((is_tFunc = is_tfunc(symbol, n)))
{
++*n;
return is_tFunc;
}
else
return false;
}
else if(*symbol == '(')
{
add(top,plus);
return false;
}
return operand;
}
else
{
add(top,plus); // +로 바뀐다...
//--*n;
// 리턴 값을 안먹는다 ㅡ.ㅡ;
// 원랜 return plus;였음...
return false;
}
}
else
{
if(isdigit(expr[tmpN-2])) // 연속된 음수 앞이 숫자가 아닌 경우
{
add(top,minus);
// 리턴 값을 안먹는다 ㅡ.ㅡ;
return false;
}
else
{
*symbol = expr[*n-1]; // -10*----5 일경우 5를 리턴
if(*symbol == 's' || *symbol == 'c' || *symbol == 't')
{
InsertMinus();
add(top,times);
--*n;
return false;
}
else
{
--*n;
return operand;
}
}
}
}
////////////////////////////////////////
else if(expr[*n]=='(')
{
InsertMinus();
add(top,times);
++*n;
return false;
}
/////////////////////////////////////////
else if((expr[*n]=='c' || expr[*n]=='t' || expr[*n]=='s') && !isdigit(expr[*n-2]))
{
InsertMinus();
add(top,times);
return false;
}
///////////////////////////////////////
else if(!isdigit(expr[*n-2])) // 음수 앞이 숫자가 아닌경우
{
return operand;
}
//////////////////////////////////////
else // 일반적인 빼기
{
return minus;
}
case '(': return lparen;
case ')': return rparen;
case '+': return plus;
case '/': return divide;
case '*': return times;
case '%': return mod;
case '\0': return eos;
default:
if((is_tFunc=is_tfunc(symbol, n)))
return is_tFunc;
else
return operand;
}
}
int is_tfunc(char* symbol, int* n)
{
if(*symbol == 's' && expr[*n] == 'i' && expr[*n+1] == 'n')
{
*n+=2;
return _sin;
}
else if(*symbol == 'c' && expr[*n] == 'o' && expr[*n+1] == 's')
{
*n+=2;
return _cos;
}
else if(*symbol == 't' && expr[*n] == 'a' && expr[*n+1] == 'n')
{
*n+=2;
return _tan;
}
return false;
}
int is_tfunc2(char* symbol, int* n)
{
if(*symbol == 's' && post_expr[*n] == 'i' && post_expr[*n+1] == 'n')
{
*n+=2;
return _sin;
}
else if(*symbol == 'c' && post_expr[*n] == 'o' && post_expr[*n+1] == 's')
{
*n+=2;
return _cos;
}
else if(*symbol == 't' && post_expr[*n] == 'a' && post_expr[*n+1] == 'n')
{
*n+=2;
return _tan;
}
return false;
}
int get_token2(char* symbol, int* n)
{
int is_tFunc = 0;
*symbol = post_expr[(*n)++];
if(*symbol == 'c' || *symbol == 's' || *symbol == 't')
if((is_tFunc=is_tfunc2(symbol, n)))
return is_tFunc;
switch(*symbol)
{
case '-':
if(*n==1)
return operand;
else if(isdigit(post_expr[*n]))
{
return minus_val;
}
else
{
return minus;
}
case '(': return lparen;
case ')': return rparen;
case '+': return plus;
case '/': return divide;
case '*': return times;
case '%': return mod;
case '\0': return eos;
case ' ': return blank;
default: return operand;
}
}
void print_token(int n)
{
printf("%c ",put_token(n));
}
char put_token(int n)
{
switch(n)
{
case minus: return '-';
case lparen: return '(';
case rparen: return ')';
case plus: return '+';
case divide: return '/';
case times: return '*';
case mod: return '%';
case eos: return '\0';
default: return '\0';
}
}
int rmstack(int* top)
{
return stack[(*top)--];
}
double pop(int* top)
{
return dbl_stack[(*top)--];
}
void add(int* top, int token)
{
stack[++*top] = token;
}
//
// overloading
//
void add(int* top, double token)
{
dbl_stack[++*top] = token;
}
double eval(void)
{
int token;
char symbol;
double op1, op2;
int n = 0;
int top = -1;
char szLine[100];
int cnt=0;
while((token = get_token2(&symbol, &n)) != eos)
{
if(token == blank) continue;
if(token == minus_val || token == operand)
{
szLine[cnt++] = symbol;
while((token = get_token2(&symbol, &n)) != blank)
szLine[cnt++] = symbol;
szLine[cnt] = '\0';
add(&top, atof(szLine));
cnt = 0;
}
else if(token == _sin || token == _cos || token == _tan)
{
op1 = ConvertRadian(pop(&top));
switch(token)
{
case _sin: add(&top, sin(op1)); break;
case _cos: add(&top, cos(op1)); break;
case _tan: add(&top, tan(op1)); break;
}
}
else
{
op2 = pop(&top); // delete stack
op1 = pop(&top);
switch(token)
{
case plus:
add(&top, op1+op2);
break;
case minus :
add(&top, op1 - op2);
break;
case times :
add(&top, op1 * op2);
break;
case divide:
add(&top, op1 / op2);
break;
case mod :
add(&top, (int)op1 % (int)op2);
break;
}
}
}
return pop(&top); // return result
}
double ConvertRadian(double d)
{
return (d*3.141592/180);
}