作为动态语言,python不需要预先设定数据的类型,非常灵活,而代价就是运行速度慢。与之相反,C++是静态语言,需要声明变量、函数或者类的类型,然后才能定义。因为C++的变量、函数和类等需要声明和定义两个步骤,为了使代码看上去更有条理,可以把它们分成两个部分(.cpp文件)。另外,C++可能需要导入一些库,这些语句可以存放在头文件中(.h文件)。
至于其他函数和语句,python和C++很接近,但又略有不同。比较好的学习方法是相互翻译。比如把一段python代码翻译成C++代码。
本文分成3个部分,第一部分是把一段python代码翻译成C++,并且把C++代码分别存放在3个文件中,目的是比较两种语言在创建变量、函数方面的异同;第二部分则是把一个python类翻译成C++,目的是比较两种语言在创建类方面的异同;第三部分会推荐一些C++的学习资料,供你学习参考。
先来看一段python代码。这段代码表达的意思是,一辆无人车沿着一维道路行走,道路分成5个格子,格子涂成绿色或者红色。无人车在某个格子上停下,检测格子的颜色。无人车移动的距离用move表示。无人车对格子颜色的检测,以及移动的距离都存在误差。正确识别颜色的概率是pHit,错误识别的概率是pMiss;移动正确的距离的概率是pExact,多移动一格的概率是pOvershoot,少移动一格的概率是pUndershoot.
代码中有sense和move两个函数,sense用来识别无人车当前所处格子的颜色,并且计算位于每个格子的概率;move用来计算无人车移动后,位于每个格子的概率。
# 无人车停在每个格子里面的初始概率
p = [0.2, 0.2, 0.2, 0.2, 0.2]
# 创建一维道路
world = ['green', 'red', 'red', 'green', 'green']
# 无人车测量到的颜色
measurements = ['red', 'green']
# 无人车移动的距离
motions = [1,1]
# 正确识别颜色的概率
pHit = 0.6
# 错误识别颜色的概率
pMiss = 0.2
# 移动正确距离的概率
pExact = 0.8
# 多移动一格的概率
pOvershoot = 0.1
# 少移动一格的概率
pUndershoot = 0.1
# 识别当前格子的颜色,计算无人车位于每个格子的概率
def sense(p, Z):
q=[]
for i in range(len(p)):
hit = (Z == world[i])
q.append(p[i] * (hit * pHit + (1-hit) * pMiss))
# 归一化
s = sum(q)
for i in range(len(q)):
q[i] = q[i] / s
return q
# 移动后无人车位于每个格子的概率
def move(p, U):
q = []
for i in range(len(p)):
s = pExact * p[(i-U) % len(p)]
s = s + pOvershoot * p[(i-U-1) % len(p)]
s = s + pUndershoot * p[(i-U+1) % len(p)]
q.append(s)
return q
# 无人车识别、移动两次后,位于每个格子的概率
for k in range(len(measurements)):
p = sense(p, measurements[k])
p = move(p, motions[k])
print(p)
[0.21157894736842103, 0.1515789473684211, 0.08105263157894739, 0.16842105263157897, 0.3873684210526316]
把代码翻译成C++.
注意:代码分成了4个部分,依次是:
// 导入库
#include
#include
#include
// 命名空间
using namespace std;
/* 声明、定义变量。
* 注意,不论是变量、函数还是类,都需要标明数据类型。
* 小数默认是double,如果声明、初始化float,
* 需要在小数后面加上“f”
*/
float pHit = 0.6f;
float pMiss = 0.2f;
float pExact = 0.8f;
float pOvershoot = 0.1f;
float pUndershoot = 0.1f;
// 声明、定义向量
vector p(5, 0.2f);
vector world = { "green", "red", "red", "green", "green" };
vector measurements = { "red", "green" };
vector motions = { 1, 1 };
// 声明函数
vector sense(vector p, string Z);
vector move(vector p, int U);
// main函数,实现无人车识别、移动,并且计算概率
int main()
{
/* 注意C++的for语句和python的用法不同,
* C++的for其实更类似于python的while
*/
for (unsigned int k = 0; k < measurements.size(); k++)
{
p = sense(p, measurements[k]);
p = move(p, motions[k]);
}
for (unsigned int i = 0; i < p.size(); i++)
{
// C++可以通过cout输出数字、字符等
cout << p[i] << endl;
}
// 换行。和python不同,C++不能自动换行
cout << endl;
return 0;
}
// 定义sense函数
vector sense(vector p, string Z)
{
vector q;
for (unsigned int i = 0; i < p.size(); i++)
{
int hit = (Z == world[i]);
// C++向量的push_back方法,类似python列表的append方法
q.push_back(p[i] * (hit * pHit + (1 - hit)*pMiss));
}
float s = 0;
// 遍历向量的每一个元素,这种用法和python的for类似
for (float i : q)
{
s = s + i;
}
// C++向量的size方法,类似python的len函数
for (unsigned int i = 0; i < q.size(); i++)
{
q[i] = q[i] / s;
}
return q;
}
// 定义move函数
vector move(vector p, int U)
{
vector q;
for (unsigned int i = 0; i < p.size(); i++)
{
float s;
/* 注意取余%的用法,C++和python是不同,
* python的取余总是大于等于0,
* 而C++可以是负数。如果希望结果大于等于0,可以加上一个周期的长度
*/
s = pExact * p[(i - U + p.size()) % p.size()];
s = s + pOvershoot * p[(i - U - 1 + p.size()) % p.size()];
s = s + pUndershoot * p[(i - U + 1 + p.size()) % p.size()];
q.push_back(s);
}
return q;
}
0.211579
0.151579
0.0810526
0.168421
0.387368
如果把代码放在3个文件中,代码如下:
function.h文件,又叫做头文件,包含导入库、使用命名空间、声明函数。
// ifndef、define和endif的作用是避免头文件被重复导入
#ifndef FUNCTION_H
#define FUNCTION_H
#include
#include
#include
// 声明函数时用到了vector,需要声明命名空间
using namespace std;
// 声明函数
// 注意:一般不在头文件中声明、定义变量,会报错
vector sense(vector p, string Z);
vector move(vector p, int U);
// 避免头文件被重复导入
#endif /*FUNCTION_H*/
function.cpp文件,包含:
注意:function.cpp文件和main.cpp文件都存在变量的声明、定义。一个变量到底在哪个文件装声明和定义,关键是看哪个文件调用了它。比如,变量pHit,pMiss,pExact,pOvershoot,pUndershoot在函数sense和move中被调用了(不考虑函数声明的调用),所以它们被放在定义了函数sense和move的文件中;而main函数调用了变量p,my_vector, measurements ,motions,所以它们被放在main.cpp文件中。
// 导入头文件
#include "function.h"
// 声明、定义变量
vector world = { "green", "red", "red", "green", "green" };
float pHit = 0.6f;
float pMiss = 0.2f;
float pExact = 0.8f;
float pOvershoot = 0.1f;
float pUndershoot = 0.1f;
// 定义函数
vector sense(vector p, string Z)
{
vector q;
for (int i = 0; i < p.size(); i++)
{
int hit = (Z == world[i]);
q.push_back(p[i] * (hit * pHit + (1 - hit)*pMiss));
}
float s = 0;
for (float i : q)
{
s = s + i;
}
for (int i = 0; i < q.size(); i++)
{
q[i] = q[i] / s;
}
return q;
}
vector move(vector p, int U)
{
vector q;
for (unsigned int i = 0; i < p.size(); i++)
{
float s;
/* C++的取余和python的不同,python的取余总是大于等于0,
* 而C++还可以是负数。如果希望结果大于等于0,
* 要加上一个周期的长度
*/
s = pExact * p[(i - U + p.size()) % p.size()];
s = s + pOvershoot * p[(i - U - 1 + p.size()) % p.size()];
s = s + pUndershoot * p[(i - U + 1 + p.size()) % p.size()];
q.push_back(s);
}
return q;
}
main.cpp,包含:
#include "function.h"
// 声明、定义变量
vector p(5, 0.2f);
vector my_vector = { 1,2,3,4 };
vector measurements = { "red", "green" };
vector motions = { 1, 1 };
int main() {
for (int k = 0; k < measurements.size(); k++)
{
p = sense(p, measurements[k]);
p = move(p, motions[k]);
}
for (int i = 0; i < p.size(); i++)
{
cout << p[i] << endl;
}
cout << endl;
return 0;
}
把python类翻译成C++
"""
两个高斯分布的概率密度函数相乘,计算新的概率密度函数的期望和方差
"""
from math import *
class Gaussian(object):
def __init__(self, average, variance):
# 属性名称前面加上双下划线"__"表示私有变量
self.__mu = average
self.__sigma2 = variance
# 设置私有变量
def setMu(self, average):
self.__mu = average
def setSigma2(self, variance):
self.__sigma2 = variance
# 访问私有变量
def getMu(self):
return self.__mu
def getSigma2(self):
return self.__sigma2
def evaluate(self, x):
coefficient = 1.0 / sqrt(2.0 * pi * self.__sigma2)
exponential = exp(-0.5 * (x-self.__mu)**2 / self.__sigma2)
return coefficient * exponential
def multiply(self, other):
# 计算新函数的期望
denominator = self.__sigma2 + other.__sigma2
numerator = self.__mu * other.__sigma2 + other.__mu * self.__sigma2
new_mu = numerator / denominator
# 计算新函数的方差
new_sigma2 = 1.0 / ((1.0 / self.__sigma2) + (1.0 / other.__sigma2))
# 生成新的高斯分布,返回类的实例
return Gaussian(new_mu, new_sigma2)
def add(self, other):
new_mu = self.__mu + other.__mu
new_sigma2 = self.__sigma2 + other.__sigma2
return Gaussian(new_mu, new_sigma2)
mygaussian = Gaussian(30.0, 20.0)
othergaussian = Gaussian(10.0, 30.0)
print("average ", mygaussian.getMu())
print("evaluation ", mygaussian.evaluate(15.0))
print("mul results sigma ", mygaussian.multiply(othergaussian).getSigma2())
print("mul results average ", mygaussian.multiply(othergaussian).getMu())
print("add results sigma ", mygaussian.add(othergaussian).getSigma2())
print("add results average ", mygaussian.add(othergaussian).getMu())
C++类
gaussian.h
#ifndef GAUSSIAN_H
#define GAUSSIAN_H
#include
#include
class Gaussian
{
private:
float mu, sigma2;
public:
Gaussian();
Gaussian(float average, float variance);
void setMu(float average);
void setSigma2(float variance);
float getMu();
float getSigma2();
float evaluate(float x);
Gaussian multiply(Gaussian other);
Gaussian add(Gaussian other);
};
# endif GAUSSIAN_H
gaussian.cpp
#include "gaussian.h"
Gaussian::Gaussian()
{
mu = 0;
sigma2 = 1;
}
Gaussian::Gaussian(float average, float variance)
{
mu = average;
sigma2 = variance;
}
void Gaussian::setMu(float average)
{
mu = average;
}
void Gaussian::setSigma2(float variance)
{
sigma2 = variance;
}
float Gaussian::getMu()
{
return mu;
}
float Gaussian::getSigma2()
{
return sigma2;
}
float Gaussian::evaluate(float x)
{
float coefficient;
float exponential;
coefficient = 1.0 / sqrt(2.0 * 3.14 * sigma2);
exponential = exp(-0.5 * pow((x - mu), 2) / sigma2);
return coefficient * exponential;
}
Gaussian Gaussian::multiply(Gaussian other)
{
float denominator, numerator, new_mu, new_sigma2;
denominator = sigma2 + other.sigma2;
numerator = mu * other.sigma2 + other.mu * sigma2;
new_mu = numerator / denominator;
new_sigma2 = 1.0 / ((1.0 / sigma2) + (1.0 / other.sigma2));
return Gaussian(new_mu, new_sigma2);
}
Gaussian Gaussian::add(Gaussian other)
{
float new_mu, new_sigma2;
new_mu = mu + other.mu;
new_sigma2 = sigma2 + other.sigma2;
return Gaussian(new_mu, new_sigma2);
}
main.cpp
#include "gaussian.h"
int main()
{
// 创建默认实例
Gaussian fun1;
// 给实例赋值
Gaussian mygaussian(30.0, 20.0);
Gaussian othergaussian(10.0, 30.0);
std::cout << "average " << mygaussian.getMu() << std::endl;
std::cout << "evaluation " << mygaussian.evaluate(15.0) << std::endl;
std::cout << "mul results sigma " << mygaussian.multiply(othergaussian).getSigma2() << std::endl;
std::cout << "mul results average " << mygaussian.multiply(othergaussian).getMu() << std::endl;
std::cout << "add results sigma " << mygaussian.add(othergaussian).getSigma2() << std::endl;
std::cout << "add results average " << mygaussian.add(othergaussian).getMu() << std::endl;
return 0;
}
明白了如何把python代码翻译成C++,我们再来看看python类和C++类的异同。
下面是python代码编写的一个类Gaussian,目的是进行两个概率密度函数之间的计算。
# 导入math库
from math import *
# 定义Gaussian类
class Gaussian(object):
# 构造函数
def __init__(self, average, variance):
# 属性名称前面加上双下划线"__"表示私有变量
self.__mu = average
self.__sigma2 = variance
# 设置私有变量。
# 外界无法赋值私有变量,需要通过该函数
def setMu(self, average):
self.__mu = average
def setSigma2(self, variance):
self.__sigma2 = variance
# 访问私有变量。
# 外界无法访问私有变量,需要通过该函数
def getMu(self):
return self.__mu
def getSigma2(self):
return self.__sigma2
# 输入概率密度函数的x值,返回y值
def evaluate(self, x):
coefficient = 1.0 / sqrt(2.0 * pi * self.__sigma2)
exponential = exp(-0.5 * (x-self.__mu)**2 / self.__sigma2)
return coefficient * exponential
# 两个概率密度函数相乘,
# 返回新的概率密度函数的实例
def multiply(self, other):
# 计算新函数的期望
denominator = self.__sigma2 + other.__sigma2
numerator = self.__mu * other.__sigma2 + other.__mu * self.__sigma2
new_mu = numerator / denominator
# 计算新函数的方差
new_sigma2 = 1.0 / ((1.0 / self.__sigma2) + (1.0 / other.__sigma2))
# 生成新的高斯分布,返回类的实例
return Gaussian(new_mu, new_sigma2)
# 两个概率密度函数相加,返回新的概率密度函数的实体
def add(self, other):
new_mu = self.__mu + other.__mu
new_sigma2 = self.__sigma2 + other.__sigma2
return Gaussian(new_mu, new_sigma2)
# 实体化
mygaussian = Gaussian(30.0, 20.0)
othergaussian = Gaussian(10.0, 30.0)
# 通过getMu访问私有变量
print("average ", mygaussian.getMu())
average 30.0
print("evaluation ", mygaussian.evaluate(15.0))
evaluation 0.00032172781336966156
print("mul results sigma ", mygaussian.multiply(othergaussian).getSigma2())
mul results sigma 11.999999999999998
print("mul results average ", mygaussian.multiply(othergaussian).getMu())
mul results average 22.0
print("add results sigma ", mygaussian.add(othergaussian).getSigma2())
add results sigma 50.0
print("add results average ", mygaussian.add(othergaussian).getMu())
add results average 40.0
把上面的代码翻译成C++类
gaussian.h文件:声明类
#ifndef GAUSSIAN_H
#define GAUSSIAN_H
#include
#include
class Gaussian
{
// 声明私有成员
private:
float mu, sigma2;
// 声明公开成员
public:
// 声明默认构造函数
Gaussian();
// 声明构造函数
Gaussian(float average, float variance);
// 声明函数
void setMu(float average);
void setSigma2(float variance);
float getMu();
float getSigma2();
float evaluate(float x);
Gaussian multiply(Gaussian other);
Gaussian add(Gaussian other);
};
# endif GAUSSIAN_H
gaussian.cpp文件:定义类
#include "gaussian.h"
// 定义默认构造函数,变量mu和sigma赋予了默认值
Gaussian::Gaussian()
{
mu = 0;
sigma2 = 1;
}
// 定义构造函数,变量mu和sigma没有赋值
Gaussian::Gaussian(float average, float variance)
{
mu = average;
sigma2 = variance;
}
// 定义函数
void Gaussian::setMu(float average)
{
mu = average;
}
void Gaussian::setSigma2(float variance)
{
sigma2 = variance;
}
float Gaussian::getMu()
{
return mu;
}
float Gaussian::getSigma2()
{
return sigma2;
}
float Gaussian::evaluate(float x)
{
float coefficient;
float exponential;
coefficient = 1.0 / sqrt(2.0 * 3.14 * sigma2);
exponential = exp(-0.5 * pow((x - mu), 2) / sigma2);
return coefficient * exponential;
}
Gaussian Gaussian::multiply(Gaussian other)
{
float denominator, numerator, new_mu, new_sigma2;
denominator = sigma2 + other.sigma2;
numerator = mu * other.sigma2 + other.mu * sigma2;
new_mu = numerator / denominator;
new_sigma2 = 1.0 / ((1.0 / sigma2) + (1.0 / other.sigma2));
return Gaussian(new_mu, new_sigma2);
}
Gaussian Gaussian::add(Gaussian other)
{
float new_mu, new_sigma2;
new_mu = mu + other.mu;
new_sigma2 = sigma2 + other.sigma2;
return Gaussian(new_mu, new_sigma2);
}
main.cpp
#include "gaussian.h"
int main()
{
// 创建默认实例。这里调用的是默认构造函数
Gaussian fun1;
// 创建实例,并且给实例赋值。这里调用的是构造函数
Gaussian mygaussian(30.0, 20.0);
Gaussian othergaussian(10.0, 30.0);
std::cout << "average " << mygaussian.getMu() << std::endl;
std::cout << "evaluation " << mygaussian.evaluate(15.0) << std::endl;
std::cout << "mul results sigma " << mygaussian.multiply(othergaussian).getSigma2() << std::endl;
std::cout << "mul results average " << mygaussian.multiply(othergaussian).getMu() << std::endl;
std::cout << "add results sigma " << mygaussian.add(othergaussian).getSigma2() << std::endl;
std::cout << "add results average " << mygaussian.add(othergaussian).getMu() << std::endl;
return 0;
}
python类是一个非常重要的概率,在《无人驾驶入门》以及无人驾驶领域,都有着非常重要的应用。而课程对C++的要求却并不高。这是因为在无人驾驶领域,编写代码使用的主要还是python,但是因为C++运行速度快,所以最终需要把python代码翻译成C++.下面推荐一些python类和C++的学习资料。
我是《无人驾驶入门》纳米学位的学长,希望这些经验对你有帮助。如果你对udacity的这门课程也感兴趣,可以使用我的优惠码:839662C0,付款时在优惠码框输入,可以抵扣300元学费(限第一次购买udacity课程的学弟学妹用哈)。