java pdb_小学四则运算生成Java实现 (pdb ly)

Java实现小学四则运算

by PDB LY

项目要求

题目:实现一个自动生成小学四则运算题目的命令行程序

功能列表

[完成] 使用 -n 参数控制生成题目的个数。

[完成] 使用 -r 参数控制题目中数值的范围。

[完成] 生成的题目中计算过程不能产生负数。

[完成] 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。

[完成] 程序一次运行生成的题目不能重复,生成的题目存入执行程序的当前目录下的Exercises.txt文件。

[完成] 每道题目中出现的运算符个数不超过3个。

[完成] 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件。

[完成] 程序应能支持一万道题目的生成。

[完成] 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。

设计实现

1.表达式生成:根据输入的两个参数决定表达式的数量及数值范围,随机生成数值范围内的自然数及运算符,随机插入左括号并在相应的位置插入右括号。

2.分数:专门写了一个类Fraction来生成分数,并且有约分的功能。

3.负数:负数只会在减法运算时产生,每当遇到减法运算时,若运算结果出现负数,就重新生成新的表达式。

4.计算:将整数也当成分数进行计算,先将上面生成的表达式(以字符串存储)分别入数字栈和符号栈,再根据符号优先级计算最终结果。

953519f4a9e0d64580fdadcd869212c9.png

代码

分数类

public class Fraction {

int x;//分子

int y;//分母

private Fraction temp;

public Fraction(int a, int b) {

x = a;

y = b;

}

Fraction add(Fraction r) {

temp = new Fraction(0, 0);

temp.x = x * r.y + y * r.x;

temp.y = y * r.y;

return temp;

}

Fraction minus(Fraction r) {

temp = new Fraction(0, 0);

temp.x = x * r.y - y * r.x;

temp.y = y * r.y;

return temp;

}

Fraction multiply(Fraction r) {

temp = new Fraction(0, 0);

temp.x = x * r.x;

temp.y = y * r.y;

return temp;

}

Fraction divide(Fraction r) {

temp = new Fraction(0, 0);

temp.x = x * r.y;

temp.y = y * r.x;

return temp;

}

String print() {

/**

* 计算结果化简

*/

if (x == 0) {

return "0";

} else {

int n;

if (x > y)

n = x;

else

n = y;

int maxn = 0;

for (int i = 1; i <= n; ++i) { //约分

if (x % i == 0 && y % i == 0)

maxn = i;

}

int a = x / maxn;

int b = y / maxn;

if (a == b)

return "1";

else if(b==1)

return a+"";

else

return a + "/" + b;

}

}

}

表达式生成

public class CreateExercise {

String[] sign = {"+", "-", "x", "÷", "/"};

int range_num;

Random random = new Random();

public void setRange_num(int range_num) {

this.range_num =range_num;

}

public String create() {

String str = "";

int local = random.nextInt(3);

for (int j = 0; j < 3; j++) {

if (local == 0 && j == 0) {

str += "(";

} else if (local == 2 && j == 1) {

str += "(";

}

str += random.nextInt(range_num) % range_num + 1; //产生指定范围随机数

if (local == 0 && j == 1) {

str += ")";

}

if (local == 2 && j == 2) {

str += ")";

}

String signElement = sign[random.nextInt(5)];//产生随机运算符号

str += signElement;

if (signElement == "/") {

str += random.nextInt(range_num) % range_num + 1;

signElement = sign[random.nextInt(5)];

while (true) {

if (signElement != "/") {

str += signElement;

break;

}

signElement = sign[random.nextInt(5)];

}

}

}

str = str.substring(0, str.length() - 1);

return str;

}

public void belongFraction(String strfraction) {

/**

* 处理分数计算

*/

String[] fractionlist = null;

if (strfraction.contains("+")) {

fractionlist = strfraction.split("\\+");

CalculateFraction(fractionlist, 0);

} else if (strfraction.contains("-")) {

fractionlist = strfraction.split("-");

CalculateFraction(fractionlist, 1);

} else if (strfraction.contains("x")) {

fractionlist = strfraction.split("\\x");

CalculateFraction(fractionlist, 2);

} else if (strfraction.contains("÷")) {

fractionlist = strfraction.split("÷");

CalculateFraction(fractionlist, 3);

}

}

public void CalculateFraction(String[] strlist, int flag) {

/**

* 分数的四种基本运算

*/

String[] fraction1 = new String[2];

String[] fraction2 = new String[2];

if (strlist[0].contains("/"))

fraction1 = strlist[0].split("/");

else {

fraction1[0] = strlist[0];

fraction1[1] = "1";

}

if (strlist[1].contains("/"))

fraction2 = strlist[1].split("/");

else {

fraction2[0] = strlist[1];

fraction2[1] = "1";

}

Fraction fr1 = new Fraction(Integer.parseInt(fraction1[0]), Integer.parseInt(fraction1[1]));

Fraction fr2 = new Fraction(Integer.parseInt(fraction2[0]), Integer.parseInt(fraction2[1]));

fr1.print();

switch (flag) {

case 0:

fr1.add(fr2).print();

break;

case 1:

fr1.minus(fr2).print();

break;

case 2:

fr1.multiply(fr2).print();

break;

case 3:

fr1.divide(fr2).print();

break;

}

}

}

