3

先做一点介绍:

我是一个新手 C++ 程序员(我是编程新手)正在编写一个小乘法表练习程序。该项目最初是一个小程序,旨在自学编程基础知识,随着我对编程的了解越来越多,我不断添加新功能。起初它只有一些基础知识,比如请求输入、循环和 if-else 语句。但现在它使用向量、读写文件、创建目录等。

您可以在此处查看代码:Bitbucket 上的项目

我的程序现在将有 2 种模式:练习用户可以自己选择的单个乘法表或混合练习所有乘法表。现在两种模式在内部的工作方式完全不同。而且我将混合模式开发为一个单独的程序,这样可以简化开发,我可以只专注于编写代码本身,而不是打扰如何将它集成到现有代码中。

下面是目前分离的混合模式程序的代码:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
#include <time.h> 

using namespace std;
using std::string;

int newquestion(vector<int> remaining_multiplication_tables, vector<int> multiplication_tables, int table_selecter){
  cout << remaining_multiplication_tables[table_selecter] << " * " << multiplication_tables[remaining_multiplication_tables[table_selecter]-1]<< " =" << "\n";
  return remaining_multiplication_tables[table_selecter] * multiplication_tables[remaining_multiplication_tables[table_selecter]-1];
}

int main(){
  int usersanswer_int;
  int cpu_answer;
  int table_selecter;
  string usersanswer;
  vector<int> remaining_multiplication_tables = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  vector<int> multiplication_tables(10, 1);//fill vector with 10 elements that contain the value '1'. This vector will store the "progress" of each multiplication_table.
  srand(time(0));

  table_selecter = rand() % remaining_multiplication_tables.size();
  cpu_answer = newquestion(remaining_multiplication_tables, multiplication_tables, table_selecter);
  while(remaining_multiplication_tables.size() != 0){
    getline(cin, usersanswer);
    stringstream usersanswer_stream(usersanswer);
    usersanswer_stream >> usersanswer_int;
    if(usersanswer_int == cpu_answer){
      cout << "Your answer is correct! :)" << "\n";
      if(multiplication_tables[remaining_multiplication_tables[table_selecter]-1] == 10){
       remaining_multiplication_tables.erase(remaining_multiplication_tables.begin() + table_selecter);
      }
      else{
    multiplication_tables[remaining_multiplication_tables[table_selecter]-1] +=1;
      }
      if (remaining_multiplication_tables.size() != 0){
    table_selecter = rand() % remaining_multiplication_tables.size();
    cpu_answer = newquestion(remaining_multiplication_tables, multiplication_tables, table_selecter);
      }
    }
    else{
      cout << "Unfortunately your answer isn't correct! :(" << "\n";
    } 
  }
  return 0;
}

如您所见,混合模式的新问题功能完全不同。while 循环还包括其他混合模式特定代码。

现在,如果我想将混合乘法表模式集成到现有的主程序中,我有 2 个选择: -我可以使用 if-else 语句将 while 循环弄乱,以检查每次循环运行时是否模式 == 10(单乘法表mode)或 mode == 100(混合乘法表模式)。并且还在 newquestion() 函数中放置一个 if-else 语句来检查模式 == 10 或模式 == 100 -我可以让程序在启动时检查用户是选择单乘法表还是混合乘法表模式并创建 2 while 循环和 2 个 newquestion() 函数。看起来像这样:

int newquestion_mixed(){
 //newquestion function for mixed mode
}
int newquestion_single(){
 //newquestion function for single mode
}

//initialization
if mode == 10
 //create necessary variables for single mode
 while(){
  //single mode loop
 }
else{
 //create necessary variables for mixed mode
 while(){
  //mixed mode loop
 }
}

现在我为什么还要费心创建 2 个单独的循环和函数呢?如果程序在每次循环运行时检查(每次用户被问到一个新问题,例如:'5 * 3 =')用户​​选择了哪种模式,这不是效率低下吗?我担心这个选项的性能。现在我听到您的想法:但是,您为什么要为这样一个简单的、非性能关键的小型应用程序以及当今极其强大的处理器和大量 RAM 的性能而烦恼呢?好吧,正如我之前所说,这个程序主要是关于教自己一个良好的编码风格和学习如何编程等。所以我想从一开始就教自己良好的习惯。

2 while 循环和函数选项效率更高,将使用更少的 CPU,但更多的空间并包括重复代码。我也不知道这是否是一种好风格。

所以基本上我在问专家什么是处理这类事情的最佳风格/方式。另外,如果您发现我的代码/不好的风格有什么不好的地方,请告诉我,我非常愿意接受反馈,因为我还是个新手。;)

4

2 回答 2

5

首先,编程的一个基本规则是“不要过早地优化代码”——也就是说,在代码正常工作之前不要摆弄小细节,并编写表达你想要完成的代码的代码尽可能清楚。这是很好的编码风格。沉迷于“哪个更快”的细节(在一个循环中,大部分时间都在等待用户输入一些数字)不是好的编码风格。

一旦它正常工作,分析(例如使用分析器工具)代码在哪里花费时间(假设性能首先是一个主要因素)。一旦你找到了主要的“热点”,然后试着以某种方式让它变得更好——你如何去做很大程度上取决于那个特定的热点代码的作用。

至于哪个性能最好,很大程度上取决于代码和编译器的细节(以及选择了哪些编译器优化)。在 while 循环中使用 if 很可能会运行得更慢,但是现代编译器非常聪明,而且我确实看到了编译器在条件不满足的情况下将这样的选择提升到循环之外的情况改变。拥有两个while循环对于编译器来说更难“做得更好”,因为它很可能不会看到你在两个循环中都在做同样的事情[因为编译器从解析树的底部向上工作,并且它将首先优化 while 循环的内部,然后转到 if-else 侧,此时它“丢失了”每个循环内部发生的事情]。

哪个更清楚,有一个带有 if 内部的 while 循环,或者一个带有两个 while 循环的 if,这是另一个好问题。

当然,面向对象的解决方案是有两个类——一个用于混合,另一个用于单一——并且只运行一个循环,它在循环之前调用基于 if-else 语句创建的对象的相关(虚拟)成员函数.

于 2013-04-27T11:08:45.233 回答
1

现代 CPU 分支预测器非常好,如果在循环期间条件永远不会改变,它可能会像在每个分支中有两个 while 循环一样快。

于 2013-04-27T11:09:30.143 回答