# lizy14/C-assignments

Fetching contributors…
Cannot retrieve contributors at this time
1095 lines (968 sloc) 23.6 KB
 /* 表达式计算器 2014年12月 */ /*测试用例及其正确结果 23+56/(102-100)*((36-24)/(8-6)) 191 1+sin(30) 0.012 sin(5+2^(1+1)+log(2*(3+1))) -0.46028129421884 abs(-5.4432) 5.4432 sqrt(-5) ERROR 2^1000 1.0715086071863 * 10 ^ 301 100! 9.3326215443944 * 10 ^ 157 */ /* 代码说明 main函数处理用户设置、输入、输出； simplify主要实现去括号、数学函数求值算法； simplify_innermost处理不含括号的最内层表达式。 程序内部以“@5”表示“(-5)”。 */ //将下面一行注释掉就不输出中间结果了。。。。 #define DEBUGING #define _CRT_SECURE_NO_WARNINGS #include #include #include #include #define for_(i,x,y) for(i=x; i<=y; i++) //遍历整数 x to y #define forarray(i,n) for(i=0; i=0? x : -x) #define sign_(x) (x>0 ? 1 : (x==0 ? 0 : -1)) #define sqrt_(x) sqrt(x) #define ln_(x) log(x) #define sinh_(x) sinh(x) #define cosh_(x) cosh(x) #define tanh_(x) tanh(x) #define coth_(x) (1/tanh(x)) #define COS_ 0 #define SIN_ 1 #define TG_ 2 #define CTG_ 3 #define ABS_ 4 #define SIGN_ 5 #define SQRT_ 6 #define LN_ 7 #define SINH_ 8 #define COSH_ 9 #define TANH_ 10 #define COTH_ 11 //返回函数值, double double Functions(int name, double x) { switch(name) { case COS_: return cos_(x); case SIN_: return sin_(x); case TG_: return tg_(x); case CTG_: return ctg_(x); case ABS_: return abs_(x); case SIGN_: return sign_(x); case SQRT_: return sqrt_(x); case LN_: return ln_(x); case SINH_: return sinh_(x); case COSH_: return cosh_(x); case TANH_: return tanh_(x); case COTH_: return coth_(x); default: return -1; } } #define IsInt(x) fabs((floor(x) - x))=0); if(!p) puts("sqrt 定义域非法"); return (p); case LN_: p=(x>0); if(!p) puts("ln 定义域非法"); return (p); case SINH_: return 1; case COSH_: return 1; case TANH_: return 1; case COTH_: p=(x!=0); if(!p) puts("ln 定义域非法"); return (p); default: return -1; } } char functionnames[][5]={"cos","sin","tg","ctg","abs","sign","sqrt","ln","sinh","cosh","tanh","coth"}; #define nfunctions 12 #define lenfunctionname(x) strlen(functionnames[x]) char ops[] = {'(', ')', '+', '-', '*', '/', '^', '!'}; #define nops 8 char digits[]={'0','1','2','3','4','5','6','7','8','9','.','@'}; #define ndigits 12 //错误代码 #define ERROR -1 #define NOT_FOUND -1 //参数传递 #define FULL_LENGTH -1 //函数声明 int Simplify(char* expression); int SimplifyInnermost(char*buffer, char*innermost_expression); void MultiplyBigInt(char* s1, char* s2, char* result); void Plus(char* s1, char* s2, char* result); int Division(char* s1, char* s2, char* result); void Power(char* s1, char* s2, char* result); int InnermostParentheses(char* expression); int MatchingParentheses(char* expression, int left); int UnexpectRightParentheses(char* expression); #define ParenthesesMatch(x) (CountCharInString(x,'(', FULL_LENGTH) == CountCharInString(x,')',FULL_LENGTH)) void HighlightCharInString(char* str, int chr); void OutputResult(char* expression, int outputDigits); //字符串处理函数 void strcpyEx(char* des, char* src, int left, int right); int FindCharInString(char* str, char chr); int CountCharInString(char* str, char chr, int length); void InsertChar(char* str, int pos, char chr); void RemoveChar(char* str, int chr); void StringReplace(char* src, char* des, int start, int end); int FindOp(char* expression); int IsOp(char chr); int FindFunctionName(char* expression, int end); #define chartoint(x) (x - '0') #define inttochar(x) (x + '0') #define max(x,y) (x>=y? x: y) #define min(x,y) (x>=y? y: x) void StartPrompt() { puts("欢迎使用表达式计算器。\n"); } void SettingPrompt() { puts(" 输入 r 设置为弧度制，输入 a 设置为角度制，"); puts(" 输入一个 0~15 的整数设置输出的小数位数。"); puts(" 输入 exit 退出设置。"); } void InputPrompt() { puts("请输入一个表达式，回车结束。"); puts(" 输入 exit 退出程序。"); puts(" 输入 setting 进入设置。"); printf("当前设定为："); printf((AngleMode==ANGLE? "角度制": "弧度制")); printf("，输出 %d 位小数。\n", outputDigits); } int main() { StartPrompt(); InputPrompt(); while (233) { putchar('\n'); char expression[MAX_STRING_LENGTH]; //输入 { char buffer[MAX_STRING_LENGTH]; printf((setting? "setting>>": ">>")); gets(buffer); if(setting) { if(!strcmp(buffer, "exit")) { setting = 0; puts("您已退出设置。\n"); InputPrompt(); continue; } switch(buffer[0]) { case 'r': AngleMode = RADIAN; puts("已设置为 弧度制。"); continue; case 'a': AngleMode = ANGLE; puts("已设置为 角度制。"); continue; } int n; if(sscanf(buffer, "%d", &n)) if(n>=0 && n <= 15) { outputDigits=n; printf("已设置为 输出小数点后 %d 位。\n", n); continue; } puts("设置格式不正确"); continue; } if(!strcmp(buffer, "exit")) return 0; if(!strcmp(buffer, "setting")) { setting = 1; puts("您已进入设置。"); SettingPrompt(); continue; } int retUnexpectRightParentheses = UnexpectRightParentheses(buffer); if(retUnexpectRightParentheses != NOT_FOUND) { printf("输入不合法：发现无法匹配的 ')'\n", retUnexpectRightParentheses); HighlightCharInString(buffer, retUnexpectRightParentheses); putchar('\n'); continue; } if(!ParenthesesMatch(buffer)) { puts("输入不合法：丢失 ')'"); continue; } strcpy(expression, buffer); } //输入结束 //主要代码开始 if(Simplify(expression) == 0) { //输出计算结果 OutputResult(expression,outputDigits); puts(expression); FILE *file=fopen("output.txt","a"); if(file==NULL) puts("无法打开 output.txt 进行写入。"); else { fputs(expression, file); fputs("\n", file); puts("计算结果已写入 output.txt。"); fclose(file); } } else { printf("出现错误，计算已中止。结果为： %s\n", expression); } //主要代码结束 AskForAnotherInput: ; } return 0; } //主要函数，在expression上直接修改，正常则返回0，否则输出错误信息并返回ERROR //本函数主要处理去括号 int Simplify(char* expression) { char last_expression[MAX_STRING_LENGTH]; last_expression[0]=0; while(FindOp(expression)) { //查找最右的'('和对应的')'，取出其中部分innermost_expression int leftParentheses = InnermostParentheses(expression); int rightParentheses = MatchingParentheses(expression, leftParentheses); if(leftParentheses == NOT_FOUND) leftParentheses=-1;//如果考虑NOT_FOUND就是-1，这句确实没什么用。。 if(rightParentheses == NOT_FOUND) rightParentheses=strlen(expression); //紧跟括号的减号不算运算符 char innermost_expression[MAX_STRING_LENGTH]; strcpyEx(innermost_expression, expression, leftParentheses+1, rightParentheses-1); //判断里面有没有运算符 if(FindOp(innermost_expression)) { //里面有运算符：算出数值 char buffer[MAX_STRING_LENGTH]; if(SimplifyInnermost(buffer, innermost_expression) == 0) StringReplace(buffer,expression,leftParentheses+1, rightParentheses-1); else return ERROR; } else { //里面已经没有运算符了 //向前查找函数名 int name = FindFunctionName(expression, leftParentheses-1); if(name==NOT_FOUND) { //未找到函数名 //替换“(-”为“(@” if(innermost_expression[0]=='-') innermost_expression[0]='@'; //删去括号 if(leftParentheses != -1) { RemoveChar(expression, rightParentheses); RemoveChar(expression, leftParentheses); } } else { //找到函数名 double x; if(innermost_expression[0]=='@') innermost_expression[0]='-'; sscanf(innermost_expression, "%lf", &x); if(!InDomain(name, x))return ERROR; char buffer[MAX_STRING_LENGTH]; sprintf(buffer, "(%.16lf)", Functions(name, x));//程序内部取函数值16位小数 StringReplace(buffer, expression, leftParentheses-lenfunctionname(name), rightParentheses); } } //本轮循环结束 if(!strcmp(last_expression, expression))//进入死循环 { puts("未知错误，请检查输入是否合法"); printf("得到结果为 %s", expression); return ERROR; } strcpy(last_expression, expression); #ifdef DEBUGING puts(expression); #endif } return 0; } //判断chr是否是运算符（即：是否不存在于数组digits[]中） int IsOp(char chr) { int i; forarray(i, ndigits) if(digits[i]==chr) return 0; return 1; } //将整数x转化为字符串存入buffer void inttostring(char* Buffer, int x) { int temp = x; int l = 0; while(233) { temp /= 10; l++; if(temp==0)break; } temp = x; int i = 0; while(233) { Buffer[l-1-i] = inttochar(temp % 10); temp /= 10; i++; if(temp==0)break; } Buffer[l] = 0; } //处理不含括号的innermost_expression，送给buffer，正常则返回0，否则输出错误信息并返回ERROR int SimplifyInnermost(char* buffer, char*innermost_expression) { strcpy(buffer, innermost_expression); char last_buffer[65535]; last_buffer[0]=0; while(FindOp(buffer)) { int op; int len=strlen(buffer); if(!FindOp(buffer+1)) if(buffer[0]=='-') { buffer[0]='@'; return 0; } //处理阶乘 if(((op = FindCharInString(buffer, '!'))!=NOT_FOUND ) || ((op = FindCharInString(buffer, '！'))!=NOT_FOUND)) { int i; for(i=op; i>0; i--) if(IsOp(buffer[i-1]))break; if(i==op){puts("输入不合法");return ERROR;} if(buffer[op+1]=='!'){puts("输入不合法，不支持 '!!' ");return ERROR;} if(buffer[i]=='@') { puts("无法对负数计算阶乘"); return ERROR; } int max; { char temp[MID_STRING_LENGTH]; strcpyEx(temp, buffer, i, op-1); if(sscanf(temp,"%d", &max) == 0) { puts("阶乘定义域非法"); return ERROR; } if(FindCharInString(temp, '.') != NOT_FOUND) { puts("无法对小数计算阶乘"); return ERROR; } } char buffer1[MAX_STRING_LENGTH]="1"; int j; for_(j, 1, max) { char buffer2[MAX_STRING_LENGTH]; inttostring(buffer2, j); MultiplyBigInt(buffer1, buffer2, buffer1); } StringReplace(buffer1,buffer,i, op); goto nextLoop; } //处理^ if((op = FindCharInString(buffer, '^')) != NOT_FOUND) { int i; int j; for(i=op; i>0; i--) if(IsOp(buffer[i-1]))break; for(j=op; j0; i--) if(IsOp(buffer[i-1]))break; for(j=op; j0; i--) if(IsOp(buffer[i-1]))break; for(j=op; j0; i--) if(IsOp(buffer[i-1]))break; for(j=op; j0; i--) if(IsOp(buffer[i-1]))break; for(j=op; j {8,4,0,2} for_(i, 0, len1 - 1) x1[i] = chartoint(s1[len1 -1 - i]); for_(i, 0, len2 - 1) x2[i] = chartoint(s2[len2 -1 - i]); for_(i, 0, len1 - 1) { for_(j, 0, len2 - 1) { val[i+j] += x1[i] * x2[j]; } } //进位 for_(i, 0 , 18 +MID_STRING_LENGTH) { val[i+1] += val[i] / 10; val [i] %= 10; } //数字串转字符串 int h;//最高位 for(i = 19 +MID_STRING_LENGTH; i>=0; i--) { if(val[i] != 0) { h=i; break; } } j = 0; for(i = h; i>=0; i--) { result[j] = inttochar(val[i]); j++; } result[j] = 0; return; } //处理乘方，在指数是正整数、底数是整数的情况下支持大整数，其他情况调用库函数pow()，double void Power(char* s1, char* s2, char* result) { if(FindCharInString(s1,'.')==NOT_FOUND && FindCharInString(s2,'.')==NOT_FOUND && s2[0]!='-') //指数是正整数，底数是整数，调用MultiplyBigInt实现支持大整数 { char ans[MAX_STRING_LENGTH]="1"; int times = atoi(s2); int i; int sgn=1; if( (s1[0]=='-') && (times%2 ==1) ) { sgn = -1; RemoveChar(s1, 0); } if( (s1[0]=='-') && (times%2 ==0) ) RemoveChar(s1, 0); for_(i, 1, times) MultiplyBigInt(ans, s1, ans); if(sgn==-1) InsertChar(ans, -1, '@'); strcpy(result, ans); } else { long double x,y; sscanf(s1, "%lf", &x); sscanf(s2, "%lf", &y); sprintf(result, "%.16lf", pow(x,y)); } } //处理加法，目前使用 long long int 和 double，不支持大数；不支持'@' void Plus(char* s1, char* s2, char* result) { if(FindCharInString(s1,'.')==NOT_FOUND && FindCharInString(s2,'.')==NOT_FOUND) //两个都是整数 { //大整数加法未实现，本部分重写 int k = 0.1; long long int x, y; sscanf(s1, "%d", &x); sscanf(s2, "%d", &y); sprintf(result, "%d", x+y); } // else if(FindCharInString(s1,'.')==NOT_FOUND) // { // long double y; long long int x; // sscanf(s1, "%lld", &x); // sscanf(s2, "%lf", &y); // sprintf(result, "%.16lf", x+y); // } // else if(FindCharInString(s2,'.')==NOT_FOUND) // { // long double x; long long int y; // sscanf(s1, "%lf", &x); // sscanf(s2, "%lld", &y); // sprintf(result, "%.16lf", x+y); // } else { long double x,y; sscanf(s1, "%lf", &x); sscanf(s2, "%lf", &y); sprintf(result, "%.16lf", x+y); } } //处理除法，目前使用double，不支持大数，不支持'@' //出错则打印出错信息并返回ERROR int Division(char* s1, char* s2, char* result) { if( (s2[0]=='0' && s2[1]!='.')|| (s2[0]=='-' && s2[1]=='0' && s2[2]!='.') ) { puts("除数为零"); return ERROR; } long double x,y; sscanf(s1, "%lf", &x); sscanf(s2, "%lf", &y); sprintf(result, "%.16lf", x/y); } //将des从下标start到end的部分（均含）替换为src void StringReplace(char* src, char* des, int start, int end) { int lensrc = strlen(src); int lendes = strlen(des); int lenfield = end - start + 1; if(lensrc == lenfield) { int i; forarray(i, lensrc) des[start + i] = src[i]; } else if(lensrc > lenfield) { int i; des[lendes-lenfield+lensrc]=0; for(i=lendes-lenfield+lensrc-1; i>=start+lensrc-lenfield; i-- ) des[i]=des[i+lenfield-lensrc]; forarray(i, lensrc) des[start + i] = src[i]; } else if(lensrc < lenfield) { int i; forarray(i, lensrc) des[start + i] = src[i]; for_(i, start+lensrc, lendes-lenfield+lensrc-1) des[i]=des[i+lenfield-lensrc]; des[i]=0; } } //用作递归终止条件 //找到括号或运算符或函数名 则返回真。 int FindOp(char* expression) { int j; int sum=0; int len = strlen(expression); forarray(j, ndigits) sum += CountCharInString(expression, digits[j],len); return (sum < len); } //寻找最内层的'('，返回其下标，未找到返回 NOT_FOUND int InnermostParentheses(char* expression) { int ret = NOT_FOUND; int i; int len = strlen(expression); forarray(i, len) if(expression[i]=='(')ret=i; return ret; } //根据'('的下标寻找相对应的')'，返回其下标，未找到返回 NOT_FOUND int MatchingParentheses(char* expression, int left) { int nLeft = 0, nRight = 0; int len = strlen(expression); for(int i = left + 1; i < len; i++) { if(expression[i]=='(') nLeft++; if(expression[i]==')') { nRight++; if(nRight == nLeft+1) return i; } } return NOT_FOUND; } //查找不合适的')'，不存在则返回NOT_FOUND，不匹配则返回下标 int UnexpectRightParentheses(char* expression) { int len = strlen(expression); int i; forarray(i, len) if(CountCharInString(expression, '(',i+1) < CountCharInString(expression, ')',i+1)) return i; return NOT_FOUND; } //字符串中特定字符计数，len传入待检字符串长度 int CountCharInString(char* str, char chr, int len) { if(len == FULL_LENGTH)len = strlen(str); int i; int count= 0; forarray(i, len) if(str[i] == chr) count ++; return count; } //寻找str中第一个字符chr的位置，返回下标，未找到返回NOT_FOUND int FindCharInString(char* str, char chr) { int len = strlen(str); int i; forarray(i, len) if(str[i] == chr) return i; return NOT_FOUND; } //传入下标，高亮输出 void HighlightCharInString(char* str, int chr) { int len=strlen(str); int i; for(i=0; ipos; i--) str[i+1]=str[i]; str[pos+1]=chr; } //将str中下标pos的字符去掉 void RemoveChar(char* str, int pos) { int len=strlen(str); int i; for(i=pos; i