代码仓库地址:https://dev.tencent.com/u/qingYinGuo/p/software_homework/git
测试效果见result.txt文件
一、 需求分析与功能设计
任务1:
使用JAVA编程语言,独立完成一个3到5个运算符的四则运算练习的软件。
软件基本功能要求如下:
- 程序可接收一个输入参数n,然后随机产生n道加减乘除(分别使用符号+-*÷来表示)练习题,每个数字在 0 和 100 之间,运算符在3个到5个之间。
- 每个练习题至少要包含2种运算符。同时,由于小学生没有分数与负数的概念,你所出的练习题在运算过程中不得出现负数与非整数,比如不能出 3÷5+2=2.6,2-5+10=7等算式。
- 练习题生成好后,将你的学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt”中,不要输出额外信息,文件目录与程序目录一致。
- 当程序接收的参数为4时,以下为一个输出文件示例。
2018010203
13+17-1=29
11*15-5=160
3+10+4-16=1
15÷5+3-2=4
软件附加功能要求如下:(请有余力的同学完成)
- 支持有括号的运算式,包括出题与求解正确答案。注意,算式中存在的括号数必须大于2对,且不得超过运算符的个数。
- 扩展程序功能支持真分数的出题与运算(只需要涵盖加减法即可),例如:1/6 + 1/8 + 2/3= 23/24。注意在实现本功能时,需支持运算时分数的自动化简,比如 1/2+1/6=2/3,而非4/6,且计算过程中与结果都须为真分数。
二、 设计实现
项目的目录结构
- Main类:主类,负责接收命令行的参数并启动程序。
- GenerateFile类:创建文件类,负责每次出题类型并产生result.text文件,将学号与练习题写入文件。
- GenerateFormula类:式子类,负责根据调用产生各类型的式子,简单四则运算、带括号的四则运算、真分数加减运算。
- Calculator类:计算类,负责各种计算,含有结果运算、有条件产生减数、有条件产生除数、有条件产生分子、有条件产生分母、判断数的大小、求取最大公因数、求取最小公倍数、分数相加、分数相减等方法。
二、收获点
1.利用js的eval函数对生成的四则运算进行计算,简化了很多的代码
static ScriptEngine scriptEngine=
new ScriptEngineManager().getEngineByName("JavaScript");
public static Object calulate(String str){
//为什么定义时一定要带上=0?
Object result=0;
try {
result=scriptEngine.eval(str);
} catch (ScriptException e) {
e.printStackTrace();
}
return result;
}
2.最小公倍数简单算法的实现
//最小公倍数
public static int lcm(int num1,int num2){
int lcm=num1;
while(lcm%num1!=0||lcm%num2!=0){
lcm++;
}
return lcm;
}
3.对小数的判断
// 对于小数的判断
public static boolean decimals(String result){
boolean hasDecimals=false;
if (result.contains(".")){
hasDecimals=true;
}
return hasDecimals;
}
4.最大公因数
// 对于小数的判断
public static boolean decimals(String result){
boolean hasDecimals=false;
if (result.contains(".")){
hasDecimals=true;
}
return hasDecimals;
}
三、整个项目最麻烦也最关键的生成计算式的类
public class GenerateFormula {
//形成运算式子
public static String simpleArithmetic(){
//标准形式
char[] stanSympol = new char[] { '*', '+', '/', '-' };
//输出形式
char[] outSympol = new char[] { '*', '+', '÷', '-' };
String str1="";
String str2="";
//生成符号的个数
int symbolCount= (int) (Math.random()*3+3);
//生成数字数组
int num[]=new int[symbolCount+1];
for(int i=0;i<=symbolCount;i++){
num[i]= (int) (Math.random()*100+1);
}
//生成符号数组
//符号的个数比数字少一
int symbol[]=new int[symbolCount];
for (int i=0;i<symbolCount;i++){
if (i>0&&symbol[i-1]==3){
//减号之后必须是加号
symbol[i]=1;
}
else if(i>0&&symbol[i-1]==2){
//除号之后必须是乘法或加法
symbol[i]= (int) (Math.random()*2);
}
else {
symbol[i]= (int) (Math.random()*4);
}
str1+=String.valueOf(num[i])+String.valueOf(stanSympol[symbol[i]]);
str2+=String.valueOf(num[i])+String.valueOf(outSympol[symbol[i]]);
if (symbol[i]==2){
num[i+1]=Calculator.divisor(num[i],num[i+1]);
}
else if(symbol[i]==3){
num[i+1]=Calculator.subtractor(num[i],num[i+1]);
}
}
int j=0;
while (j<(symbolCount-1)&&symbol[j]==symbol[j+1]){
j++;
}
if(j==(symbolCount-1)){
return simpleArithmetic();
}
else {
str1+=String.valueOf(num[symbolCount]);
str2+=String.valueOf(num[symbolCount]);
return str2+"="+Calculator.calulate(str1);
}
}
//生成分数
public static String fraction(){
char[] symbol={'+','-'};
String str="";
int symCount= (int) (Math.random()*3+3);
//分子
int x[]=new int[symCount+1];
//分母
int y[]=new int[symCount+1];
//符号集
int z[]=new int[symCount];
//中间运算结果
int mid[]=new int[2];
//生成分数数字集
for (int i=0;i<=symCount;i++){
x[i]= (int) (Math.random()*35+1);
y[i]=Calculator.stfraction(x[i]);
}
mid[0]=x[0];
mid[1]=y[1];
//生成符号集
for (int i=0;i<symCount;i++){
z[i]= (int) (Math.random()*2);
if (z[i]==0){
int a1[]=new int[2];
a1=Calculator.addFraction(mid[0],mid[1],x[i+1],y[i+1]);
//中间的运算结果也要为真分数
if (a1[0]>=a1[1]){
z[i]=1;
}
else {
mid=a1;
}
}
if (z[1]==1){
int a1[]=new int[2];
a1=Calculator.subFraction(mid[0],mid[1],x[i+1],y[i+1]);
if (a1[0]<0){
x[i+1]=Calculator.stfraction2(mid[0],mid[1]);
y[i+1]=mid[1];
a1=Calculator.subFraction(mid[0],mid[1],x[i+1],y[i+1]);
}
mid=a1;
}
str+=String.valueOf(x[i])+"/"+String.valueOf(y[i])+String.valueOf(symbol[z[i]]);
}
int j=0;
while (j<(symCount-1)&&z[j]==z[j+1]){
j++;
}
if (j==(symCount-1)) {
return fraction();
}
else {
str+=String.valueOf(x[symCount])+"/"+String.valueOf(y[symCount]);
return str+"="+mid[0]+"/"+mid[1];
}
}
//随机产生括号的四则运算
public static String addBracket() {
//标准形式
char[] stanSympol = new char[]{'*', '+', '/', '-'};
//输出形式
char[] outSympol = new char[]{'*', '+', '÷', '-'};
String str1 = "";
String str2 = "";
//生成括号的个数
int bracket = 0;
//未匹配的左括号的个数
int bracket_left = 0;
//符号个数
int symCount = (int) (Math.random() * 3 + 3);
//存储符号的数组
int[] symbol = new int[symCount];
//存储数字的数组
int[] num = new int[symCount + 1];
//随机产生数字
for (int i = 0; i <= symCount; i++) {
num[i] = (int) (Math.random() * 100 + 1);
}
//随机生成符号
for (int j = 0; j <= (symCount - 1); j++) {
symbol[j] = (int) (Math.random() * 4);
}
//形成运算式
for (int i = 1; i <= (symCount - 1); i++) {
//减数时防止产生负数
if (symbol[i] == 3) {
num[i] = Calculator.subtractor(num[i - 1], num[i]);
} else if (symbol[i] == 2) {
num[i] = (int) (Math.random() * 100 + 1);
}
str1 += num[i];
str2 += num[i];
int bracket_left1 = bracket_left;
for (int j = 0; j < bracket_left1; j++) {
if ((int) (Math.random() * 3) > 1) {
bracket_left--;
str1 += ")";
str2 += ")";
}
}
str1 += stanSympol[symbol[i]];
str2 += outSympol[symbol[i]];
if (((bracket * 2) <= symCount) && (((int) (Math.random() * 9)) > 1)) {
str1 += "(";
str2 += "(";
bracket++;
bracket_left++;
str1 += num[++i];
str2 += num[i];
str1 += stanSympol[symbol[i - 1]];
str2 += outSympol[symbol[i - 1]];
}
}
int k = 0;
while (k != symCount) {
if (symbol[k] == 3) {
num[k + 1] = Calculator.subtractor(num[k], num[k + 1]);
} else if (symbol[k] == 2) {
num[k + 1] = (int) (Math.random() * 100 + 1);
}
str1 += num[k];
str2 += num[k];
str1 += stanSympol[symbol[k]];
str2 += outSympol[symbol[k]];
k++;
}
if (symbol[symCount - 1] == 3) {
num[symCount] = Calculator.subtractor(num[symCount - 1], num[symCount]);
}
str1 += num[symCount];
str2 += num[symCount];
while (bracket_left != 0) {
str1 += ")";
str2 += ")";
bracket_left--;
}
str2 += "=";
String result = String.valueOf(Calculator.calulate(str1));
if (Calculator.decimals(result) || result.contains("Infinity")) {
return addBracket();
} else if (bracket >= 2) {
int result1 = Integer.parseInt(result);
if (result1 < 0) {
return addBracket();
} else {
return str2 + result;
}
}
else {
return addBracket();
}
}
}
5.本地命令行运行报错
a.中文乱码
b.编译问题
四、总结
这个项目我开始想的时候式很简单的,但是真正写起来才发现并不如我所想的那样简单。开始写简单四则运算的时候,我就开始要写代码的数量发愁,偶然发现了eval()方法,心底真的式发出了感叹,居然会有如此神奇的算法,编程世界的前辈们真的是太优秀啦!
有了这种方法的帮助,四则运算也很快的就完成了。对于附加功能的实现,我是借鉴了学长学姐的方法,当然。我相信只要给我时间,拥有耐心,我相信,我也是可以成功实现的。前辈们的方法好则好矣,却是使我减少了思考过程的探险,少了许多项目完成时的欣喜。