计算

public class Calculator {

/**

* 数字栈:存储表达式中的数字

*/

private Stack numStack = null;

/**

* 符号栈:存储表达式中的运算符和括号

*/

private Stack charStack = null;

/**

* 计算四则运算表达式,返回计算结果

*

*/

public String calculate(String numStr) {

numStr = removeStrSpace(numStr);

if (numStr.length() > 1 && !"=".equals(numStr.charAt(numStr.length() - 1) + "")) {

numStr += "=";

}

if (!isStandard(numStr)) {

return "0";

}

numStack = new Stack();

charStack = new Stack();

StringBuffer temp = new StringBuffer();

for (int i = 0; i < numStr.length(); i++) {

char ch = numStr.charAt(i);

if (isNumber(ch) || ch == '/') {

temp.append(ch);

} else {

String tempStr = temp.toString();

if (!tempStr.isEmpty()) {

numStack.push(tempStr);

temp = new StringBuffer();

}

while (!comparePri(ch) && !charStack.empty()) {

String a = numStack.pop();

String b = numStack.pop();

Fraction f1 = null;

Fraction f2 = null;

if (a.contains("/")) {

String[] alist = a.split("/");

f1 = new Fraction(Integer.parseInt(alist[0]), Integer.parseInt(alist[1]));

} else {

f1 = new Fraction(Integer.parseInt(a), 1);

}

if (b.contains("/")) {

String[] blist = b.split("/");

f2 = new Fraction(Integer.parseInt(blist[0]), Integer.parseInt(blist[1]));

} else {

f2 = new Fraction(Integer.parseInt(b), 1);

}

switch (charStack.pop()) {

case '+':

numStack.push(f2.add(f1).print());

break;

case '-':

if ((f1.x/f1.y) >= (f2.x/f2.y)) {

return null;

}

numStack.push(f2.minus(f1).print());

break;

case 'x':

numStack.push(f2.multiply(f1).print());

break;

case '÷':

if (f1.x==0){

return null;

}

numStack.push(f2.divide(f1).print());

break;

default:

break;

}

}

if (ch != '=') {

charStack.push(new Character(ch));

if (ch == ')') {

charStack.pop();

charStack.pop();

}

}

}

}

return numStack.pop();

}

private String removeStrSpace(String str) {

return str != null ? str.replaceAll(" ", "") : "";

}

private boolean isStandard(String numStr) {

if (numStr == null || numStr.isEmpty())

return false;

Stack stack = new Stack();

boolean b = false;

for (int i = 0; i < numStr.length(); i++) {

char n = numStr.charAt(i);

if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "")

|| "+".equals(n + "") || "-".equals(n + "")

|| "x".equals(n + "") || "÷".equals(n + "") || "/".equals(n + "")

|| "=".equals(n + ""))) {

return false;

}

if ("(".equals(n + "")) {

stack.push(n);

}

if (")".equals(n + "")) {

if (stack.isEmpty() || !"(".equals((char) stack.pop() + ""))

return false;

}

if ("=".equals(n + "")) {

if (b)

return false;

b = true;

}

}

