MOOS-ivp 实验五 MOOS编程进阶(3)
经过近日的学习与摸索,我来重新完善以下实验五的相关内容,上次做到三分之二的内容放弃了,主要原因还是因为C++功底不够深厚,需要更多的学习和积累。经过我的一番学习以及在github上对相关资料进行查找,把程序做了进一步的完善,基本上实现了实验所要求的相关功能。
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
六、质因数算法分解程序
1.要求
我们首先对一开始实验所设定的要求进行回顾。
主要任务:
(1)实验中订阅的变量为:NUM_VALUE,这是一个最长可以到64位的非负整数
(2)输入变量的格式是字符串格式,需要将其转化为数字格式进行处理
(3)需要创建一个list,其中包含了各种算法处理的变量,最好的办法是将算法写成一个.cpp程序
(3)实验中发布的变量为:PRIME_RESULT
(4)最终发布的结果格式:PRIME_RESULT = “orig=90090,received=34,calculated=33,solve_time=2.03,
primes=2:3:3:5:7:11:13,username=jane”
(5)长数据的处理过程不能阻挡较短数据的处理,它们应该同时进行处理,较短数据一经处理完成之后就应该发布和在list中删除
(6)不使用已知的缓存的素数数据进行处理
2.程序中的订阅
我们需要在OnNewMail()函数里对变量进行订阅,但是由于订阅得到的变量是字符串类型,所以需要现将其转化为数据类型。这个具体操作在MOOS-ivp 实验五 MOOS编程进阶(1)中已经有详细讲解,下面直接上程序:
bool PrimeFactor::OnNewMail(MOOSMSG_LIST &NewMail)
{
MOOSMSG_LIST::iterator p;
for(p=NewMail.begin(); p!=NewMail.end(); p++) {
CMOOSMsg &msg = *p;
string key = msg.GetKey();
string sval = msg.GetString();
if (key=="NUM_VALUE"){
//进行数据转换
m_index++;
stringstream temp(sval);
m_ival = 0;
temp >> m_ival;
//将我们定义好的PrimeEntry类变量存入list中
PrimeEntry m_prime;
m_prime.setOriginalVal(m_ival);
m_prime.setReceivedIndex(m_index);
m_mail_list.push_back(m_prime);
}
}
3.程序中的发布
程序发布的主要内容是写在函数Iterate()之中的,其主要作用是检查质因数计算是否完成,如果质因数计算完成,那么发布变量内容
bool PrimeFactor::Iterate()
{
//设定最大循环步数
m_max_iter=100000; // m_max_iter=1000000;
//遍历整个列表
for(std::list<PrimeEntry>::iterator k=m_mail_list.begin();k!=m_mail_list.end();k++){
// 计算质因数
PrimeEntry& m_prime_entry=*k;
m_prime_entry.factor(m_max_iter);
//如果完成质因数计算之后,发布变量并且将其从list中进行删除
if (m_prime_entry.done()){
m_calc++;
m_prime_entry.setCalculatedIndex(m_calc); //Update index calculated
m_max_iter=m_max_iter-m_prime_entry.iter_calc(); // Update max _iter
m_result_str=m_prime_entry.getReport();
Notify("NUM_RESULT",m_result_str);
k=m_mail_list.erase(k); //从list中删除
}
else{ //经过最长步数仍未完成质因数计算,跳出,进入下一个数据的计算。
break;
}
}
return(true);
}
4.新建文件添加
我们首先需要定义一个相关的类,命名为PrimeEntry。其主要作用就是用于质因数的相关计算,并且记录下关于质因数计算结果的相关内容,我们将类的相关定义写到头文件里。在创建完成头文件和.cpp文件之后需要将其添加到该目录下的CMAKEList文件之中去,否则无法对其进行编译。
下面是具体内容
#--------------------------------------------------------
# The CMakeLists.txt for: pPrimeFactor
# Author(s): Pitt Gao
#--------------------------------------------------------
# FILE(GLOB SRC *.cpp)
SET(SRC
PrimeFactor.cpp
PrimeFactor_Info.cpp
main.cpp
PrimeEntry.cpp
)
ADD_EXECUTABLE(pPrimeFactor ${SRC})
TARGET_LINK_LIBRARIES(pPrimeFactor
${MOOS_LIBRARIES}
mbutil
m
pthread)
#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
5.PrimeEntry头文件设定
// File: PrimeEntry.h
#include <string>
#include <vector>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <sstream>
#include "MOOS/libMOOS/Utils/MOOSUtils.h"
#ifndef PRIME_ENTRY_HEADER
#define PRIME_ENTRY_HEADER
class PrimeEntry
{
public:
PrimeEntry();
~PrimeEntry() {};
void setOriginalVal(unsigned long int v); //Set original value
void setReceivedIndex(unsigned int v);
void setCalculatedIndex(unsigned int v);
void setDone(bool v);
bool done();
long unsigned int iter_calc();
void factor(unsigned long int max_steps); //Factoring function for a certain number of steps
std::string getReport(); //String to print out report
protected:
unsigned long int m_N; //Updated number to factor
unsigned long int m_orig; //Original prime number
bool m_done; //True or false if done with factoring
unsigned long int m_received_index;
unsigned long int m_calculated_index;
unsigned long int m_finished_iter;
unsigned long int m_maxiter;
unsigned long int m_ii;
unsigned long int m_k_start;
unsigned long int m_k;
double m_start_time, m_finish_time, m_solve_time;
std::vector<unsigned long int> m_factors; //Vector of all the factors so far
};
#endif
这里用到了标准模板库中的向量vector,主要作用是在后续计算中对于已经求解出的质因数进行存储。定义了一系列函数,来对我们的类的变量进行赋值或者读取数值的操作。主要计算函数是factor()函数,主要作用是对质因数进行计算,计算过程和之前的程序类似,都是从2逐渐增加到输入数据的开根号不断进行取余运算。下面是代码:
void PrimeEntry::factor(unsigned long int max_steps){
//Reset iterations of factor function.
m_ii=0;
if (m_N==0){ //第一次运算进入
m_N=m_orig;
m_k=2;
m_start_time=MOOSTime();
}
while (m_k<=ceil(sqrtl(m_N))){
m_ii++; // Add iteration
if (m_ii>max_steps){ //Reached max steps, stop factoring
break;
}
if (m_N%m_k==0){ //Divisible
m_factors.push_back(m_k);
m_N=m_N/m_k; // Update N_m
m_k=2; //Reset k.
}
m_k++;
}
//确定是否完成计算
if (m_k>=ceil(sqrtl(m_N))){ //Finished
m_finished_iter=m_ii;
m_finish_time=MOOSTime();
if (m_N!=1){ //Add last (prime) number
m_factors.push_back(m_N);
}
setDone(true);
}
else{
setDone(false);
}
}
在完成相关运算之后需要对程序按照既定格式进行发布,主要内容在函数getReport()中进行数学,定义了一个string类型的函数,下面是其相关代码:
std::string PrimeEntry::getReport(){
//Print results: orig=90090,received=34,calculated=33,solve_time=2.03, primes=2:3:3:5:7:11:13,username=jane"
std::stringstream ss;
ss << "orig ="<<m_orig<<", received="<<m_received_index<<", calculated="<<m_calculated_index<<", "<<"solve_time=";
m_solve_time=m_finish_time-m_start_time; // Calculate time.
ss<<m_solve_time<<", ";
std::vector<unsigned long int>::iterator p;
ss<<"primes=";
std::sort(m_factors.begin(),m_factors.end()); //Sort factors.
for(p=m_factors.begin();p!=m_factors.end();p++){
ss<<*p<<":";
}
ss.seekp(-1, std::ios_base::end); //Delete last ":"
ss<<", username=PittGao"<<std::endl;
//Return ss stream object
return ss.str();
}
七、测试和查看实验记录
1.添加测试内容
为了测试我们的程序是否能顺利运行,我们需要一些数据对其进行测试,在我们的.moos文件中添加入以下uTimerScript模块,可以在不同时间内循环发布一定位数的字符串格式的变量。
ProcessConfig = uTimerScript
{
AppTick = 4
CommsTick = 4
paused = false
event = var=NUM_VALUE, val="$(15)", time=0.25
event = var=NUM_VALUE, val="$(9)", time=0.50
event = var=NUM_VALUE, val="$(7)", time=0.75
event = var=NUM_VALUE, val="$(5)", time=1.00
reset_max = nolimit
reset_time = all-posted
}
2.查看日志
有了不断发布的数据之后,我们希望可以查看我们自己的相应数据记录,需要在.moos文件里添加以下pLogger模块
ProcessConfig = pLogger
{
AsyncLog = true
WildCardLogging = true
WildCardOmitPattern = *_STATUS
LOG = PRIME_RESULT @ 0
LOG = NUM_VALUE @ 0
}
要记得在初始运行配置里添加启动
ProcessConfig = ANTLER
{
MSBetweenLaunches = 200
Run = MOOSDB @ NewConsole = false
Run = uXMS @ NewConsole = true ~uXMS
Run = uTimerScript @ NewConsole = false
Run = pPrimeFactor @ NewConsole = false
Run = pLogger @ NewConsole = false
}
运行之后,我们发布的数据和结果便会生成一个写有日期的文件夹,里面包含了相关的实验日志。
点击进入之后,打开相应的日志文件,使用以下命令对我们所需要的关键信息进行查看
aloggrep MOOSLog_27_10_2020_____09_22_24.alog NUM_RESULT NUM_VALUE
可以显示以下内容
这样可以通过生成的数据核对我们的程序是否有问题。
总结
一个本该尽早完成的实验,因为对list和vector以及C++中类的运用不够熟练,导致一直拖到了现在。今天将最后完成的程序做一个发布和总结,实验五到此结束。