关于“计算题”程序的分析和总结

这次计算题程序已收官完成,再次进行分析和总结。

一、设计思路

1. 从txt读取算式。

2. 将算式由中缀转后缀。

3. 计算后缀算式并与用户输入答案进行比较,答案正确提示正确,答案错误提示错误并输出正确的答案。与此同时,统计用户正确与错误的次数以及题目的总数量。

4. 重复,直到算式全部计算完成,输出统计的正确错误数和题目的总数量。

二、具体实现

本程序运用了面向对象的设计思路。经过资料搜索,我发现有很多参考的程序。它们已经实现了中缀转后缀并输出正确结果并统计正误的功能,但无法计算分数。因此,我在此基础上进行了改进,增加了一个Fraction类。其把所有的整数都转换成了分数形式,并且重载了所有的运算符。之后,在重用的程序中把所有的定义的变量都定义为Fraction类型的就可以了。

以下是新增的Fraction类。

#pragma once
#include <iostream>

using namespace std;

class Fraction
{
public:
    Fraction();
    Fraction(int n);
    Fraction(int n, int d);
    ~Fraction();
    int numerator;
    int denominator;
    Fraction operator + (Fraction f);
    Fraction operator - (Fraction f);
    Fraction operator * (Fraction f);
    Fraction operator / (Fraction f);
    bool operator == (Fraction f);
    friend istream &operator >> (istream &in, Fraction &f);
    friend ostream &operator << (ostream &out, Fraction &f);
    void reduction();
    int get_gcd(int a, int b);
};
#include "stdafx.h"
#include "Fraction.h"

Fraction::Fraction()
{
}

Fraction::Fraction(int n) :numerator(n), denominator(1)
{
}

Fraction::Fraction(int n, int d) : numerator(n), denominator(d)
{
}

Fraction::~Fraction()
{
}

Fraction Fraction::operator + (Fraction f) {
    return Fraction(numerator * f.denominator + denominator * f.numerator, denominator * f.denominator);
}

Fraction Fraction::operator - (Fraction f) {
    return Fraction(numerator * f.denominator - denominator * f.numerator, denominator * f.denominator);
}

Fraction Fraction::operator * (Fraction f) {
    return Fraction(numerator * f.numerator, denominator * f.denominator);
}

Fraction Fraction::operator / (Fraction f) {
    return Fraction(numerator * f.denominator, denominator * f.numerator);
}

bool Fraction::operator == (Fraction f) {
    return numerator == f.numerator && denominator == f.denominator;
}

istream& operator >> (istream &in, Fraction &f) {
    in >> f.numerator;
    f.denominator = 1;
    char c;
    in.get(c);
    if (c != ‘\n‘)
    {
        in >> f.denominator;
    }
    return in;
}

ostream& operator << (ostream &out, Fraction &f) {
    f.reduction();
    if (f.denominator == 1)
        out << f.numerator;
    else
        out << f.numerator << "/" << f.denominator;
    return out;
}

void Fraction::reduction() {
    int gcd = get_gcd(numerator, denominator);
    numerator = numerator / gcd;
    denominator = denominator / gcd;
    if (denominator < 0)
    {
        numerator = -numerator;
        denominator = -denominator;
    }
}

int Fraction::get_gcd(int a, int b)
{
    if (b == 0)
        return a;
    return get_gcd(b, a%b);
}

以下是网上参考的只能进行整数运算的程序的改进。

#pragma once
#include "Fraction.h"

class Expression
{
public:
    Fraction    Operand;
    char        Operator  = NULL;
};

#include "stdafx.h"
#include "Expression.h"

/////////////////////////////////////////////////////////////////////////
#pragma once
#include "Expression.h"
#include <stack>
#include <fstream>

class Calculator
{
private:
    stack<char> is;
    stack<Fraction> ps;
    Expression InfixExp[100];
    Expression PostfixExp[100];
    int il;
    int pl;
    bool GetInfixExp();
    bool Transform();
    bool GetTwoOperands(Fraction &opd1, Fraction &opd2);
    bool Compute(char op);
    ifstream ifs, ifs_line;
public:
    Calculator();
    ~Calculator();
    void Run();
};

#include "stdafx.h"
#include "Calculator.h"

Calculator::Calculator()
{
    Run();
}

Calculator::~Calculator()
{
}

bool Calculator::GetInfixExp() {
    char c;
    int newOperand;
    bool lastExpIsNum = false;
    bool nextNumAddMinus = false;

    char printExp[128];
    ifs_line.getline(printExp, 128);
    cout << printExp << " ";

    while (ifs >> c, c != ‘=‘) {
        switch (c) {
        case ‘-‘:
            if (lastExpIsNum)
            {
                InfixExp[il].Operator = c;
            }
            else
            {
                nextNumAddMinus = true;
                il--;
            }
            lastExpIsNum = false;
            break;
        case ‘+‘:
        case ‘*‘:
        case ‘/‘:
        case ‘(‘:
            InfixExp[il].Operator = c;
            lastExpIsNum = false;
            break;
        case ‘)‘:
            InfixExp[il].Operator = c;
            lastExpIsNum = true;
            break;
        default:
            if (c >= ‘0‘ && c <= ‘9‘) {
                ifs.putback(c);
                ifs >> newOperand;
                newOperand = nextNumAddMinus ? -newOperand : newOperand;
                nextNumAddMinus = false;
                InfixExp[il].Operand = Fraction(newOperand);
            }
            else {
                return false;
            }
            lastExpIsNum = true;
            break;
        }
        il++;
    }
    return true;
}