if (!stack.isEmpty())

return false;

if (!("=".equals(numStr.charAt(numStr.length() - 1) + "")))

return false;

return true;

}

private boolean isNumber(char num) {

if (num >= '0' && num <= '9')

return true;

return false;

}

/**

* 比较优先级:如果当前运算符比栈顶元素运算符优先级高则返回true,否则返回false

*/

private boolean comparePri(char symbol) {

if (charStack.empty()) {

return true;

}

char top = charStack.peek();

if (top == '(') {

return true;

}

switch (symbol) {

case '(':

return true;

case 'x': {

if (top == '+' || top == '-')

return true;

else

return false;

}

case '÷': {

if (top == '+' || top == '-')

return true;

else

return false;

}

case '+':

return false;

case '-':

return false;

case ')':

return false;

case '=':

return false;

default:

break;

}

return true;

}

String getFinalResult(String str) {

if (!str.contains("/"))

return str;

String[] part = str.split("/");

int a = Integer.parseInt(part[0]);

int b = Integer.parseInt(part[1]);

if (a == b)

return "1";

else if (a > b && a % b != 0) {

return a / b + "’" + a % b + "/" + b;

} else if (a < b && -a > b && (-a) % b != 0) {

return "-" + (-a) / b + "’" + (-a) % b + "/" + b;

} else if (b == 1)

return a + "";

else

return a + "/" + b;

}

}

生成txt文本

