项目源码地址:https://git.dev.tencent.com/weizh588/sizeyunsuan.git
一、需求分析
- 程序可从命令行接收一个输入参数n,然后随机产生n道加减乘除练习题。
- 每个数字在0和100之间,运算符3个到5个之间。
- 每个练习题至少要包含2种运算符。
- 所出的练习题在运算过程中不得出现负数与非整数。
- 将学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt”中。
- 支持有括号的运算式,包括出题与求解正确答案。注意,算式中存在的括号必须大于2个,且不得超过运算符的个数。(附加)
- 支持真分数的出题与运算(只需要涵盖加减法即可),且支持分数的自动化简。(附加)
二、功能设计
- 基本功能:实现四则运算的功能,并能够将题目输出到文本文件中。
- 扩展功能:能够随机产生带有括号的运算式。可以生成可以真分数的运算表达式,且分数可以自动化简。
三、设计实现
考虑到程序的可扩展性,我将程序分为以下的几个类
-
Main类:主要是用来控制命令行的输入,以及对输入格式的规定和限制。
-
FileCreate类:主要的功能实现部分。其中的getFile()函数用来生成运算式并生成得到txt文件。
-
Easy类 :实现简单的四则运算逻辑
-
Complex 类:“实现” 加括号的复杂的四则运算
-
calculate 类:做临时的一些运算处理
各类之间的逻辑关系图:
四、算法详解
简单的四则运算:
// 输出看的字符
List see =new ArrayList<>();
see.add('*');see.add('+');see.add('÷');see.add('-');
//计算机能够识别的字符
List result =new ArrayList<>();
result.add('*');
result.add('+');
result.add('/');
result.add('-');
//储存临时运算符号
List key =new ArrayList<>();
// key.add(0,"+");
//先初始化一个key
// key.set(0,result.get((int)(Math.random()*4)));
String tosee = "";
String toresult = "";
//符号的数量m
int m = (int) (Math.random() * 3 + 3);
//用来储存运算数的数组;
// List num=new ArrayList();
int[] num = new int[m + 1]; // 数字
//在0-100中随机生成
for (int i = 0; i <= m; i++) {
num[i] = (int) (Math.random() * 101);
}
for (int j=0;j<m;j++){
if(j>0&&key.get(j-1).equals('-')){
key.add(j,'+');
}
else if (j>0&&key.get(j-1).equals('/')){
key.add(j,result.get((int)(Math.random()*2)));
}
else
{
int k=(int)(Math.random()*4);
System.out.println(k);
key.add(j,result.get((int)(Math.random()*4)));
}
tosee += String.valueOf(num[j]) + String.valueOf(key.get(j));
toresult += String.valueOf(num[j]) + String.valueOf(key.get(j));
//开始要判断是否两个数为负数或者为分数
if (key.get(j).equals('-')){
num[j+1]= calculate.subtraction(num[j],num[j+1]);
}
if (key.get(j).equals('/')){
num[j+1]= calculate.division(num[j],num[j+1]);
}
}
//接下来要判断运算符是否符合要求
int count=0;
for (int i=0;i<key.size()-1;i++){
if (key.get(i)==key.get(i+1)){
count++;
}
}
//如果count==运算符数量m 即表示所有的符号都是一样的,重新再来
if (count==m){
return arithmetic();
}
else {
tosee+=String.valueOf(num[m]);
toresult+=String.valueOf(num[m]);
return tosee + "=" + calculate.result(toresult);
}
有括号的四则运算:
/**
* 带有括号的四则运算
*/
public static String bracket() {
int flag = 0; // 用来防止出现除0错误
int brack_left = 0; // 记录未匹配的左括号个数
int count = 0; // 括号个数
int op;
char result[] = { '+', '-', '*', '/' };
char see[] = { '+', '-', '*', '÷' };
String temp1 = "";
String temp2 = "";
int n = (int) (Math.random() * 3 + 4); // 数字个数
int[] num = new int[n];
for (int j = 0; j < n; j++) {
num[j] = (int) (Math.random() * 101); // 数字
}
int i;
for (i = 0; i < (n - 2); i++) { // 循环生成算式
if (flag == 1) { // 若此时需要生成的数字前的符号是'/',则需要特判此次生成的数字不能为0
flag = 0;
num[i] = (int) (Math.random() * 100 + 1);//不为0
} else if (flag == 2) {
flag = 0;
num[i] = calculate.subtraction(num[i - 1], num[i]); // 确保能够相减
}
temp1 += num[i];
temp2 += num[i];
int tmpcnt = brack_left;
for (int j = 0; j < tmpcnt; j++) { // 若当前有未匹配的左括号,则对每一个未匹配的左括号,都有一定概率生成相应右括号。
if ((int) (Math.random() * 5) > 1) { // 生成右括号概率为0.6
brack_left--;
temp1 += ")";
temp2 += ")";
}
}
op = (int) (Math.random() * 4); // 生成运算符
temp1 += result[op];
temp2 += see[op];
if (op == 3) // 若生成了除号,则需要置相应标志位
flag = 1;
else if (op == 1) // 若生成了减号,则需要置相应标志位
flag = 2;
if (((count * 2) <= (n - 1)) && (((int) (Math.random() * 2)) == 0)) { // 以一定概率生成左括号,概率为1/2
temp1 += "(";
temp2 += "(";
count++;
brack_left++;
temp1 += num[++i]; // 生成左括号后必须生成一个数字和运算符,不然可能出现(15)这样的错误
temp2 += num[i];
op = (int) (Math.random() * 4);
temp1 += result[op];
temp2 += see[op];
if (op == 3)
flag = 1;
else if (op == 1)
flag = 2;
}
}
while (i != (n - 1)) { // 判断是否为最后一个数
if (flag == 1) {
flag = 0;
num[i + 1] = (int) (Math.random() * 100 + 1);
} else if (flag == 2) {
flag = 0;
num[i + 1] = calculate.subtraction(num[i], num[i + 1]);
}
temp1 += num[i];
temp2 += num[i];
op = (int) (Math.random() * 4);
temp1 += result[op];
temp2 += see[op];
i++;
}
if (flag == 1) { // 最后不生出运算符
flag = 0;
num[n - 1] = (int) (Math.random() * 100 + 1);
} else if (flag == 2) {
flag = 0;
num[n - 1] = calculate.subtraction(num[n - 2], num[n - 1]);
}
temp1 += num[n - 1];
temp2 += num[n - 1];
while ((brack_left) != 0) { // 补全右括号
temp1 += ")";
temp2 += ")";
brack_left--;
}
temp2 += "=";
String result1 = String.valueOf(calculate.result(temp1));
if (calculate.judgeIsDecimal(result1) || result1.contains("Infinity") || result.equals("NaN")) {
return bracket();// 小数、无穷、非数处理
} else {
int result0 = Integer.valueOf(result1);
if (result0 < 0) {
return bracket();// 负数处理
} else {
return temp2 + result1;
}
}
}
五、测试运行
1、在命令行中的运行结果展示:
Complex单元测试:
cmd测试:
2、生成的txt文件展示: