小学生四则运算系统

发布时间 2023-11-17 21:53:49作者: 王曦轶

作业:0. 使用C实现四则运算

  1. 参考 https://www.cnblogs.com/saiwa/articles/5253713.html学习参数传递,使用 -n 参数控制生成题目的个数,例如
    Myapp -n 10 -o Exercise.txt
    将生成10个题目,题目保存在Exeercise.txmt。
  2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如
    Myapp -r 10
    将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。
  3. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。
  4. 每道题目中出现的运算符个数不超过3个。
  5. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。
    生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:
    1. 四则运算题目1
    2. 四则运算题目2
      ……

其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。
6. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:
1. 答案1
2. 答案2

特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。
  1. 程序应能支持一万道题目的生成。
  2. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,并会输出所有题目中重复的题目,输入参数如下:
    Myapp -e .txt -a .txt -o Grade.txt

统计结果输出到文件Grade.txt,格式如下:

Correct: 5 (1, 3, 5, 7, 9)
Wrong: 5 (2, 4, 6, 8, 10)
Repeat:2
RepeatDetail:
(1) 2,45+32 Repeat 3,32+45
(2) 5,3+(2+1) Repeat 7,1+2+3

解释:
Correct: 5 ----5道题目正确,正确的题号 1,3,5,7,9
Wrong:5 -----5道题目错误,错误的题号 2,4,6,8,10
Repeat:2 2---组题目重复
(1) 第一组 题号2,题目 45+32 与题号3的题目重复,题号3为 32+45
(2)第二组 题号5,题目 3+(2+1) 与题号7的题目重复,题号7为 1+2+3

其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。

这个任务完全做下来难度很大,于是我分成了多个步骤,一步一步地实现。
1.初步实现四则运算:

include <stdio.h>

include <stdlib.h>

include<time.h>

int main(){
int a,b,c,d,i,f;
srand(time(NULL));
f = 0;
for (int i = 0; i < 10; i++) {
a = rand()%10 + 1;
b = rand()%10 + 1;
d = rand()%4 + 1;
g = rand() % 4+1;
h = rand() % 4+1;
switch(d)
{
case 1:
printf("%d+%d=",a,b);
scanf("%d",&c);
if(ca+b){
f++;
}
case 2:
printf("%d-%d=",a,b);
scanf("%d",&c);
if(c
a-b){
f++;
}
case 3:
printf("%d%d=",a,b);
scanf("%d",&c);
if(c==a
b){
f++;
}
case 4:
printf("%d/%d=",a,b);
scanf("%d",&c);
if(c==a/b){
f++;
}
}
}
return 0;
}
2.每次运算符不小于三个:

include <stdio.h>

include <stdlib.h>

include <time.h>

int main() {
int a, b, c, f;
srand(time(NULL));
f = 0;
for (int i = 0; i < 10; i++) {
a = rand() % 10 + 1;
b = rand() % 10 + 1;
int num_operators = rand() % 3 + 1;
for (int j = 0; j < num_operators; j++) {
int d = rand() % 4 + 1;
switch (d) {
case 1:
printf("%d+%d", a, b);
break;
case 2:
printf("%d-%d", a, b);
break;
case 3:
printf("%d*%d", a, b);
break;
case 4:
printf("%d/%d", a, b);
break;
}
if (j < num_operators - 1) {
printf(" ");
}
a = a + 1;
b = b + 2;
}
printf("=");
scanf("%d", &c);
if (c == a + b) {
f++;
}
}
return 0;
}

3.结尾输入正确错误的题数以及题号:

include <stdio.h>

include <stdlib.h>

include <time.h>

