工程实践之高精度计算器

    技术2024-12-18  8

    说明

    本代码使用easyx绘制计算器界面,同时使用高精度算法实现大整数的连续运算

    前提准备

    需要安装easyx图形库,具体安装和使用流程请点击链接查看

    代码怎么用

    需要新建一个工程,向工程中添加头文件和源代码,或者先把所有头文件都提取出来放到一个新的cpp(虽然是c语言,但是easyx底层实现用到了很多c++的东西,所以需要放在cpp文件中,但是语法仍使用c语言)文件中,之后把下面所有块中的函数都提到这一个文件中,因为没有使用全局变量,所以不需要考虑函数接口的问题,直接放在一起就可以使用

    头文件1

    #ifndef _calculator_h #define _calculator_h #include <graphics.h> #include <windows.h> #include <conio.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> void menu(); void mouse_infor(); void input_num(char *str, char *str_all, int &str_len, int &str_all_len, char num); void calculate(char *ans, char *str, int &str_len, char *str_all, int &str_all_len, int &loca, int step, char op); #endif

    头文件2

    #ifndef _ALGORITHM_H #define _ALGORITHM_H #include<stdio.h> #include<string.h> #include<math.h> #include<time.h> #include<stdlib.h> #include<conio.h> #define _FOR(i, begin, end) for(i=begin; i<=end; ++i) #define _for(i, begin, end) for(i=begin; i>=end; --i) void add(char *ans, char *num); int compare(char *num_b, char *num_c); void subtract(char *ans, char *num); void multiply(char *ans, char *num); void division(char *ans, char *num); void mod(char *ans, char *num); int SubStract(int *numb, int *numc); void str_to_num(char *str, int *num); #endif

    主函数

    #include"calculator.h" #include"high_precision_algorithm.h" int main() { initgraph(600, 500); cleardevice(); setbkcolor(BLACK); menu(); mouse_infor(); closegraph(); return 0; }

    计算器界面绘制

    #include"calculator.h" #include"high_precision_algorithm.h" void menu() { loadimage(NULL, _T("space.jpg")); setcolor(DARKGRAY); //横线 line(0, 45, 600, 45); line(280, 158, 520, 158); line(280, 271, 520, 271); line(280, 384, 520, 384); line(520, 110, 600, 110); line(520, 175, 600, 175); line(520, 240, 600, 240); line(520, 305, 600, 305); line(520, 370, 600, 370); line(520, 435, 600, 435); //竖线 line(280, 45, 280, 500); line(360, 45, 360, 500); line(440, 45, 440, 500); line(520, 45, 520, 500); //文字 settextstyle(30, 0, _T("幼圆")); settextcolor(RGB(153,100,254)); outtextxy(180, 0, _T("大整数的四则运算")); settextcolor(RGB(153,100,254)); settextstyle(60, 40, _T("幼圆")); outtextxy(305, 75, _T("7")); outtextxy(385, 75, _T("8")); outtextxy(465, 75, _T("9")); outtextxy(300, 188, _T("4")); outtextxy(380, 188, _T("5")); outtextxy(460, 188, _T("6")); outtextxy(300, 301, _T("1")); outtextxy(380, 301, _T("2")); outtextxy(460, 301, _T("3")); outtextxy(380, 414, _T("0")); settextstyle(30, 0, _T("幼圆")); outtextxy(303, 414, _T("历")); outtextxy(303, 460, _T("史")); outtextxy(463, 414, _T("清")); outtextxy(463, 460, _T("零")); settextcolor(RGB(153,100,254)); settextstyle(60, 0, _T("幼圆")); outtextxy(545, 46, _T("<")); outtextxy(545, 111, _T("+")); outtextxy(545, 176, _T("-")); outtextxy(545, 241, _T("*")); outtextxy(545, 306, _T("/")); outtextxy(545, 371, _T("%")); outtextxy(545, 436, _T("=")); }

    鼠标信息捕获及对应处理

    #include"calculator.h" #include"high_precision_algorithm.h" void mouse_infor() { char ans[100], str[100], str_all[100]; int str_len = 0, str_all_len = 0; int loca = 50, step = 40;//文字初始位置及增加步长 MOUSEMSG m; memset(ans, 0, sizeof(ans)); memset(str, 0, sizeof(str)); memset(str_all, 0, sizeof(str_all)); while(1) { //处理数据超出屏幕的问题 if(loca > 500) { loca = 50; cleardevice(); setbkcolor(BLACK); menu(); } m = GetMouseMsg(); if(m.uMsg == WM_LBUTTONDOWN) { if(m.x>280 && m.x<360 && m.y>45 && m.y<158)//7 input_num(str, str_all, str_len, str_all_len, '7'); if(m.x>360 && m.x<440 && m.y>45 && m.y<158)//8 input_num(str, str_all, str_len, str_all_len, '8'); if(m.x>440 && m.x<520 && m.y>45 && m.y<158)//9 input_num(str, str_all, str_len, str_all_len, '9'); if(m.x>280 && m.x<360 && m.y>158 && m.y<271)//4 input_num(str, str_all, str_len, str_all_len, '4'); if(m.x>360 && m.x<440 && m.y>158 && m.y<271)//5 input_num(str, str_all, str_len, str_all_len, '5'); if(m.x>440 && m.x<520 && m.y>158 && m.y<271)//6 input_num(str, str_all, str_len, str_all_len, '6'); if(m.x>280 && m.x<360 && m.y>271 && m.y<384)//1 input_num(str, str_all, str_len, str_all_len, '1'); if(m.x>360 && m.x<440 && m.y>271 && m.y<384)//2 input_num(str, str_all, str_len, str_all_len, '2'); if(m.x>440 && m.x<520 && m.y>271 && m.y<384)//3 input_num(str, str_all, str_len, str_all_len, '3'); if(m.x>360 && m.x<440 && m.y>384 && m.y<500)//0 input_num(str, str_all, str_len, str_all_len, '0'); if(m.x>520 && m.x<600 && m.y>45 && m.y<110)//< { if(strlen(str) != 0) { str[--str_len] = '\0'; str_all[--str_all_len] = '\0'; } } //放在这为了第一次输入时的负号显示 if(m.x>520 && m.x<600 && m.y>175 && m.y<240)//- { if(strlen(ans)==0 && strlen(str)==0)//判断最开始读入数字时的负号 { str[str_len++] = '-'; str_all[str_all_len++] = '-'; } else { calculate(ans, str, str_len, str_all, str_all_len, loca, step, '-'); } } if(strlen(ans) == 0)//连续计算的需要,一次运算执行完如果不判断那么之前的记录就会被清除 { cleardevice(); setbkcolor(BLACK); menu(); setcolor(GREEN); settextstyle(40, 0, _T("幼圆")); loca = 50; outtextxy(0, loca, _T(str)); } if(m.x>280 && m.x<360 && m.y>384 && m.y<500)//历史 { loca += step; setcolor(GREEN); settextstyle(30, 0, _T("幼圆")); outtextxy(0, loca, _T("历史记录查看:")); loca += step; if(strlen(str_all) != 0) outtextxy(0, loca, _T(str_all)); else outtextxy(0, loca, _T("历史记录为空")); } if(m.x>440 && m.x<520 && m.y>384 && m.y<500)//清零 { //数据清除 memset(ans, 0, sizeof(ans)); memset(str, 0, sizeof(str)); memset(str_all, 0, sizeof(str_all)); str_len = str_all_len = 0; loca = 50; //图像清除 cleardevice(); setbkcolor(BLACK); menu(); setcolor(GREEN); settextstyle(40, 0, _T("幼圆")); outtextxy(0, loca, _T("历史记录已删除")); } if(m.x>520 && m.x<600 && m.y>110 && m.y<175)//+ { calculate(ans, str, str_len, str_all, str_all_len, loca, step, '+'); } if(m.x>520 && m.x<600 && m.y>240 && m.y<305)//* { calculate(ans, str, str_len, str_all, str_all_len, loca, step, '*'); } if(m.x>520 && m.x<600 && m.y>305 && m.y<370)// / { calculate(ans, str, str_len, str_all, str_all_len, loca, step, '/'); } if(m.x>520 && m.x<600 && m.y>370 && m.y<435)//% { calculate(ans, str, str_len, str_all, str_all_len, loca, step, '%'); } } } }

    计算

    #include"calculator.h" #include"high_precision_algorithm.h" void calculate(char *ans, char str[], int &str_len, char *str_all, int &str_all_len, int &loca, int step, char op) { int i; MOUSEMSG m; if(loca!=50 || strlen(ans)==0)//不是首行或第一次输入时 loca += step; setcolor(GREEN); settextstyle(40, 0, _T("幼圆")); outtextxy(0, loca, _T(op)); str_all[str_all_len++] = op; if(strlen(str)!=0 && str[0]!='+' && str[0]!='-')//为没有符号的数字加正号且保证一定是为数字加而不是单纯一个正号 { for(i=strlen(str); i>=1; i--) { str[i] = str[i-1]; } str[0] = '+'; } if(strlen(ans) == 0)//第一次运算 { strcpy(ans, str); str_len = 0; memset(str, 0, strlen(str)); } loca += step; while(1) { m = GetMouseMsg(); if(m.uMsg == WM_LBUTTONDOWN) { if(m.x>280 && m.x<360 && m.y>45 && m.y<158)//7 input_num(str, str_all, str_len, str_all_len, '7'); if(m.x>360 && m.x<440 && m.y>45 && m.y<158)//8 input_num(str, str_all, str_len, str_all_len, '8'); if(m.x>440 && m.x<520 && m.y>45 && m.y<158)//9 input_num(str, str_all, str_len, str_all_len, '9'); if(m.x>280 && m.x<360 && m.y>158 && m.y<271)//4 input_num(str, str_all, str_len, str_all_len, '4'); if(m.x>360 && m.x<440 && m.y>158 && m.y<271)//5 input_num(str, str_all, str_len, str_all_len, '5'); if(m.x>440 && m.x<520 && m.y>158 && m.y<271)//6 input_num(str, str_all, str_len, str_all_len, '6'); if(m.x>280 && m.x<360 && m.y>271 && m.y<384)//1 input_num(str, str_all, str_len, str_all_len, '1'); if(m.x>360 && m.x<440 && m.y>271 && m.y<384)//2 input_num(str, str_all, str_len, str_all_len, '2'); if(m.x>440 && m.x<520 && m.y>271 && m.y<384)//3 input_num(str, str_all, str_len, str_all_len, '3'); if(m.x>360 && m.x<440 && m.y>384 && m.y<500)//0 input_num(str, str_all, str_len, str_all_len, '0'); if(m.x>520 && m.x<600 && m.y>45 && m.y<110)//< { if(strlen(str) != 0)// { str[--str_len] = '\0'; str_all[--str_all_len] = '\0'; } } if(m.x>520 && m.x<600 && m.y>175 && m.y<240)//- { if(strlen(str) == 0)//现在的负号是在运算符之后的,但是还得满足在数字之前 { str[str_len++] = '-'; str_all[str_all_len++] = '-'; } } //设置裁剪区域 HRGN rgn = CreateRectRgn(0, loca, 280, loca+step); setcliprgn(rgn); //清除裁剪区域内容 clearcliprgn(); //取消裁剪区域 DeleteObject(rgn); setcliprgn(NULL); //重新显示文字 outtextxy(0, loca, _T(str)); if(m.x>520 && m.x<600 && m.y>435 && m.y<500)//= { break; } } } if(strlen(str)!=0 && str[0]!='+' && str[0]!='-')//添加正号 { for(i=strlen(str); i>=1; i--) { str[i] = str[i-1]; } str[0] = '+'; } switch(op) { case '+': add(ans, str); break; case '-': subtract(ans, str); break; case '*': multiply(ans, str); break; case '/': division(ans, str); break; case '%': mod(ans, str); break; } str_len = 0; memset(str, 0, strlen(str)); //输出答案 loca += step; outtextxy(0, loca, _T("=")); if(ans[0]=='+' || ans[1]=='0') outtextxy(10, loca, _T(ans+1)); else outtextxy(10, loca, _T(ans)); }

    高精度加法

    #include"calculator.h" #include"high_precision_algorithm.h" void add(char *ans, char *num) { int len_max; int cnt, begin; int sum, carry; int i, flag_b, flag_c; int num_b[100], num_c[100], num_tmp[100]; cnt = 1; sum = carry = 0; flag_b = ans[0]=='-'?1:0;//ans的负数标记 flag_c = num[0]=='-'?1:0;//num的负数标记 memset(num_b, 0, sizeof(num_b)); memset(num_c, 0, sizeof(num_c)); memset(num_tmp, 0, sizeof(num_tmp)); if(flag_b==0 && flag_c==1) //正+负 { num[0] = '+'; subtract(ans, num); } else if(flag_b==1 && flag_c==0) //负+正 { ans[0] = '+'; subtract(ans, num); if(ans[0] == '+') ans[0] = '-'; else if(ans[0] = '-') ans[0] = '+'; } else if(flag_b==1 && flag_c==1) //负+负 { ans[0] = '+'; num[0] = '+'; add(ans, num); ans[0] = '-'; } else if(flag_b==0 && flag_c==0) //正+正 { memset(num_b, 0, sizeof(num_b)); memset(num_c, 0, sizeof(num_c)); memset(num_tmp, 0, sizeof(num_tmp)); str_to_num(ans, num_b), memset(ans, 0, strlen(ans)); str_to_num(num, num_c); len_max = max(num_b[0], num_c[0]); _FOR(i, 1, len_max) { sum = num_b[i] + num_c[i] + carry; num_tmp[i] = sum%10; carry = sum/10; } //开始的进位 if(carry != 0) { num_tmp[len_max+1] = carry; num_tmp[0] = len_max+1; } else num_tmp[0] = len_max; //转换为字符数组形式 begin = num_tmp[0]; _for(i, begin, 1) { ans[cnt++] = num_tmp[i] + '0'; } ans[0] = '+'; } }

    高精度减法

    #include"calculator.h" #include"high_precision_algorithm.h" void subtract(char *ans, char *num) { //输入保证ans[0],num[0]均为+ //位数相同,首位大的减小的,位数不同,位数多的减少的,最后决定加不加负号 int cnt, begin, tag; int i, flag_b, flag_c; int num_b[100], num_c[100], num_tmp[100]; cnt = 1; flag_b = ans[0]=='-'?1:0;//ans的负数标记 flag_c = num[0]=='-'?1:0;//num的负数标记 if(flag_b==0 && flag_c==1) //正-负 { num[0] = '+'; add(ans, num); } else if(flag_b==1 && flag_c==0) //负-正 { ans[0] = '+'; add(ans, num); ans[0] = '-'; } else if(flag_b==1 && flag_c==1) //负-负 { ans[0] = '+'; num[0] = '+'; subtract(ans, num); if(ans[0] == '+') ans[0] = '-'; else if(ans[0] == '-') ans[0] = '+'; } else if(flag_b==0 && flag_c==0) //正-正 { memset(num_b, 0, sizeof(num_b)); memset(num_c, 0, sizeof(num_c)); memset(num_tmp, 0, sizeof(num_tmp)); tag = compare(ans, num);//判断大小 str_to_num(ans, num_b), memset(ans, 0, strlen(ans)); str_to_num(num, num_c); if(tag == 0) ans[0] = '+', ans[1]='0'; else if(tag == 1)//ans>num { _FOR(i, 1, num_b[0]) { if(num_b[i] < num_c[i]) { num_b[i+1]--; num_b[i] += 10; } num_tmp[i] = num_b[i] - num_c[i]; } begin = num_b[0]; while(num_tmp[begin] == 0) begin--; _for(i, begin, 1) { ans[cnt++] = num_tmp[i] +'0'; } ans[0] = '+'; } else //ans<num { _FOR(i, 0, num_c[0]) { if(num_c[i] < num_b[i]) { num_c[i+1]--; num_c[i] += 10; } num_tmp[i] = num_c[i] - num_b[i]; } begin = num_c[0]; while(num_tmp[begin] == 0) begin--; _for(i, begin, 1) { ans[cnt++] = num_tmp[i] +'0'; } ans[0] = '-'; } } }

    高精度乘法

    #include"calculator.h" #include"high_precision_algorithm.h" void multiply(char *ans, char *num) { int cnt, begin; int i, j, flag_b, flag_c; int str_len = 0, str_all_len = 0; int num_b[100], num_c[100], num_tmp[100]; char str_all[200], str[200]; cnt = 1; flag_b = ans[0]=='-'?1:0;//ans的负数标记 flag_c = num[0]=='-'?1:0;//num的负数标记 if(flag_b==0 && flag_c==1) //正*负 { num[0] = '+'; multiply(ans, num); ans[0] = '-'; } else if(flag_b==1 && flag_c==0) //负*正 { ans[0] = '+'; multiply(ans, num); ans[0] = '-'; } else if(flag_b==1 && flag_c==1) //负*负 { ans[0] = '+'; num[0] = '+'; multiply(ans, num); ans[0] = '+'; } else if(flag_b==0 && flag_c==0) //正*正 { memset(num_b, 0, sizeof(num_b)); memset(num_c, 0, sizeof(num_c)); memset(num_tmp, 0, sizeof(num_tmp)); str_to_num(ans, num_b), memset(ans, 0, strlen(ans)); str_to_num(num, num_c); _FOR(i, 1, num_b[0]) { _FOR(j, 1, num_c[0]) { num_tmp[i+j] += num_b[i]*num_c[j]%10; num_tmp[i+j+1] += num_b[i]*num_c[j]/10; } } //确定终点 begin = num_b[0] + num_c[0] + 1;//2; while(num_tmp[begin]==0 && begin>2) begin--; //处理进位 _FOR(i, 2, begin) { if(num_tmp[i] >= 10) { num_tmp[i+1] += num_tmp[i] / 10; num_tmp[i] %=10; if(i == begin) { begin++; } } } _for(i, begin, 2) ans[cnt++] = num_tmp[i] + '0'; ans[0] = '+'; } }

    高精度除法

    #include"calculator.h" #include"high_precision_algorithm.h" void division(char *ans, char *num) { int cnt, begin; int i, j, flag_b, flag_c; int len_tmp, digits;//ans比num多出来的位数 int str_len = 0, str_all_len = 0; int num_b[100], num_c[100], num_tmp[100]; cnt = 1; flag_b = ans[0]=='-'?1:0;//ans的负数标记 flag_c = num[0]=='-'?1:0;//num的负数标记 memset(num_b, 0, sizeof(num_b)); memset(num_c, 0, sizeof(num_c)); memset(num_tmp, 0, sizeof(num_tmp)); if(flag_b==0 && flag_c==1) // 正/负 { num[0] = '+'; division(ans, num); ans[0] = '-'; } else if(flag_b==1 && flag_c==0) // 负/正 { ans[0] = '+'; division(ans, num); ans[0] = '-'; } else if(flag_b==1 && flag_c==1) // 负/负 { ans[0] = '+'; num[0] = '+'; division(ans, num); ans[0] = '+'; } else if(flag_b==0 && flag_c==0) // 正/正 { memset(num_b, 0, sizeof(num_b)); memset(num_c, 0, sizeof(num_c)); memset(num_tmp, 0, sizeof(num_tmp)); str_to_num(ans, num_b); str_to_num(num, num_c); digits = num_b[0] - num_c[0]; if(compare(ans, num) == 0) memset(ans, 0, strlen(ans)), ans[0] = '+', ans[1] = '1'; else if(compare(ans, num) == -1) memset(ans, 0, strlen(ans)), ans[0] = '+', ans[1] = '0'; else //ans > num { //将num补位与ans位数相等 _for(i, num_b[0], 1) { if(i > digits) num_c[i] = num_c[i - digits]; else num_c[i] = 0; } num_c[0] = num_b[0]; //减法模拟除法 _FOR(i, 1, digits+1) { while((len_tmp = SubStract(num_b, num_c)) >= 0) { num_tmp[digits + 2 - i]++; } num_c[0]--; _FOR(j, 1, num_c[0]) num_c[j] = num_c[j+1]; num_c[num_c[0]+1] = 0; } //确定位数 begin = digits + 1; while(num_tmp[begin] == 0 && begin > 1) begin--; num_tmp[0] = begin; //结果保存到ans memset(ans, 0, strlen(ans)); _for(i, num_tmp[0], 1) { ans[cnt++] = num_tmp[i] + '0'; } ans[0] = '+'; } } }

    高精度取余

    #include"calculator.h" #include"high_precision_algorithm.h" void mod(char *ans, char *num) { char ans_tmp[100]; memset(ans_tmp, 0, sizeof(ans_tmp)); strcpy(ans_tmp, ans); division(ans_tmp, num); multiply(ans_tmp, num); subtract(ans, ans_tmp); }

    里面自定义的一些函数

    比较两数大小

    #include"calculator.h" #include"high_precision_algorithm.h" int compare(char *num_b, char *num_c) { //输入保证num_b[0]和num_c[0]均为+ if(strlen(num_b) == strlen(num_c)) { if(strcmp(num_b, num_c) == 0) return 0; else if(strcmp(num_b, num_c) > 0) return 1; else return -1; } else if(strlen(num_b) > strlen(num_c)) return 1; else return -1; }

    将数据写入数组

    #include"calculator.h" #include"high_precision_algorithm.h" void input_num(char *str, char *str_all, int &str_len, int &str_all_len, char num) { str[str_len++] = num; str_all[str_all_len++] = num; }

    字符串转变为数字

    #include"calculator.h" #include"high_precision_algorithm.h" void str_to_num(char *str, int *num) { int i, cnt, len; int end, size; size = 0; cnt = 1; len = strlen(str); if(str[0]=='+' || str[0]=='-') end = 1; else end = 0; _for(i, len-1, end) { num[cnt++] = str[i]-'0'; size++; } num[0] = size; }

    除法中用到的减法(如果不明白这个“减法”,再理解下高精度除法的思想)

    #include"calculator.h" #include"high_precision_algorithm.h" int SubStract(int *num_b, int *num_c)//返回numb-numc结果的长度 { int i; int len_b = num_b[0]; int len_c = num_c[0]; if(len_b < len_c) return -1; else if(len_b == len_c) { _for(i, len_b, 1) { if(num_b[i] > num_c[i]) break; else if(num_b[i] < num_c[i]) return -1; } } _FOR(i, 1, len_b)//能够进行到这里说明lenb >= len_c { if(num_b[i] < num_c[i]) { num_b[i+1]--; num_b[i] += 10; } num_b[i] -= num_c[i]; } _for(i, len_b, 1) { if(num_b[i] != 0) { num_b[0] = i; return i; } } num_b[0] = 0; return 0; }
    Processed: 0.020, SQL: 9