MOOS-ivp 实验五 MOOS编程进阶(1)
到了实验五,需要要完成一个比实验四更加复杂的程序:主要是对于长整数进行质因数的分解。
文章目录
前言
此次实验的难点是在处理数据的过程中,不仅处理长度较小的数据,同时也处理长度较大的数据。并且先将长度较小的数据进行发布。整个程序运行在4HZ之下,但是数据的发布不仅仅是4HZ,这就需要我们利用一些关于C++STL中list的一些函数。
一、创建程序
此次程序最主要的内容就是实现长短数据的质因数的分解。
创建程序的主要详细过程在实验四(一)中有详细的讲解,现在再次简单进行列举:
GenMOOSApp PrimeFactor p "John Doe"
主要任务:
(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)不使用已知的缓存的素数数据进行处理
二、C++的一些补充
1.无符号长整型数据
因为在程序运行过程中,我们所接受到的非负整数最长的格式为64位整数,在寻常我们做整数处理的过程中都是使用类似于double的数据格式进行处理,但如果长度到达了64位那么double就无法对长数据进行处理了,它可能会对数据进行压缩,使得数据的结果不准确。
查看例子的代码如下(示例):
uint64_t value1 = 184467440739429084;
double value2 = 184467440739429084;
cout << "value 1: " << value1 << endl;
cout << "value 2: " << fixed << value2 << endl;
同样是输入一个长数据,但是返回的结果如下:
value 1: 184467440739429084
value 2: 184467440739429088;
可以看到double类型的数据会被压缩,使得数据不再精准。在MOOS中如果想要发布一个长数据的话,通常是使用字符串来进行实现的。
2.字符串和数字之间的相互转换
如果想要定义64的长数据类型,可以通过添加头文件来进行处理。
代码如下(示例):
#include <cstdint>
uint64_t value = 0;
在linux系统中直接使用还是会报错,于是我又继续用了typedef在头文件中又声明了一次。
typedef unsigned long long uint64_t;
如果发布的内容是字符串格式的话
NUM VALUE="5674032334252535".
那么我们需要利用如下语句来进行处理
#include <cstdlib> // for the strtoul() function
string str = "5674032334252535"
uint64_t value = strtoul(str.c_str(), NULL, 0);
C 库函数 - strtoul()
C语言之strtoul()—字符串转换成无符号长整形
函数的主要作用就是讲字符串转化为数字格式。而c_str()函数的作用是返回所对应字符串的一个指针,后面的两个变量结尾默认选项,NULL代表不返回字符串结尾对应的指针,0代表讲字符串按照十进制进行转换。
另一方面,如果想要把数字转换为字符串的话需要添加以下头文件:
// Include the stringstream header file
#include <sstream>
....
// Create the biggest unsigned long int possibe
uint64_t ival = 18446744073709551615;
// Convert it to a string
stringstream ss;
ss << ival;
string str = ss.str();
// Confirm it works
cout << "Value:" << str << endl;
具体内容可以参考网站stringstream用法
stringstream clear与str("")的问题
std :: stringstream :: str
stringstream是C++提供的模板库中的(stream)物件,作用是将数据可以转换成字符串的格式。str = ss.str();的作用是返回字符串的内容,还有第二个用法,是清空stream缓存区中的缓存。
三、程序的初步测试
首先我们的程序是可以对数据进行接受和处理的,这是完成接下来实验的第一步,所以我们编写一个简单的小程序来验证我们接受和处理数据的功能是否实现。这里简单写一个判断数据是奇数还是偶数的程序,然后进行发布。
1.接受和处理数据
我们将接受和发布数据的内容先全部都写到OnNewMail()函数当中去,如果能正常发布:
NUM RESULT = “37,odd”
这样就说明我们的接受和处理数据是没有问题的。下面是我写的OnNewMail()函数的主要内容,一些我自己定义的变量都在头文件中进行了声明,在类的构造函数里进行了初始化处理。
//---------------------------------------------------------
// Procedure: OnNewMail
bool PrimeFactor::OnNewMail(MOOSMSG_LIST &NewMail)
{
MOOSMSG_LIST::iterator p;
for(p=NewMail.begin(); p!=NewMail.end(); p++) {
CMOOSMsg &msg = *p;
#if 0 // Keep these around just for template
string key = msg.GetKey();
string comm = msg.GetCommunity();
double dval = msg.GetDouble();
string sval = msg.GetString();
string msrc = msg.GetSource();
double mtime = msg.GetTime();
bool mdbl = msg.IsDouble();
bool mstr = msg.IsString();
#endif
string key = msg.GetKey();
if(key == "NUM_VALUE")//判断奇数偶数
{
string m_str = msg.GetString();
m_value = msg.GetDouble();
m_value = strtoul(m_str.c_str(), NULL, 0);
if ( m_value % 2 == 0)
{
// Convert it to a string
stringstream ss;
ss << m_value;
string str = ss.str();
// Confirm it works
Notify("NUM_RESULT", str+" even");
}
else
{
stringstream ss;
ss << m_value;
string str = ss.str();
// Confirm it works
Notify("NUM_RESULT", str+" odd");
}
}
}
return(true);
}
程序很简单,具体不解释了。
2.测试程序
程序写好之后进行cmake编译,具体操作在实验四中讲过了,之后我们需要对其进行测试。首先打开MOOSDB,使得可以订阅和发布变量。接下来打开uXMS scope,使得可以观察变量的变化情况。启动uTimerScript脚本,循环发布变量,观察结果。具体过程可以在.moos文件中进行书写。下面是.moos文件的具体内容:
ServerHost = localhost
ServerPort = 9000
Community = alpha
ProcessConfig = ANTLER
{
MSBetweenLaunches = 200
Run = MOOSDB @ NewConsole = false
Run = uXMS @ NewConsole = true ~uXMS
Run = uTimerScript @ NewConsole = false
Run = pPrimeFactor @ NewConsole = false
}
ProcessConfig = uXMS
{
AppTick = 4
CommsTick = 4
VAR = NUM_VALUE,NUM_RESULT
COLOR_MAP = NUM_VALUE, red
COLOR_MAP = NUM_RESULT, blue
}
//------------------------------------------------
// pPrimeFactor config block
ProcessConfig = pPrimeFactor
{
AppTick = 4
CommsTick = 4
}
ProcessConfig = uTimerScript
{
AppTick = 4
CommsTick = 4
event = var=NUM_VALUE, val="22", time = 0.50
event = var=NUM_VALUE, val="234", time = 1.00
event = var=NUM_VALUE, val="117", time = 1.50
reset_max = nolimit
reset_time = all-posted
}
下面是结果显示:
总结
第一部分内容主要是对一些C++长数据类型及其转换进行讲解,接下里是对程序进行初步测试。主要目的还是为了接下来的复杂程序进行铺垫。