int main() {
int a, b, c, f;
srand(time(NULL));
f = 0;
int correct[10];
for (int i = 0; i < 10; i++) {
a = rand() % 10 + 1;
b = rand() % 10 + 1;
int num_operators = rand() % 3 + 1;
for (int j = 0; j < num_operators; j++) {
int d = rand() % 4 + 1;
switch (d) {
case 1:
printf("%d+%d", a, b);
break;
case 2:
printf("%d-%d", a, b);
break;
case 3:
printf("%d*%d", a, b);
break;
case 4:
printf("%d/%d", a, b);
break;
}
if (j < num_operators - 1) {
printf(" ");
}
a = a + 1;
b = b + 2;
}
printf("=");
scanf("%d", &c);
if (c == a + b) {
f++;
correct[i] = 1;
} else {
correct[i] = 0;
}
}
printf("Correct answers: %d\n", f);
printf("Incorrect answers: %d\n", 10 - f);
printf("Question numbers with correct answers: ");
for (int i = 0; i < 10; i++) {
if (correct[i] == 1) {
printf("%d ", i+1);
}
}
printf("\nQuestion numbers with incorrect answers: ");
for (int i = 0; i < 10; i++) {
if (correct[i] == 0) {
printf("%d ", i+1);
}
}
return 0;
}
4.ai给出题目的完整做法(参考):

include <stdio.h>

include <stdlib.h>

include <string.h>

include <time.h>

// 定义最大题目数量

define MAX_QUESTIONS 10000

// 定义真分数结构体
typedef struct {
int integer; // 整数部分
int numerator; // 分子
int denominator; // 分母
} Fraction;

// 判断是否为质数
int isPrime(int num) {
if (num < 2) {
return 0;
}
for (int i = 2; i * i <= num; i++) {
if (num % i == 0) {
return 0;
}
}
return 1;
}

// 获取一个随机数
int getRandomNumber(int range) {
return rand() % range;
}

// 获取一个随机真分数
Fraction getRandomFraction(int range) {
Fraction fraction;
fraction.integer = getRandomNumber(range);
fraction.numerator = getRandomNumber(range);
fraction.denominator = getRandomNumber(range) + 1;
return fraction;
}

// 获取一个随机运算符
char getRandomOperator() {
char operators[] = {'+', '-', '*', '/'};
return operators[getRandomNumber(4)];
}

// 判断两个题目是否重复
int isRepeated(char* question1, char* question2) {
char* p1 = strstr(question1, "=");
char* p2 = strstr(question2, "=");
int len = strlen(p1) - 1;
if (strncmp(question1, question2, len) == 0) {
return 1;
}
return 0;
}

// 将分数转换为字符串形式
void fractionToString(Fraction fraction, char* result) {
if (fraction.integer == 0) {
sprintf(result, "%d/%d", fraction.numerator, fraction.denominator);
} else if (fraction.numerator == 0) {
sprintf(result, "%d", fraction.integer);
} else {
sprintf(result, "%d'%d/%d", fraction.integer, fraction.numerator, fraction.denominator);
}
}

// 计算两个整数的最大公约数
int gcd(int a, int b) {
if (b == 0) {
return a;
}
return gcd(b, a % b);
}

// 计算两个整数的最小公倍数
int lcm(int a, int b) {
return a * b / gcd(a, b);
}

// 化简真分数
void simplifyFraction(Fraction* fraction) {
int g = gcd(fraction->numerator, fraction->denominator);
fraction->numerator /= g;
fraction->denominator /= g;
fraction->integer += fraction->numerator / fraction->denominator;
fraction->numerator %= fraction->denominator;
}

// 计算四则运算表达式的结果
Fraction calculateResult(Fraction operand1, Fraction operand2, char operator) {
Fraction result;
int commonDenominator;
switch (operator) {
case '+':
commonDenominator = lcm(operand1.denominator, operand2.denominator);
operand1.numerator *= commonDenominator / operand1.denominator;
operand2.numerator *= commonDenominator / operand2.denominator;
operand1.denominator = operand2.denominator = commonDenominator;
result.integer = operand1.integer + operand2.integer;
result.numerator = operand1.numerator + operand2.numerator;
result.denominator = commonDenominator;
break;
case '-':
commonDenominator = lcm(operand1.denominator, operand2.denominator);
operand1.numerator *= commonDenominator / operand1.denominator;
operand2.numerator = commonDenominator / operand2.denominator;
operand1.denominator = operand2.denominator = commonDenominator;
result.integer = operand1.integer - operand2.integer;
result.numerator = operand1.numerator - operand2.numerator;
result.denominator = commonDenominator;
break;
case '
':
result.integer = operand1.integer * operand2.integer;
result.numerator = operand1.numerator * operand2.numerator;
result.denominator = operand1.denominator * operand2.denominator;
break;
case '/':
result.integer = 0;
result.numerator = operand1.integer * operand2.denominator + operand1.numerator * operand2.denominator;
result.denominator = operand1.denominator * operand2.integer + operand1.denominator * operand2.numerator;
if (result.denominator == 0) {
printf("错误:除数为0\n");
exit(1);
}
break;
default:
printf("错误:无效的运算符\n");
exit(1);
}
simplifyFraction(&result);
return result;
}

