个人项目实战-四则混合运算

代码仓库地址:https://dev.tencent.com/u/qingYinGuo/p/software_homework/git

测试效果见result.txt文件

一、 需求分析与功能设计

任务1

    使用JAVA编程语言,独立完成一个35个运算符的四则运算练习的软件。

软件基本功能要求如下:

  • 程序可接收一个输入参数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()方法,心底真的式发出了感叹,居然会有如此神奇的算法,编程世界的前辈们真的是太优秀啦!

有了这种方法的帮助,四则运算也很快的就完成了。对于附加功能的实现,我是借鉴了学长学姐的方法,当然。我相信只要给我时间,拥有耐心,我相信,我也是可以成功实现的。前辈们的方法好则好矣,却是使我减少了思考过程的探险,少了许多项目完成时的欣喜。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值