bool Calculator::Transform() {
    bool flag;
    for (int i = 0; i < il; i++) {
        if (InfixExp[i].Operator == NULL) {
            PostfixExp[pl].Operand = InfixExp[i].Operand;
            pl++;
        }
        else if (InfixExp[i].Operator == ‘(‘) {
            is.push(‘(‘);
        }
        else if (InfixExp[i].Operator == ‘)‘) {
            if (is.empty()) {
                return false;
            }
            else {
                flag = false;
                while (!is.empty()) {
                    if (is.top() != ‘(‘) {
                        PostfixExp[pl].Operator = is.top();
                        is.pop();
                        pl++;
                    }
                    else {
                        flag = true;
                        is.pop();
                        break;
                    }
                }
                if (is.empty() && !flag) {
                    return false;
                }
            }
        }
        else {
            while (
                !is.empty() &&
                is.top() != ‘(‘ &&
                !((is.top() == ‘+‘ || is.top() == ‘-‘) && (InfixExp[i].Operator == ‘*‘ || InfixExp[i].Operator == ‘/‘))
                ) {
                PostfixExp[pl].Operator = is.top();
                is.pop();
                pl++;
            }
            is.push(InfixExp[i].Operator);
        }
    }
    while (!is.empty()) {
        if (is.top() == ‘(‘) {
            return false;
        }
        else {
            PostfixExp[pl].Operator = is.top();
            is.pop();
            pl++;
        }
    }
    return true;
}

bool Calculator::GetTwoOperands(Fraction& opd1, Fraction& opd2) {
    if (ps.empty())
        return false;
    opd1 = ps.top();
    ps.pop();
    if (ps.empty())
        return false;
    opd2 = ps.top();
    ps.pop();
    return true;
}

bool Calculator::Compute(char op) {
    bool result;
    Fraction operand1, operand2;
    result = GetTwoOperands(operand1, operand2);
    if (result) {
        switch (op)
        {
        case ‘+‘:
            ps.push(operand2 + operand1);
            break;
        case ‘-‘:
            ps.push(operand2 - operand1);
            break;
        case ‘*‘:
            ps.push(operand2 * operand1);
            break;
        case ‘/‘:
            if (operand1.numerator == 0) {
                cout << "除数存在0,错误!" << endl;
                return false;
            }
            else {
                ps.push(operand2 / operand1);
            }
            break;
        }
    }
    return true;
}

void Calculator::Run() {
    ifs = ifstream("Expressions.txt");
    ifs_line = ifstream("Expressions.txt");

    Fraction correct_answer, user_answer;
    int    correct_num = 0, wrong_num = 0;

    // 输入中缀表达式
    cout << "请计算下列算式:" << endl;
    while (!ifs_line.eof())
    {
        il = 0;
        pl = 0;
        while (!is.empty())
            is.pop();
        while (!ps.empty())
            ps.pop();
        for (int i = 0; i < 100; i++)
        {
            InfixExp[i] = PostfixExp[i] = Expression();
        }

        if (GetInfixExp() && Transform()) {
            for (int i = 0; i < pl; i++) {
                if (PostfixExp[i].Operator == NULL)
                    ps.push(PostfixExp[i].Operand);
                else {
                    if (!Compute(PostfixExp[i].Operator))
                        return;
                }
            }
            correct_answer = ps.top();
        }
        else
        {
            cout << "算式格式错误" << endl;
            return;
        }

        cin >> user_answer;
        user_answer.reduction(), correct_answer.reduction();
        if (user_answer == correct_answer)
        {
            correct_num++;
            cout << "正确" << endl;

        }
        else
        {
            wrong_num++;
            cout << "错误,正确答案是" << correct_answer << endl;

        }
    }
    cout << "--------------------------" << endl;
    cout << "共" << correct_num + wrong_num << "题,";
    cout << "正确" << correct_num << "道,错误" << wrong_num << "道" << endl;
}

三、项目总结

这次项目,对我改进程序的能力有了提升。每个程序并不是一定要从零开始。我们可以利用他人的的思路和成果,再次基础上进行改进。同时,我们也应多和他人进行交流,因为这样可以更方便地获取新鲜高端的思路,对项目的完成有所广益。

时间: 2024-12-19 07:26:51

关于“计算题”程序的分析和总结的相关文章

2016年5月信息系统项目管理师临门一脚重点串讲(综合知识、案例分析、重点论文、计算题)

http://edu.51cto.com/course/course_id-5868.html 1.旨在帮助大家快速通过软考,少受备考的折磨与孤独. 2.28小时,不到2天的时间,快速学完100天的内容 3.着重梳理综合知识重点高频考点,快速提升大家综合知识得分能力 4.多角度剖析案例分析,提升大家案例分析应试能力. 5.从论文框架与模版.到重点论文的准备,尽在掌控. 为帮助大家提高复习效率,以最小的代价通过信息系统项目管理师,本套软考冲刺临门一脚,从以下方面进行课程优化与组合:1.信息化或计算

MathExam小学一二年级计算题生成器V1.0

MathExam小学一二年级计算题生成器v1.0 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 ? Estimate ? 估计这个任务需要多少时间 880 1540 Development 开发 ? Analysis ? 需求分析 (包括学习新技术) 60 100 ? Design Spec ? 生成设计文档 20 20 ? Design Review ? 设计复审 10 20 ? Co

小学计算题一次大满足

海量小学计算题 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 120 300 ? Estimate ? 估计这个任务需要多少时间 600 1460 Development 开发 ? Analysis ? 需求分析 (包括学习新技术) 120 300 ? Design Spec ? 生成设计文档 30 60 ? Design Review ? 设计复审 20 30 ? Coding Sta

MathExamV2.0四则混合运算计算题生成器

MathExamV2.0四则混合运算计算题生成器----211606360 丁培晖 211606343 杨宇潇 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 ? Estimate ? 估计这个任务需要多少时间 60 100 Development 开发 ? Analysis ? 需求分析 (包括学习新技术) 360 440 ? Design Spec ? 生成设计文档 20 20 ? D

PMP--可能会涉及到的计算题

一.进度管理里的历时三点估算历时的三点估算可能会出现在进度管理的计算题里.以下公式,大家要记住:说一下历时的三点估算中的几个值:1.最有可能的历时估算:Tm2.最乐观的历时估算: To3.最悲观的历时估算: Tp4.活动历时的均值=(To+4Tm+Tp)/65.由于是估算,难免有误差,其方差=(Tp-To)/6此处的方差与正态分布中的西格玛含义不同.西格玛是一个概率.1 西格玛是指活动在(平均值减1 个标准差,平均值加1 个标准差)内完成的概率,是一个常数,0.6827.例题:某项目完成估计需要

[软考]决策树、最短路径、最大收益、盈亏平衡点、线性规划(信息系统项目管理师-计算题汇总)

开场白:已经是第五篇软考文章了,也是最后一篇计算题的文章,基本包含了信管考试的全部计算题,因为现在离考试还早,北京地区8月11日报名,可以先学习一遍,考前再来复习一遍.这篇文章包含了许多实例,不对各实例的意义进行讲解了,都比较简单,看实例讲解,会算就可以了. 前天发布的第四篇文章没有被推上首页,可能是因为大部分题的来源都在网上可以搜到.这里我对这些题进行了分析整理,把一些错误的答案,不明确的讲解进行了完善,试题图片也是参照众多版本选出最清晰的.所以虽是网上收集来的,但也付出了很多的时间,在自己学

通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

实验一:通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的 学号:20135114 姓名:王朝宪 注: 原创作品转载请注明出处   <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 1 1)实验部分(以下命令为实验楼64位Linux虚拟机环境下适用,32位Linux环境可能会稍有不同) 使用 gcc –S –o main.s main.c -m32 命令编译成汇编代码,如下代码中的数字请自行修改以防与

程序员突围-程序调试分析(序)

-从实践到思考,痛苦的煎熬 其实算算,工作一年了,从大学毕业至今,接触编程已经五年了,但是真正的编程感觉还没有开始,从大一开始接触C语言,陆续接触c++,java,C#等等,现在感悟到了一点,编程语言学那么多有什么用呢?其实把一门编程语言学精了,学透了,其他的是触类旁通的(底层的C语言和C++可能有点例外),下面我会说一下我的经历,我感觉可能是大多数学习编程人的必经的阶段,让大家对编程的抵触少一些,然后想想一个我这样的白痴都能慢慢的开始程序调试,程序分析,你们绝对比我强的,下篇文章才会进入我的程

程序员突围-程序调试分析(一) 我从菜鸟进化的感悟

程序员突围-程序调试分析(一) 我从菜鸟进化的感悟 在说程序调试分析之前,我们还是了解一些基本的概念性的东西(在下现在从事java,因而都已java为例) 1. bug的分类 根据程序的阶段和MSDN和看过的一些书籍的分析,bug分为编译错误,运行时错误和逻辑的错误 (1)  编译错误 一般初学者犯错比较多的地方,编译错误,说白了就是程序在从java编译成.class文件时出现了问题,这个问题的现象比较明显,比如说语句写的有问题,那么对于这类问题的解决方法是什么呢,翻翻书,翻翻API(翻阅API