#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
//#include<time.h>
#define OPERATORSTACK_LENGTH 5
#define NUMBERSTACK_LENGTH 100
#define MAX_STRING_LENGTH 100
//判断函数************
char string[MAX_STRING_LENGTH];
//显示时间
/*void show_time()
{
printf("\n");
printf("亲~现在时间是 ");
time_t t = time(0);
char tmp[64];
strftime( tmp, sizeof(tmp), "%Y/%m/%d %X %A 本年第%j天 %z",localtime(&t) );
puts( tmp );
printf("\n");
}*/
//保存输入记录
char s[7];
int len, len1, i, j, n, point, num;//len是s[]的长度
int ans[200], reee[200], a[7], ok, d, m;
int flag_file=0;
int rizhi=0;
//char name_file[]="store.txt";
void save(){
FILE *fp;
if(flag_file==0)
{
if((fp=fopen("store.txt","w"))==NULL)
{
printf("fail to open file\n");
exit(1);
}
flag_file=1;
}
if((fp=fopen("store.txt","at+"))==NULL){
printf("fail to open file\n");
exit(1);
}
//fputc(ch,fp);
fputs(string,fp);
fputc('\n',fp);
fclose(fp);
}
//利息计算
void F() //乘法函数(与之前用过的模板原理相同)
{
for ( i=0 ; i < len ; i++ )
for( j = 0 ; j < len1 ; j++ )
{
reee[i + j] += ( a[i] * ans[j] % 10 );
reee[ i + j + 1 ] += ( a[i] * ans[j] / 10 ) ;
}
for( i=0 ; i < len + len1 - 1 ; i++)
{
if( reee[i] >= 10 )
{
reee[i+1] += reee[i]/10;
reee[i] %= 10;
}
}
if( reee[len + len1 - 1] != 0) //判断高位有没进位
len1 = len1 + len;
else
len1 = len1 + len - 1;
for( i=0 ; i < len1 ; i++)
ans[i] = reee[i];
}
void profit()
{
int k;
scanf("%s%d", s, &n);
len = strlen(s);
if( n == 1) //若是一次方则直接输出
{
printf("%g\n", atof(s));//n为1,情况特殊(把字符串转换成浮点数)
return;
}
point = 0;
ok = 0;
i = 0;
j = len - 1;
for ( m=0 ; m < len ; m++)//没分什么小数部分整数部分,一起计算,只要记录小数点位置就Ok
{
if( s[m] == '.' ) //找s[m]中是否是有'.'
{
ok = 1; //找到小数点的位置
break;
}
}
if( ok == 1 ) //如果有小数点则执行(j=len-1)
{
while( s[j] == '0' && j >= 0 )
j-- ;
while( s[j] != '.' && j >= 0)
a[i++] = s[j--] - 48; //(i=0)字符与数字之间的转换
//从后往前找,将小数点剔除
point = i;
j-- ;
}
num = point * n ;//计算乘方后小数点应该在的位置
for( m=0 ; m <= j ; m++)
if( s[m] != '0' )
break;
while( j >= m ) //从前往后找将整数部分取出
a[ i++ ] = s[j--] - 48;
len=i;
len1=len;
memset( ans , 0 , sizeof(ans));
for( i=0 ; i<len ; i++ )
ans[i] = a[i];
for( k=2 ; k<=n ; k++)//该题关键---计算乘方的次数
{
memset( reee , 0 , sizeof(reee));//每次计算之后都要清零
F();
}
d = num - 1;
for( i = len1-1 ; i >= num ; i-- ) //len1=len
{
if( reee[i] != 0 )
{
d=i;
break;
}
}
if( d >= num ) //输出部分是将完整的reee分成前后两部分
{ //控制好小数点输出的位置
for( i = len1-1 ; i >= num ; i-- )
printf( "%d" , reee[i] );
}
if( point != 0 && ok==1)//输出的要求较高
printf( "." );
for( i = num-1 ; i >= 0 ; i--)
printf("%d", reee[i] );
putchar(10);
}
int judge_equation1(int length){//判断出现加减乘除()0~9之内的数cos,sin,tan,cot之外的符号
int i;
for(i=0;i<=length;i++){
if(string[i]<'0'||string[i]>'9'){
if(string[i]!='.'&&string[i]!='+'&&string[i]!='-'&&string[i]!='*'&&string[i]!='/'&&string[i]!='('&&string[i]!=')'){
if(length-i>=2&&string[i]=='s'){
if(string[i+1]=='i'&&string[i+2]=='n'){
i=i+2;
continue;
}
}
if(length-i>=2&&string[i]=='c'){
if(string[i+1]=='o'&&string[i+2]=='s'){
i=i+2;
continue;
}
}
if(length-i>=2&&string[i]=='t'){
if(string[i+1]=='a'&&string[i+2]=='n'){
i=i+2;
continue;
}
}
return 1;
}
}
}
return 0;
}
int judge_equation2(int length){//判断括号的个数是否匹配括号里面一定有其他的符号,且左括号一定大于右括号,且左括号要等于右括号的个数
int i,bracket=0;
for(i=0;i<=length;i++){
if(string[i]=='('){
if(string[i+1]==')'){
return 1;
}
bracket++;
}
if(string[i]==')'){
bracket--;
}
if(bracket<0) return 1;
}
if(bracket!=0) return 1;
return 0;
}
int judge_equation3(int length){//对点数的检验,不可能同时出现两个点连在一起,不可能是空字符串即下面的i=w
int i,ans=0;
for(i=0;i<=length;i++){
if(string[i]=='.'){
ans++;
if(ans>1) return 1;
if(i==length) return 1;
if(string[i+1]<'0'||string[i+1]>'9') return 1;
}
if(string[i]=='+'||string[i]=='-'||string[i]=='*'||string[i]=='/'||string[i]=='('||string[i]==')'){
ans=0;//当遇到一个操作符点数立即清零
}
}
return 0;
}
int judge_equation4(int length){//不可能空字符,加减的位置不可能在最后一个位置或者是最开始的位置,*/号后面包含的数不包含0~9以外的数字或者(
int i;
for(i=0;i<=length;i++){
if(string[i]=='+'||string[i]=='-'||string[i]=='*'||string[i]=='/'){
//printf("judg4111\n");
if(i==length)
{
// printf("judg4111i=w\n");
return 1;
}
if((string[i+1]<'0'||string[i+1]>'9')&&string[i+1]!='(') return 1;
}
}
return 0;
}
int judge_equation(int length){//判断运算式子是否正确,并返回等式错误的原因
int a=0;
if(judge_equation1(length)==1){
printf("表达式中含有其他的计算器不能识别的符号");
a=1;
}
if(judge_equation2(length)==1) {
printf("括号不匹配!");
a=1;
}
if(judge_equation3(length)==1)
{
printf("输入的数字不合法!");
a=1;
}
if(judge_equation4(length)==1)
{
printf("输入的符号组合不合法!");
a=1;
}
if(a==1)
return 1;
else
return 0;
}
int judge(){//判断等式是否正确
if(rizhi==0){//如果是记录日志的功能的话则不需要输入新的字符串
scanf("%s",string);
}
return judge_equation(strlen(string)-1);
}
//***************
struct my_operator
{
char name;
int priority;
int opnum;
};
struct my_operator opStack[OPERATORSTACK_LENGTH];// 存放操作符的栈 //利用的栈的先进后出的原则存放运算符和数字,根据符号的优先级,来计算
int opStackTop = -1; //栈顶
double numStack[NUMBERSTACK_LENGTH]; //存放数字的栈
int numStackTop = -1; //栈顶
int getPriority(char name) //获取读取符号的优先级*/优先其次是+-而括号用于读取数据是计算完括号内部的数字,使得等式简化为不含有括号的式子,最后再进行运算,在括号内部的式子先算加减号,后算乘除号
{
/*switch(name)//利用switch语句简化代码
{
case '(':
case ')':
return 0;
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
exit("1");
}*/
if (name == '(' || name == ')')
{
return 0;
}
if (name == '*' || name == '/')
{
return 2;
}
if (name == '+' || name == '-')
{
return 1;
}
exit(1);
}
int getOpNum(char name) //得到符号的运算顺序
{
/*switch(name)//利用switch语句简化代码
{
case '*':
case '/':
case '+':
case '-':
return 1;
case '(':
case ')':
return 0;
default:
exit(1);
}*/
if (name == '*' || name == '/' || name == '+' || name == '-')
{
return 1;
}
if (name == '(' || name == ')')
{
return 0;
}
exit(1);
}
void pushOperator(struct my_operator op) //将读取的操作数的结构体放入栈中
{
if (opStackTop < OPERATORSTACK_LENGTH - 1)
{
opStack[++opStackTop] = op;
}
else
{
exit(1);
}
}
struct my_operator popOperator() // 将操作数从栈中提出
{
if (opStackTop >= 0)
{
return opStack[opStackTop--];
}
else
{
exit(1);
}
}
void pushNumber(double num) //同上操作数
{
if (numStackTop < NUMBERSTACK_LENGTH - 1)
{
numStack[++numStackTop] = num;
}
else
{
exit(1);
}
}
double popNumber() //同上操作数
{
if (numStackTop >= 0)
{
return numStack[numStackTop--];
}
else
{
exit(1);
}
}
double getNumFromString(char *s, int *i) //将读取的字符中的数字读取一个出来 ,***这里用了指针传递了变量的地址,直接改变了主函数变量的值 ,同时返还下一位符号的位置
{
int j = 0;
static char numstr[MAX_STRING_LENGTH]; //判断是否是个整数
while ((*s) >= '0' && *s <= '9')
{
numstr[j++] = (*s);
s++;
}
if ((*s) == '.') //是否有点,如果有点的话还有读取点后面的数字,最终得到浮点数的字符串,最后运用库函数atof() 求出浮点数
{
numstr[j++] = (*s);
s++;
while ((*s) >= '0' && *s <= '9')
{
numstr[j++] = (*s);
s++;
}
}
(*i) = (*i) + j;
numstr[j] = '\0';
return atof(numstr);
}
double opertateNum(struct my_operator op) //运用逆波尔表达式的计算方法计算
{
double num2 = popNumber(); //由于减法和除法对2个数的顺序有要求所以用num2存放符号后面一个数,再用num1存放符号前面一个数,而由于栈先进后出,所以后面的数先被弹出,所以num3=先弹出的数
double num1 = popNumber();
switch(op.name)
{
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1*num2;
case '/':
if(num2==0)
{
printf("error:the number is divided is 0!\n");
exit(1);
}
return num1 / num2;
default:
exit(1);
}
/*if (op.name == '+')
{
return num1 + num2;
}
if (op.name == '-')
{
return num1 - num2;
}
if (op.name == '*')
{
return num1 * num2;
}
if (op.name == '/')
{
if(num2==0)
{
printf("error:the number is divided is 0!\n");
exit(1);
}
return num1 / num2;
}
exit(1); */
}
/*double opertate1Num(OPERATOR op)
{
double num = popNumber();
if (op.name == '!')
{
double result = 1;
while (num > 1)
{
result *= num;
num--;
}
return result;
}
exit(1);
} */
double operate(struct my_operator op) //根据操作符的操作顺序进行操作
{
/*if (op.opnum == 1)
{
return opertate1Num(op);
}
else*/
if (op.opnum == 1)
{
return opertateNum(op);
}
exit(1);
}
char get_char()//得到要获取的字符
{
char c;
scanf("%c",&c);
while(c==' '||c=='\n'||c=='\t')
scanf("%c",&c);
//printf("c=%c\t",c);
if(c=='n'||c=='y')//flag 的限制条件
{
;
}else
printf("error:the character you input is wrong!\n");
return c;
}
char get_char_flag()//得到要获取的字符
{
char c;
scanf("%c",&c);
while(c==' '||c=='\n'||c=='\t')
scanf("%c",&c);
//printf("c=%c\t",c);
if(c=='1'||c=='2'||c=='3'||c=='4'||c=='5'||c=='6')//限制条件
{
;
}else
{
printf("error:the character you input is wrong!exit\n");
exit(1);
//printf("11111\n");
}
return c;
}
char get_char_flag3()//得到要获取的字符
{
char c;
scanf("%c",&c);
while(c==' '||c=='\n'||c=='\t')
scanf("%c",&c);
//printf("c=%c\t",c);
if(c>='1'&&c<='6')//限制条件
{
;
}else
{
printf("error:the character you input is wrong!exit\n");
exit(1);
}
return c;
}
void up_show(){
FILE *fp;
char sss[100];
if((fp=fopen("store.txt","rt+"))==NULL){
puts("fail to open file");
exit(1);
}
fgets(sss,100,fp);//要先获取后判断
while(!feof(fp)){
printf("%s",sss);
fgets(sss,100,fp);
//if(feof(fp))
// break;
}
fclose(fp);
}
void show(){//显示日志
char filename[100];
FILE *fp;
printf("please input filename\n");
scanf("%s",filename);
if((fp=fopen(filename,"rt"))==NULL){
puts("fail to open file");
exit(1);
}
fgets(string,100,fp);
//printf("%s\n",string);
fclose(fp);
}
int search_math_flag()//判断从日志读取的式子中是否要进行函数运算cossin等
{
// printf("enter search_math_flag\nstring[0]=%c\n",string[0]);
//printf("string=%s\n",string);
if(string[0]=='s'||string[0]=='c'||string[0]=='t')
{
return 2;
}else
{
return 1;
}
}
void calculate()//计算
{
double result;//初始化
char flag1_last;
int i,a,number,math_flag;
char flag,flag1,flag2,flag3,flag4;
struct my_operator op, topOp;//topOp操作符的栈顶元素
topOp.name = '#'; //*****判断操作数是否已经运算完毕的标识符
topOp.priority = 0;
topOp.opnum = 0;
pushOperator(topOp);
printf(" 欢迎使用该计算器(╯3╰)\n\n********************************************************************************如果你想使用计算器,请输入'y'.否则输入'n'\n");
//show_time();
flag=get_char();
while(flag=='y')
{
topOp.name = '#';
topOp.priority = 0; //初始化
topOp.opnum = 0;
opStackTop = 0;
printf("********************************************************************************");
printf("if you want to use the function which is listed ,please enter the number which is before the function you want to use\n");
printf("1基本的加减乘除运算\n2基本函数运算\n3进制转化\n4使用日志\n5查询历史记录\n6利息计算\n");//选择
//printf("");
flag1=get_char_flag();
// scanf("%c",&flag1);
switch(flag1)//判断输入的字符时什么
{
case '1':
printf("the basic calculation:\n");
break;
case '2':
printf("the basic function calculation:\n");
printf("1sin\t2cos\n3tan\t4cot\n");
flag2=get_char_flag();
break;
case '3':
printf("enter hex converter\n");
break;
case '4':
rizhi=1;
show();
break;
case '5':
up_show();
break;
case '6':
printf("please input profit and number of year\n");
profit();
break;
default:
printf("error!\n");
break;
}
/*if(flag1=='1')
printf("the basic calculation:\n");
else if(flag1=='2')
{
printf("the basic function calculation:\n");
printf("1sin\t2cos\n3tan\t4cot\n");
flag2=get_char_flag();
//printf("flag2=%c\n",flag2);
//if(flag2)
// scanf("%c",&flag);
}else if(flag1=='3')
printf("enter hex converter\n");
else if(flag1=='4'){
rizhi=1;
show();
}
else if(flag1=='5'){
up_show();
}else if(flag1=='6'){
printf("please input profit and number of year\n");
profit();
} */
if(flag1=='1'||flag1=='2'||flag1=='4')//判断进行函数运算还是基本算术运算
{
if(flag1=='1'||flag1=='2'){
rizhi=0;
printf("input you equation:");
}
a=judge();
if(a==0){
;
//jbs();
}
else {
save();
printf("表达式不合法\n");
}
flag1_last=flag1;
if(flag1=='4')//判断日志中的等式是进行函数运算还是基本运算
{
math_flag=search_math_flag();
// printf("math_flag=%d\n",math_flag);
if(math_flag==2)
{
flag1='2';
if(string[0]=='s'&&string[1]=='i'&&string[2]=='n')
flag2='1';
else if(string[0]=='c'&&string[1]=='o'&&string[2]=='s')
flag2='2';
else if(string[0]=='t'&&string[1]=='a'&&string[2]=='n')
flag2='3';
else
flag2='4';
}else
{
flag1='1';
}
}
//printf("flag1_last=%c\n",flag1_last);
if(flag1_last=='4'&&flag1=='2')//将他们要计算的值从全是基本等式开始
{
i=3;//函数的话一开始就是要加3
}else
i=0;
// printf("******flag1=%c\n",flag1);
// printf("i=%d\n",i);
for (; string[i] != '\0' && string[i] != '=';) //按照优先级,栈的原理来进行计算,#做结束符
{
// printf("flag1=%c\n",flag1);
// printf("string[i]=%c",string[i]);
if (string[i] >= '0' && string[i] <= '9') //获取数字并压到数栈中
{
pushNumber(getNumFromString(&string[i], &i));
//printf("flag1=%c\n",flag1);
}
else
{
op.name = string[i]; //获取符号,判断其优先级,优先顺序并构成一个结构体
op.priority = getPriority(string[i]);
op.opnum = getOpNum(string[i]);
topOp = popOperator(); //将原来栈中的符号取出来一遍判断是否用到 ,优先顺序比后者低则不用掉或者在一个完整的括号内则需要用掉 遇到半个括号则需要把原来的和现在的操作数压会栈中
if (op.name == '(')
{
pushOperator(topOp);
pushOperator(op);
}
else if (op.name == ')')
{
while (topOp.name != '(')
{
pushNumber(operate(topOp)); //
topOp = popOperator();
}
}
else
{
if (topOp.name != '#' && op.priority <= topOp.priority) //刚刚获取的符号前一个符号不是‘#’前面的运算符优先级比单签的运算符好则你计算,并将值压会到栈中,
{
pushNumber(operate(topOp));
}
else
{
pushOperator(topOp); //前面的运算符优先级比当前的低或者前面的运算符是#(只有一个数字不能进行符号间的运算)
}
pushOperator(op); //再将当前的运算符压回
}
i++;
}
}
// printf("flag1=%c\n",flag1);
while ((topOp = popOperator()).name != '#') //当读取结束后只剩下不含有括号的式子,而后面的优先级一定比前面的高或者相等所以开始一次次提出运算符,并计算,得到最终值
{
pushNumber(operate(topOp));
}
result=popNumber();
//printf("flag1=%c\n",flag1);
if(flag1=='1')
{
FILE *f1;
if(flag1_last=='4')
{
printf("%s\n",string);
}
printf("result=%g\n", result);
//save();
if(flag_file==0)
{
if((f1=fopen("store.txt","w"))==NULL)//将基本运算的结果记录下来
{
printf("fail to open file\n");
exit(1);
}
flag_file=1;
}
if((f1=fopen("store.txt","at+"))==NULL){
printf("fail to open file\n");
exit(1);
}
// fputc(ch,fp);
fputs(string,f1);
fputc('=',f1);
fprintf(f1,"%g\n",result);
fclose(f1);
}else
{
//printf("5flag2=%c\n",flag2);
FILE *f;
if(flag_file==0)
{
if((f=fopen("store.txt","w"))==NULL)
{
// printf("fail to open file\n");
exit(1);
}
flag_file=1;
}
if((f=fopen("store.txt","at+"))==NULL)
{
printf("fail to open file\n");
exit(1);
}
//fputc(ch,fp);
/*if(flag2=='1')
{
// printf("sinprintwenjian\n");
result=sin(result);
fputs("sin",f);
}
else if(flag2=='2')
{
result=cos(result);
fputs("cos",f);
}
//printf("result=%g\n",result);
else if(flag2=='3')
{
result=tan(result);
fputs("tan",f);
}
else
{
result=1/tan(result);
fputs("cot",f);
}
printf("result=%g\n",result);*/
//把sin,cos,tan,cot函数的结果存到文件中
if(flag1_last=='4')//将函数运算的结果记录下来
{
if(flag2=='1')
{
// printf("sinprintwenjian\n");
result=sin(result);
// fputs("sin",f);
}
else if(flag2=='2')
{
result=cos(result);
// fputs("cos",f);
}
//printf("result=%g\n",result);
else if(flag2=='3')
{
result=tan(result);
// fputs("tan",f);
}
else
{
result=1/tan(result);
// fputs("cot",f);
}
printf("result=%g\n",result);
fputs(string,f);
fputc('=',f);
fprintf(f,"%g\n",result);
}else
{
if(flag2=='1')
{
// printf("sinprintwenjian\n");
result=sin(result);
fputs("sin",f);
}
else if(flag2=='2')
{
result=cos(result);
fputs("cos",f);
}
//printf("result=%g\n",result);
else if(flag2=='3')
{
result=tan(result);
fputs("tan",f);
}
else
{
result=1/tan(result);
fputs("cot",f);
}
printf("result=%g\n",result);
fputc('(',f);
fputs(string,f);
fputc(')',f);
fputc('=',f);
fprintf(f,"%g\n",result);
}
//fputc('\n',f);
fclose(f);
}
}else if(flag1=='3')//选择进制并计算
{
printf("1十进制转八进制\t2十进制转十六进制\n3八进制转十进制\t4八进制转十六进制\n5十六进制转八进制\t6十六进制转十进制\n");
flag3=get_char_flag3();
switch(flag3)
{
case '1':
printf("input shijinzhi number:");
scanf("%d",&number);
printf("result=0%o\n",number);
break;
case '2':
printf("input shijinzhi number:");
scanf("%d",&number);
printf("result=0x%x\n",number);
break;
case '3':
printf("input bajinzhi number:");
scanf("%o",&number);
printf("result=%d\n",number);
break;
case '4':
printf("input bajinzhi number:");
scanf("%o",&number);
printf("result=0x%x\n",number);
break;
case '5':
printf("input shiliujinzhi number:");
scanf("%x",&number);
printf("result=0%o\n",number);
break;
case '6':
printf("input shiliujinzhi number:");
scanf("%x",&number);
printf("result=%d\n",number);
break;
}
}/*else if(flag1=='4')
{
printf("1二进制\t2八进制\t3十六进制\n");
}*/
printf("********************************************************************************if you enter into calculator again,if you want ,please input 'y'.else input 'n'\n");
flag=get_char();//判断是否继续
}
printf("exit\n");
}
int main()
{
calculate();
return 0;
}
Linux环境下的计算器
最新推荐文章于 2023-02-27 23:09:02 发布