小学数学
| 这个作业属于哪个课程 | 作业课程 |
|---|---|
| 这个作业要求在哪里 | 作业要求 |
| 这个作业的目标 | 实现一个自动生成小学四则运算题目的命令行程序 |
成员:3123004217蔡宜桓
我的github:github仓库
一.PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 35 | 30 |
| Estimate | 估计这个任务需要多少时间 | 15 | 30 |
| Development | 开发 | 185 | 200 |
| Analysis | 需求分析 (包括学习新技术) | 75 | 80 |
| Design Spec | 生成设计文档 | 25 | 20 |
| Design Review | 设计复审 | 35 | 30 |
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 25 |
| Design | 具体设计 | 35 | 40 |
| Coding | 具体编码 | 75 | 70 |
| Code Review | 代码复审 | 25 | 45 |
| Test | 测试(自我测试,修改代码,提交修改) | 35 | 30 |
| Reporting | 报告 | 15 | 20 |
| Test Repor | 测试报告 | 25 | 15 |
| Size Measurement | 计算工作量 | 5 | 20 |
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 35 | 30 |
| 合计 | 650 | 685 |
二.代码展示
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#define MAX_QUESTIONS 10000
#define MAX_EXPR_LEN 100
typedef struct {
int numerator;
int denominator;
} Fraction;
typedef struct {
char expression[MAX_EXPR_LEN];
Fraction answer;
} Question;
// 最大公约数
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// 约分分数
void simplify(Fraction *f) {
int common = gcd(abs(f->numerator), abs(f->denominator));
f->numerator /= common;
f->denominator /= common;
if (f->denominator < 0) {
f->numerator *= -1;
f->denominator *= -1;
}
}
// 生成随机分数
Fraction random_fraction(int range) {
Fraction f;
f.denominator = rand() % (range - 1) + 2; // 分母至少为2
f.numerator = rand() % (f.denominator * (range - 1)) + 1;
simplify(&f);
return f;
}
// 生成随机自然数或分数
Fraction random_number(int range, bool allow_fraction) {
if (allow_fraction && rand() % 4 == 0) { // 25%概率生成分数
return random_fraction(range);
} else {
Fraction f;
f.numerator = rand() % range;
f.denominator = 1;
return f;
}
}
// 分数转字符串
void fraction_to_str(Fraction f, char *str) {
if (f.denominator == 1) {
sprintf(str, "%d", f.numerator);
} else if (abs(f.numerator) > f.denominator) {
int whole = f.numerator / f.denominator;
int remainder = abs(f.numerator) % f.denominator;
sprintf(str, "%d'%d/%d", whole, remainder, f.denominator);
} else {
sprintf(str, "%d/%d", f.numerator, f.denominator);
}
}
// 字符串转分数
Fraction str_to_fraction(const char *str) {
Fraction f;
int whole = 0, numerator = 0, denominator = 1;
if (strchr(str, '\'') != NULL) {
sscanf(str, "%d'%d/%d", &whole, &numerator, &denominator);
f.numerator = whole * denominator + (whole >= 0 ? numerator : -numerator);
f.denominator = denominator;
} else if (strchr(str, '/') != NULL) {
sscanf(str, "%d/%d", &numerator, &denominator);
f.numerator = numerator;
f.denominator = denominator;
} else {
sscanf(str, "%d", &numerator);
f.numerator = numerator;
f.denominator = 1;
}
simplify(&f);
return f;
}
// 分数加法
Fraction add(Fraction a, Fraction b) {
Fraction result;
result.numerator = a.numerator * b.denominator + b.numerator * a.denominator;
result.denominator = a.denominator * b.denominator;
simplify(&result);
return result;
}
// 分数减法
Fraction subtract(Fraction a, Fraction b) {
Fraction result;
result.numerator = a.numerator * b.denominator - b.numerator * a.denominator;
result.denominator = a.denominator * b.denominator;
simplify(&result);
return result;
}
// 分数乘法
Fraction multiply(Fraction a, Fraction b) {
Fraction result;
result.numerator = a.numerator * b.numerator;
result.denominator = a.denominator * b.denominator;
simplify(&result);
return result;
}
// 分数除法
Fraction divide(Fraction a, Fraction b) {
Fraction result;
result.numerator = a.numerator * b.denominator;
result.denominator = a.denominator * b.numerator;
simplify(&result);
return result;
}
// 生成表达式和答案
void generate_expression(Question *q, int range, int operators_left, bool in_parentheses) {
if (operators_left == 0) {
Fraction num = random_number(range, true);
char num_str[20];
fraction_to_str(num, num_str);
strcat(q->expression, num_str);
q->answer = num;
return;
}
bool use_parentheses = in_parentheses ? false : (rand() % 2 == 0 && operators_left > 1);
if (use_parentheses) {
strcat(q->expression, "(");
}
// 左子表达式
int left_operators = rand() % operators_left;
if (left_operators == operators_left) left_operators--;
generate_expression(q, range, left_operators, use_parentheses);
// 运算符
char op;
Fraction temp_answer;
switch (rand() % 4) {
case 0: op = '+'; break;
case 1: op = '-'; break;
case 2: op = '*'; break;
case 3: op = '/'; break;
}
// 处理减法和除法的限制
bool valid = false;
Fraction right_num;
char right_str[20];
int attempts = 0;
do {
attempts++;
if (attempts > 10) { // 避免无限循环
op = (op == '-' || op == '/') ? '+' : op;
}
// 生成右子表达式
char temp_expr[MAX_EXPR_LEN] = "";
Question temp_q;
strcpy(temp_q.expression, temp_expr);
generate_expression(&temp_q, range, operators_left - left_operators - 1, use_parentheses);
right_num = temp_q.answer;
strcpy(right_str, temp_q.expression);
if (op == '-') {
valid = (q->answer.numerator * right_num.denominator >=
right_num.numerator * q->answer.denominator);
} else if (op == '/') {
valid = (right_num.numerator != 0);
} else {
valid = true;
}
} while (!valid);
// 添加运算符和右子表达式
char op_with_spaces[4] = " ";
op_with_spaces[1] = op;
op_with_spaces[2] = ' ';
strcat(q->expression, op_with_spaces);
strcat(q->expression, right_str);
// 计算答案
switch (op) {
case '+': q->answer = add(q->answer, right_num); break;
case '-': q->answer = subtract(q->answer, right_num); break;
case '*': q->answer = multiply(q->answer, right_num); break;
case '/': q->answer = divide(q->answer, right_num); break;
}
if (use_parentheses) {
strcat(q->expression, ")");
}
}
// 检查题目是否重复
bool is_duplicate(Question *questions, int count, Question *new_q) {
// 简化检查:比较答案和表达式长度
for (int i = 0; i < count; i++) {
if (questions[i].answer.numerator == new_q->answer.numerator &&
questions[i].answer.denominator == new_q->answer.denominator &&
strlen(questions[i].expression) == strlen(new_q->expression)) {
// 更复杂的检查可以在这里添加
return true;
}
}
return false;
}
// 生成题目
void generate_questions(int count, int range, const char *exercise_file, const char *answer_file) {
Question questions[MAX_QUESTIONS];
FILE *ef = fopen(exercise_file, "w");
FILE *af = fopen(answer_file, "w");
if (!ef || !af) {
printf("无法打开输出文件\n");
return;
}
srand(time(NULL));
for (int i = 0; i < count; i++) {
Question q;
strcpy(q.expression, "");
int operators = rand() % 3 + 1; // 1-3个运算符
generate_expression(&q, range, operators, false);
// 确保不重复
while (is_duplicate(questions, i, &q)) {
strcpy(q.expression, "");
generate_expression(&q, range, operators, false);
}
questions[i] = q;
// 写入题目文件
fprintf(ef, "%d. %s =\n", i + 1, q.expression);
// 写入答案文件
char answer_str[20];
fraction_to_str(q.answer, answer_str);
fprintf(af, "%d. %s\n", i + 1, answer_str);
}
fclose(ef);
fclose(af);
}
// 检查答案
void check_answers(const char *exercise_file, const char *answer_file, const char *grade_file) {
FILE *ef = fopen(exercise_file, "r");
FILE *af = fopen(answer_file, "r");
FILE *gf = fopen(grade_file, "w");
if (!ef || !af || !gf) {
printf("无法打开输入/输出文件\n");
return;
}
int correct_count = 0, wrong_count = 0;
int correct_indices[MAX_QUESTIONS], wrong_indices[MAX_QUESTIONS];
char line[256];
int index;
while (fgets(line, sizeof(line), ef)) {
sscanf(line, "%d.", &index);
char answer_line[256];
fgets(answer_line, sizeof(answer_line), af);
// 提取正确答案
char correct_answer[20];
sscanf(answer_line, "%*d. %s", correct_answer);
Fraction correct = str_to_fraction(correct_answer);
// 提取用户答案
char *eq_pos = strchr(line, '=');
if (!eq_pos || *(eq_pos + 1) == '\n') {
// 没有答案
wrong_indices[wrong_count++] = index;
continue;
}
char user_answer[20];
sscanf(eq_pos + 1, "%s", user_answer);
Fraction user = str_to_fraction(user_answer);
if (user.numerator == correct.numerator && user.denominator == correct.denominator) {
correct_indices[correct_count++] = index;
} else {
wrong_indices[wrong_count++] = index;
}
}
// 写入成绩文件
fprintf(gf, "Correct: %d (", correct_count);
for (int i = 0; i < correct_count; i++) {
fprintf(gf, "%d", correct_indices[i]);
if (i < correct_count - 1) fprintf(gf, ", ");
}
fprintf(gf, ")\n");
fprintf(gf, "Wrong: %d (", wrong_count);
for (int i = 0; i < wrong_count; i++) {
fprintf(gf, "%d", wrong_indices[i]);
if (i < wrong_count - 1) fprintf(gf, ", ");
}
fprintf(gf, ")\n");
fclose(ef);
fclose(af);
fclose(gf);
}
// 打印帮助信息
void print_help() {
printf("使用方法:\n");
printf("生成题目: program -n <题目数量> -r <数值范围>\n");
printf("检查答案: program -e <题目文件> -a <答案文件>\n");
}
int main(int argc, char *argv[]) {
if (argc < 2) {
print_help();
return 1;
}
if (strcmp(argv[1], "-n") == 0 && argc >= 5 && strcmp(argv[3], "-r") == 0) {
int count = atoi(argv[2]);
int range = atoi(argv[4]);
if (count <= 0 || range <= 0) {
printf("无效的参数值\n");
return 1;
}
generate_questions(count, range, "Exercises.txt", "Answers.txt");
printf("已生成 %d 道题目,范围在 %d 以内\n", count, range);
} else if (strcmp(argv[1], "-e") == 0 && argc >= 5 && strcmp(argv[3], "-a") == 0) {
check_answers(argv[2], argv[4], "Grade.txt");
printf("已检查答案,结果保存在 Grade.txt\n");
} else {
print_help();
return 1;
}
return 0;
}

浙公网安备 33010602011771号