MOOS-ivp 实验五 MOOS编程进阶(3)

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++中类的运用不够熟练,导致一直拖到了现在。今天将最后完成的程序做一个发布和总结,实验五到此结束。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值