int main(int argc, char* argv[]) {
srand(time(NULL));

// 解析命令行参数
int range = 0;
if (argc != 3 || strcmp(argv[1], "-r") != 0 || (range = atoi(argv[2])) <= 0) {
    printf("用法:%s -r <范围>\n", argv[0]);
    return 1;
}

// 初始化题目和答案数组
char questions[MAX_QUESTIONS][100];
char answers[MAX_QUESTIONS][100];

int count = 0;  // 题目数量
int correctCount = 0;   // 正确题目数量
int wrongCount = 0; // 错误题目数量
int repeatCount = 0;    // 重复题目数量
int repeatIndexes[MAX_QUESTIONS];   // 重复题目的索引

while (count < MAX_QUESTIONS) {
    // 随机生成两个操作数和一个运算符
    Fraction operand1 = getRandomFraction(range);
    Fraction operand2 = getRandomFraction(range);
    char operator = getRandomOperator();
    
    // 判断是否满足条件
    if (operator == '/' && operand2.integer == 0) {
        continue;
    }
    if (operator == '/' && calculateResult(operand1, operand2, operator).integer != 0) {
        continue;
    }
    if (operator == '/' && !isPrime(operand2.denominator)) {
        continue;
    }
    
    // 构造题目字符串
    char question[100];
    char operand1Str[20];
    char operand2Str[20];
    fractionToString(operand1, operand1Str);
    fractionToString(operand2, operand2Str);
    sprintf(question, "%d. %s %c %s =", count + 1, operand1Str, operator, operand2Str);
    
    // 检查是否重复
    int repeated = 0;
    for (int i = 0; i < count; i++) {
        if (isRepeated(question, questions[i])) {
            repeated = 1;
            repeatIndexes[repeatCount++] = i + 1;
            break;
        }
    }
    if (repeated) {
        continue;
    }
    
    // 计算答案
    Fraction result = calculateResult(operand1, operand2, operator);
    
    // 构造答案字符串
    char answer[100];
    fractionToString(result, answer);
    
    // 保存题目和答案
    strcpy(questions[count], question);
    strcpy(answers[count], answer);
    count++;
    
    // 判断答案是否正确
    char userAnswer[100];
    printf("%s ", question);
    scanf("%s", userAnswer);
    if (strcmp(userAnswer, answer) == 0) {
        correctCount++;
    } else {
        wrongCount++;
    }
}

// 输出统计结果
printf("Correct: %d ", correctCount);
for (int i = 0; i < MAX_QUESTIONS; i++) {
    if (i < correctCount) {
        printf("(%d) ", i + 1);
    }
}
printf("\nWrong: %d ", wrongCount);
for (int i = 0; i < MAX_QUESTIONS; i++) {
    if (i < wrongCount) {
        printf("(%d) ", i + 1);
    }
}
printf("\nRepeat: %d\n", repeatCount);
printf("RepeatDetail:\n");
for (int i = 0; i < repeatCount / 2; i++) {
    int index1 = repeatIndexes[i * 2];
    int index2 = repeatIndexes[i * 2 + 1];
    printf("(%d)   %d,%s  Repeat %d,%s\n", i + 1, index1, questions[index1 - 1], index2, questions[index2 - 1]);
}

return 0;

}