public class IO {

File ExerciseFile = null;

File AnswerFile = null;

String filename = "";

BufferedWriter ExerciseOut = null;

BufferedWriter AnswerOut = null;

public IO() {

if (this.CreateFile()) {

this.setOutBufferedWriter();

} else

System.out.println("创建文件失败!");

}

public void setOutBufferedWriter() {

try {

this.ExerciseOut = new BufferedWriter(new FileWriter(ExerciseFile));

this.AnswerOut=new BufferedWriter(new FileWriter(AnswerFile));

} catch (IOException e) {

e.printStackTrace();

}

}

public boolean CreateFile() {

String relativelyPath=System.getProperty("user.dir");

ExerciseFile = new File(relativelyPath+"\\Exercise" + ".txt");

AnswerFile = new File(relativelyPath+"\\Answer" + ".txt");

if (ExerciseFile.exists()) {

ExerciseFile.delete();

}

if (AnswerFile.exists()) {

AnswerFile.delete();

}

try {

ExerciseFile.createNewFile();

AnswerFile.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

return true;

}

public boolean WriteToFile(String content, int flag) {

try {

switch (flag) {

case 0:

ExerciseOut.write(content);

ExerciseOut.write("\r\n");

ExerciseOut.flush();

return true;

case 1:

AnswerOut.write(content);

AnswerOut.write("\r\n");

AnswerOut.flush();

return true;

}

} catch (IOException e) {

e.printStackTrace();

}

return false;

}

public boolean CloseOutBufferedWriter() {

try {

ExerciseOut.close();

AnswerOut.close();

return true;

} catch (IOException e) {

e.printStackTrace();

}

return false;

}

}

主函数启动类

public class MyApp {

public static void main(String[] args) {

Scanner scan = new Scanner(System.in);

System.out.print("请输入希望生成的题目数量:");

int problems_num = scan.nextInt();

System.out.print("请输入题目的数值范围n(范围为0到n):");

int range_num = scan.nextInt();

System.out.print("是否开始答题(yes/no):");

String is_doNow=scan.next();

LinkedHashMap rightAnswerMap = new LinkedHashMap();

LinkedHashMap exerciseMap = new LinkedHashMap();

ArrayList rightRecord = new ArrayList();

ArrayList wrongRecord = new ArrayList();

CreateExercise ce = new CreateExercise();

IO save = new IO();

ce.setRange_num(range_num);

for (int i = 1; i <= problems_num; i++) {

String problem = ce.create();

exerciseMap.put(i,problem);

String ns = problem;

int rightbrackets;

int leftbrackets;

if (problem.contains(")")) {

rightbrackets = problem.indexOf(")");

leftbrackets = problem.indexOf("(");

if (rightbrackets != problem.length() - 1 && problem.charAt(rightbrackets + 1) == '/') {

StringBuilder sb = new StringBuilder(problem);

if (leftbrackets - 1 > 0 && problem.charAt(leftbrackets - 1) == '÷')

sb.replace(rightbrackets + 1, rightbrackets + 2, "x");

else

sb.replace(rightbrackets + 1, rightbrackets + 2, "÷");

ns = sb.toString();

}

}

Calculator cal = new Calculator();

String result = cal.calculate(ns);

if (result != null) {

result = cal.getFinalResult(result);

System.out.println(i + ": " + problem + "=" );

rightAnswerMap.put(i, result);

if (!save.WriteToFile(i + ": " + problem + "=", 0)) {

System.out.println("生成Exercise文件失败!");

System.exit(0);

}

if (!save.WriteToFile(+ i + ": " + problem + "=" + result, 1)) {

System.out.println("生成Answer文件失败!");

System.exit(0);

}

} else {

i--;

}

}

if(is_doNow.equals("yes")){

System.out.println("请输入答案(带分数用“ ’ ”分隔,如1’1/2):");

for (int i = 1; i <= problems_num; i++) {

System.out.print( + i + ": " + exerciseMap.get(i) + "=");

String input = scan.next();

if (rightAnswerMap.get(i).equals(input))

rightRecord.add(i);

else

wrongRecord.add(i);

}

System.out.println("结果为:");

if (rightRecord.size()!=0){

System.out.print("正确题目:"+rightRecord.size()+" (");

for (int i=0;i

System.out.print(rightRecord.get(i)+",");

System.out.println(rightRecord.get(rightRecord.size()-1)+")");

}

else

System.out.println("正确题目:"+rightRecord.size());

if (wrongRecord.size()!=0){

System.out.print("错误题目:"+wrongRecord.size()+" (");

for (int i=0;i

System.out.print(wrongRecord.get(i)+",");

System.out.println(wrongRecord.get(wrongRecord.size()-1)+")");

}

else

System.out.println("错误题目:"+wrongRecord.size());

}

if (save.CloseOutBufferedWriter())

System.out.println("题目和答案文本创建成功");

else

System.out.println("题目和答案文本创建失败");

}

}

测试运行

生成10000道题目

94c4853916e122e5322b20049e2683d9.png

部分题目及答案

0560643a887fbf543972c47ea7690c74.png

答案统计

29963e89bbc74cb8e00b1db82c6db7c6.png

故意答错 1,3题

59ff857b9c853708a42dd365bafd7fe0.png

代码覆盖率

884af28ce9b24bd2701b25179de98484.png

PSP

PSP2.1

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

60

120

· Estimate

· 估计这个任务需要多少时间

30

60

Development

开发

1000

2200

· Analysis

· 需求分析 (包括学习新技术)

100

180

· Design Spec

· 生成设计文档

60

100

· Design Review

· 设计复审 (和同事审核设计文档)

30

30

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

30

30

· Design

· 具体设计

120

150

· Coding

· 具体编码

600

1500

· Code Review

· 代码复审

50

60

· Test

· 测试(自我测试,修改代码,提交修改)

150

60

Reporting

报告

80

80

· Test Report

· 测试报告

30

40

· Size Measurement

· 计算工作量

20

10

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

40

20

合计

1150

2400

总结

此次的结对编程,我主要负责表达式的生成、计算,李尤同学主要负责文件生成的IO,我们都相互审阅了对方的代码。刚拿到题目的时候,我们的思路并不是很清晰,对于表达式的计算及负数的避免想要直接实现,尝试过后发现过于麻烦,后来与李尤同学讨论后发现使用数据结构的栈来实现会简单很多,可以说这次的结对编程,通过两个人的讨论,使得项目的整体思路变得很清晰,实现起来也更加容易。此次编程较为遗憾的没有实现题目的查重功能,我们以后会继续努力完善这个功能。李尤同学的思维很活跃,经常有一些天马行空的想法,在编写程序的过程中给了我很多启发。这次的结对编程,让我体会到了合作的力量,同时也认识到了自己数据结构方面知识的不足,今后会多加学习这方面的知识,完善自己的不足。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
04-12 2700

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值