小学题目加上括号,高中三角函数先精确计算再保留2位小数

liuyi_branch
柳意 2 months ago
parent 6dd2bf888b
commit 0a08b966c4

@ -46,12 +46,11 @@ public class QuestionGenerator {
private Question generatePrimaryQuestion(int index) {
int operandCount = random.nextInt(4) + 2; // 2-5个操作数
int[] operands = new int[operandCount];
int[] operations = new int[operandCount - 1]; // 操作符数组
int[] operations = new int[operandCount - 1];
String questionText;
int answer;
double answer;
// 生成合适的题目,确保计算过程中不出现负数
do {
// 生成操作数
for (int i = 0; i < operandCount; i++) {
@ -63,11 +62,27 @@ public class QuestionGenerator {
operations[i] = random.nextInt(4);
}
// 构建题目并计算答案
questionText = buildPrimaryQuestionText(operands, operations);
answer = calculatePrimaryAnswer(operands, operations);
// 改进的括号逻辑:在可能改变计算顺序的地方加括号
boolean useParentheses = random.nextDouble() < 0.3 && operandCount >= 3;
int parenStart = -1;
int parenEnd = -1;
if (useParentheses) {
// 寻找适合加括号的位置(加减法周围)
parenStart = findSuitableParenthesesPosition(operations);
if (parenStart != -1) {
// 括号包含2-3个操作数
parenEnd = parenStart + 1;
if (parenEnd < operands.length - 1 && random.nextBoolean()) {
parenEnd++;
}
}
}
} while (answer < 0 || !isValidPrimaryCalculation(operands, operations));
questionText = buildPrimaryQuestionText(operands, operations, parenStart, parenEnd);
answer = calculatePrimaryAnswerWithParentheses(operands, operations, parenStart, parenEnd);
} while (answer < 0 || Double.isNaN(answer) || Double.isInfinite(answer));
return generateOptions(questionText, answer, "小学");
}
@ -77,7 +92,7 @@ public class QuestionGenerator {
int[] operands = new int[operandCount];
int[] operations = new int[Math.max(0, operandCount - 1)]; // 操作符数组
boolean[] hasSpecialOp = new boolean[operandCount]; // 标记哪些操作数有平方或开根号
int[] specialOpTypes = new int[operandCount]; // 0:平方, 1:开根号 - 新增:记录具体操作类型
int[] specialOpTypes = new int[operandCount]; // 0:平方, 1:开根号
String questionText;
double answer;
@ -88,7 +103,7 @@ public class QuestionGenerator {
hasSpecialOp[i] = random.nextDouble() < 0.6; // 60%的概率有特殊运算
if (hasSpecialOp[i]) {
hasSpecialOperation = true;
specialOpTypes[i] = random.nextInt(2); // 随机选择平方或开根号,并记录下来
specialOpTypes[i] = random.nextInt(2); // 随机选择平方或开根号
}
}
@ -149,11 +164,16 @@ public class QuestionGenerator {
// 生成合适的题目
do {
// 生成操作数 (角度值,通常用特殊角度)
// 生成操作数
for (int i = 0; i < operandCount; i++) {
// 使用常见角度0, 30, 45, 60, 90等
int[] commonAngles = {0, 30, 45, 60, 90, 120, 135, 150, 180};
operands[i] = commonAngles[random.nextInt(commonAngles.length)];
if (hasTrigOp[i]) {
// 三角函数使用特殊角度值
int[] specialAngles = {0, 15, 30, 45, 60, 75, 90};
operands[i] = specialAngles[random.nextInt(specialAngles.length)];
} else {
// 普通操作数使用1-100的随机数
operands[i] = random.nextInt(100) + 1;
}
}
// 生成操作符 (0: +, 1: -, 2: *, 3: /)
@ -167,31 +187,69 @@ public class QuestionGenerator {
} while (Double.isNaN(answer) || Double.isInfinite(answer) || Math.abs(answer) > 10000);
return generateOptions(questionText, (int)Math.round(answer), "高中");
return generateOptions(questionText, answer, "高中");
}
// 小学题目相关方法
private String buildPrimaryQuestionText(int[] operands, int[] operations) {
private int findSuitableParenthesesPosition(int[] operations) {
// 寻找加减法操作符的位置,在这些地方加括号才有意义
List<Integer> suitablePositions = new ArrayList<>();
for (int i = 0; i < operations.length; i++) {
// 如果是加减法,且不是第一个操作符
if ((operations[i] == 0 || operations[i] == 1) && i > 0) {
suitablePositions.add(i);
}
}
if (suitablePositions.isEmpty()) {
// 如果没有找到合适的加减法位置,随机选择一个位置
return operations.length > 1 ? random.nextInt(operations.length - 1) : -1;
}
// 从合适的位置中随机选择一个
return suitablePositions.get(random.nextInt(suitablePositions.size()));
}
private String buildPrimaryQuestionText(int[] operands, int[] operations, int parenStart, int parenEnd) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < operands.length; i++) {
if (i > 0) {
switch (operations[i - 1]) {
// 在操作数前添加左括号
if (i == parenStart) {
sb.append("(");
}
// 添加操作数
sb.append(operands[i]);
// 在操作数后添加右括号(但要在操作符之前)
if (i == parenEnd) {
sb.append(")");
}
// 添加操作符(如果不是最后一个操作数)
if (i < operations.length) {
switch (operations[i]) {
case 0: sb.append(" + "); break;
case 1: sb.append(" - "); break;
case 2: sb.append(" × "); break;
case 3: sb.append(" ÷ "); break;
}
}
sb.append(operands[i]);
}
sb.append(" = ?");
return sb.toString();
}
private int calculatePrimaryAnswer(int[] operands, int[] operations) {
// 先处理乘除法,再处理加减法
private double calculatePrimaryAnswerWithParentheses(int[] operands, int[] operations, int parenStart, int parenEnd) {
// 如果没有括号,使用原来的计算方法
if (parenStart == -1 || parenEnd == -1) {
return calculatePrimaryAnswer(operands, operations);
}
// 复制操作数和操作符
List<Integer> numbers = new ArrayList<>();
List<Integer> ops = new ArrayList<>();
@ -202,33 +260,91 @@ public class QuestionGenerator {
ops.add(operation);
}
// 处理乘除法
// 计算括号内的表达式
double parenthesesResult = calculateParenthesesContent(numbers, ops, parenStart, parenEnd);
// 验证括号计算结果是否有效
if (parenthesesResult < 0 || Double.isNaN(parenthesesResult) || Double.isInfinite(parenthesesResult)) {
return -1;
}
// 用括号计算结果替换括号内的所有元素
replaceWithParenthesesResult(numbers, ops, parenStart, parenEnd, parenthesesResult);
// 计算剩余表达式
return calculateWithoutParentheses(numbers, ops);
}
private double calculateParenthesesContent(List<Integer> numbers, List<Integer> ops, int start, int end) {
// 提取括号内的数字和操作符
List<Integer> parenNumbers = new ArrayList<>();
List<Integer> parenOps = new ArrayList<>();
for (int i = start; i <= end; i++) {
parenNumbers.add(numbers.get(i));
}
for (int i = start; i < end; i++) {
parenOps.add(ops.get(i));
}
// 计算括号内的表达式(精确计算)
return calculateWithoutParentheses(parenNumbers, parenOps);
}
private void replaceWithParenthesesResult(List<Integer> numbers, List<Integer> ops,
int start, int end, double result) {
// 计算需要移除的元素数量
int numCountToRemove = end - start + 1;
int opCountToRemove = end - start;
// 移除括号范围内的数字
for (int i = 0; i < numCountToRemove; i++) {
numbers.remove(start);
}
// 移除括号范围内的操作符
for (int i = 0; i < opCountToRemove; i++) {
ops.remove(start);
}
// 插入括号计算结果
numbers.add(start, (int) Math.round(result));
}
private double calculateWithoutParentheses(List<Integer> numbers, List<Integer> ops) {
// 转换为double列表进行计算精确计算
List<Double> doubleNumbers = new ArrayList<>();
for (Integer num : numbers) {
doubleNumbers.add(num.doubleValue());
}
// 先处理乘除法(精确计算)
for (int i = 0; i < ops.size(); i++) {
int op = ops.get(i);
if (op == 2 || op == 3) {
int left = numbers.get(i);
int right = numbers.get(i + 1);
int result;
double left = doubleNumbers.get(i);
double right = doubleNumbers.get(i + 1);
double result;
if (op == 2) {
result = left * right;
} else {
if (right == 0 || left % right != 0) return -1;
if (right == 0) return Double.NaN;
result = left / right;
}
numbers.set(i, result);
numbers.remove(i + 1);
doubleNumbers.set(i, result);
doubleNumbers.remove(i + 1);
ops.remove(i);
i--;
}
}
// 处理加减法
int result = numbers.get(0);
// 处理加减法(精确计算)
double result = doubleNumbers.get(0);
for (int i = 0; i < ops.size(); i++) {
int op = ops.get(i);
int nextNum = numbers.get(i + 1);
double nextNum = doubleNumbers.get(i + 1);
if (op == 0) {
result += nextNum;
@ -238,33 +354,60 @@ public class QuestionGenerator {
}
}
return result;
// 只在最后结果保留2位小数
return Math.round(result * 100) / 100.0;
}
private boolean isValidPrimaryCalculation(int[] operands, int[] operations) {
try {
int current = operands[0];
private double calculatePrimaryAnswer(int[] operands, int[] operations) {
// 转换为double列表精确计算
List<Double> numbers = new ArrayList<>();
List<Integer> ops = new ArrayList<>();
for (int i = 0; i < operations.length; i++) {
int next = operands[i + 1];
int op = operations[i];
if (op == 1) {
if (current < next) return false;
current = current - next;
} else if (op == 0) {
current = current + next;
} else if (op == 2) {
current = current * next;
} else if (op == 3) {
if (next == 0 || current % next != 0) return false;
current = current / next;
for (int operand : operands) {
numbers.add((double) operand);
}
for (int operation : operations) {
ops.add(operation);
}
// 处理乘除法(精确计算)
for (int i = 0; i < ops.size(); i++) {
int op = ops.get(i);
if (op == 2 || op == 3) {
double left = numbers.get(i);
double right = numbers.get(i + 1);
double result;
if (op == 2) {
result = left * right;
} else {
if (right == 0) return Double.NaN;
result = left / right;
}
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
i--;
}
return current >= 0;
} catch (Exception e) {
return false;
}
// 处理加减法(精确计算)
double result = numbers.get(0);
for (int i = 0; i < ops.size(); i++) {
int op = ops.get(i);
double nextNum = numbers.get(i + 1);
if (op == 0) {
result += nextNum;
} else {
if (result < nextNum) return -1;
result -= nextNum;
}
}
// 只在最后结果保留2位小数
return Math.round(result * 100) / 100.0;
}
// 初中题目相关方法
@ -299,7 +442,7 @@ public class QuestionGenerator {
}
private double calculateMiddleSchoolAnswer(int[] operands, int[] operations, boolean[] hasSpecialOp, int[] specialOpTypes) {
// 先处理特殊运算(平方和开根号)
// 先处理特殊运算(平方和开根号)- 精确计算
double[] processedValues = new double[operands.length];
for (int i = 0; i < operands.length; i++) {
if (hasSpecialOp[i]) {
@ -315,7 +458,7 @@ public class QuestionGenerator {
}
}
// 然后按照小学的计算逻辑处理
// 然后按照小学的计算逻辑处理(精确计算)
List<Double> numbers = new ArrayList<>();
List<Integer> ops = new ArrayList<>();
@ -326,7 +469,7 @@ public class QuestionGenerator {
ops.add(operation);
}
// 处理乘除法
// 处理乘除法(精确计算)
for (int i = 0; i < ops.size(); i++) {
int op = ops.get(i);
if (op == 2 || op == 3) {
@ -348,7 +491,7 @@ public class QuestionGenerator {
}
}
// 处理加减法
// 处理加减法(精确计算)
double result = numbers.get(0);
for (int i = 0; i < ops.size(); i++) {
int op = ops.get(i);
@ -361,7 +504,8 @@ public class QuestionGenerator {
}
}
return result;
// 只在最后结果保留2位小数
return Math.round(result * 100) / 100.0;
}
// 高中题目相关方法
@ -394,22 +538,34 @@ public class QuestionGenerator {
}
private double calculateHighSchoolAnswer(int[] operands, int[] operations, boolean[] hasTrigOp, int[] trigFunctions) {
// 先处理三角函数运算
// 先处理三角函数运算(精确计算)
double[] processedValues = new double[operands.length];
for (int i = 0; i < operands.length; i++) {
if (hasTrigOp[i]) {
double radians = Math.toRadians(operands[i]);
switch (trigFunctions[i]) {
case 0: processedValues[i] = Math.sin(radians); break;
case 1: processedValues[i] = Math.cos(radians); break;
case 2: processedValues[i] = Math.tan(radians); break;
case 0:
processedValues[i] = Math.sin(radians);
break;
case 1:
processedValues[i] = Math.cos(radians);
break;
case 2:
// 避免tan(90°)等无效值
if (operands[i] % 180 == 90 && operands[i] % 360 != 270) {
return Double.NaN;
}
processedValues[i] = Math.tan(radians);
break;
default:
processedValues[i] = 0;
}
} else {
processedValues[i] = operands[i];
}
}
// 然后按照常规计算逻辑处理
// 然后按照常规计算逻辑处理(精确计算)
List<Double> numbers = new ArrayList<>();
List<Integer> ops = new ArrayList<>();
@ -420,7 +576,7 @@ public class QuestionGenerator {
ops.add(operation);
}
// 处理乘除法
// 处理乘除法(精确计算)
for (int i = 0; i < ops.size(); i++) {
int op = ops.get(i);
if (op == 2 || op == 3) {
@ -442,7 +598,7 @@ public class QuestionGenerator {
}
}
// 处理加减法
// 处理加减法(精确计算)
double result = numbers.get(0);
for (int i = 0; i < ops.size(); i++) {
int op = ops.get(i);
@ -455,37 +611,59 @@ public class QuestionGenerator {
}
}
return result;
// 只在最后结果保留2位小数
return Math.round(result * 100) / 100.0;
}
// 生成选项的通用方法
private Question generateOptions(String questionText, double answer, String level) {
String[] options = new String[4];
Set<Double> usedValues = new HashSet<>();
Set<String> usedValues = new HashSet<>();
// 添加正确答案保留1位小数
options[0] = String.format("%.1f", answer);
usedValues.add(Math.round(answer * 10) / 10.0); // 保留1位小数进行比较
// 检查答案是否为整数
boolean isIntegerAnswer = (answer == (int) answer);
// 格式化正确答案
String correctAnswer = formatAnswer(answer);
options[0] = correctAnswer;
usedValues.add(correctAnswer);
// 生成错误答案
for (int i = 1; i < 4; i++) {
double wrongAnswer;
String wrongAnswer;
int attempts = 0;
do {
// 根据答案大小生成合适的错误答案
double range = Math.max(2, Math.abs(answer) / 4 + 1);
double offset = (random.nextDouble() * range * 2) - range;
wrongAnswer = answer + offset;
wrongAnswer = Math.round(wrongAnswer * 10) / 10.0; // 保留1位小数
// 基于正确答案生成错误答案
double wrongValue;
double offset = (random.nextDouble() * 5) + 1; // 1-6的偏移量
if (isIntegerAnswer) {
// 如果答案是整数,生成整数错误答案
int intAnswer = (int) answer;
int intOffset = random.nextInt(10) + 1; // 1-10的整数偏移
if (random.nextBoolean()) {
wrongValue = intAnswer + intOffset;
} else {
wrongValue = Math.max(1, intAnswer - intOffset);
}
// 确保是整数
wrongValue = (int) wrongValue;
} else {
// 如果答案是小数,生成小数错误答案
if (random.nextBoolean()) {
wrongValue = answer + offset;
} else {
wrongValue = answer - offset;
}
// 保留2位小数
wrongValue = Math.round(wrongValue * 100) / 100.0;
}
wrongAnswer = formatAnswer(wrongValue);
attempts++;
} while (usedValues.contains(wrongAnswer) && attempts < 20);
if (usedValues.contains(wrongAnswer)) {
wrongAnswer = answer + (i * 0.5) + 0.3;
wrongAnswer = Math.round(wrongAnswer * 10) / 10.0;
}
options[i] = String.format("%.1f", wrongAnswer);
options[i] = wrongAnswer;
usedValues.add(wrongAnswer);
}
@ -494,9 +672,8 @@ public class QuestionGenerator {
// 找到正确答案的新位置
int correctIndex = 0;
String correctAnswerStr = String.format("%.1f", answer);
for (int i = 0; i < options.length; i++) {
if (options[i].equals(correctAnswerStr)) {
if (options[i].equals(correctAnswer)) {
correctIndex = i;
break;
}
@ -505,6 +682,14 @@ public class QuestionGenerator {
return new Question(questionText, options, correctIndex, level);
}
private String formatAnswer(double answer) {
if (answer == (int) answer) {
return String.valueOf((int) answer); // 整数不显示小数
} else {
return String.format("%.2f", answer); // 小数保留2位
}
}
private void shuffleArray(String[] array) {
for (int i = array.length - 1; i > 0; i--) {
int j = random.nextInt(i + 1);

Loading…
Cancel
Save