C++宏,将可读方程转换为相应的代码
C++ macros to convert readable equations into corresponding code
假设我当前有以下代码:
double P[2][2][10];
std::vector<double> b, r, n;
//
// Assume that 10 doubles are pushed to each vector and
// that P has all its allocated values set.
//
for(int t=0; t<10; ++t) {
P[0][0][t] = b[t]*r[t]+n[t];
P[0][1][t] = b[t]*2.0*r[t]+(1.0-n[t]);
P[1][0][t] = b[t]*b[t]+r[t]*n[t];
P[1][1][t] = r[t]+n[t];
}
这是一个微不足道的例子来说明我的问题。在实际情况下,P
通常是P[9][9][100]
,并且方程会更加混乱。基本上,我的问题是,如何使用宏来使这些方程更可读?
特别是,这里有一个不工作的代码片段,来说明我希望这个问题的解决方案看起来如何:
#define P(i,j) P[i][j][t]
#define b b[t]
#define r r[t]
#define n n[t]
for(int t=0; t<10; ++t) {
P(0,0) = b*r+n;
P(0,1) = b*2.0*r+(1.0-n);
P(1,0) = b*b+r*n;
P(1,1) = r+n;
}
此代码片段至少有一个问题。例如,它将根据宏定义展开For循环语句中的"r"answers"n"。但你明白了。
这里的目标是开发一种输入方程的方法,该方法可以更容易地读取和检查错误。我对非宏解决方案持开放态度,尽管在我看来,宏在这里可能会有所帮助。
关于我在上面发布的非工作代码片段,以说明我认为解决方案可能是什么样子。。。是否可以以这样一种方式使用宏,即宏替换仅发生在For循环体内部?或者至少要等到For循环语句之后的?
一个可行的解决方案是定义for
之前的所有宏,然后定义#undef
之后的所有宏。示例:
#define P(i,j) P[i][j][t]
#define b b[t]
#define r r[t]
#define n n[t]
for(int t=0; t<10; ++t) {
P(0,0) = b*r+n;
P(0,1) = b*2.0*r+(1.0-n);
P(1,0) = b*b+r*n;
P(1,1) = r+n;
}
#undef P
#undef b
#undef r
#undef n
在我看来,宏不是解决这个问题的最佳方案,但我找不到任何其他解决方案。
这里好的老式循环局部变量有什么问题?我假设你把向量称为比b
更有意义的东西,所以我会给它们取稍长的名字。我还自由地在你非常密集的方程中添加了一些眼睛清晰度,允许空白:
double P_arr[10][2][2];
std::vector<double> b_arr, r_arr, n_arr;
//
// Assume that 10 doubles are pushed to each vector and
// that P has all its allocated values set.
//
for(int t = 0; t < 10; ++t)
{
const double b = b_arr[t];
const double r = r_arr[t];
const double n = n_arr[t];
double** P = P_arr[t];
P[0][0] = b * r + n;
P[0][1] = b * 2.0 * r + (1.0 - n);
P[1][0] = b * b + r * n;
P[1][1] = r + n;
}
将概念上不同的东西分开通常是个好主意。这通常会大大提高代码的清晰度、可维护性和灵活性。
这里至少有两种不同的东西:
-
您可以循环遍历数据数组。
-
你计算了一些东西。
你能做的最好的事情就是把这些东西分成不同的函数,或者更好的是,类。像这样的东西就可以了:
class MyFavoriteMatrix
{
private:
double m_P[2][2];
public:
MyFavoriteMatrix( double b, double r, double n ) {
m_P[0][0] = b*r+n;
m_P[0][1] = b*2.0*r+(1.0-n);
m_P[1][0] = b*b+r*n;
m_P[1][1] = r+n;
}
double Get( int i, int j ) {
return m_P[i][j];
}
}
然后你的循环会是这样的:
for(int t = 0; t < 10; ++t)
{
// Computation is performed in the constructor
MyFavoriteMatrix mfm( b[t], r[t], n[t] );
// Now put the result where it belongs
P[0][0][t] = mfm.Get( 0, 0 );
P[0][1][t] = mfm.Get( 0, 1 );
P[1][0][t] = mfm.Get( 1, 0 );
P[1][1][t] = mfm.Get( 1, 1 );
}
注意这样的解决方案:
如果您改变了对存储容器的看法(例如,正如Mark B所建议的,出于性能原因,将p[2][2][10]更改为p[10][2][2]),则计算代码根本不会受到影响,只有相对简单的循环会发生一些变化。
如果你需要在10个不同的地方执行相同的计算,你不必复制计算代码:你只需要在那里调用MyFavoriteMatrix。
如果你发现计算代码需要更改,你只需要在一个地方修改它:在MyFavoriteMatrix构造函数中。
每一段代码看起来都很整洁,因此拼写错误的可能性较小。
所有这些都是通过分离概念上不同的东西——计算和迭代得到的。
令人惊讶的是,没有人建议使用引用。http://en.wikipedia.org/wiki/Reference_(C%2B%2B)
typedef double Array22[2][2]; // for convenience...
for(int t = 0; t < 10; ++t)
{
const double &b(b_arr[t]);
const double &r(r_arr[t]);
const double &n(n_arr[t]);
Array22 &P(P_arr[t]);
P[0][0] = b * r + n;
P[0][1] = b * 2.0 * r + (1.0 - n);
P[1][0] = b * b + r * n;
P[1][1] = r + n;
}
这就是运算符的设计目的。下面是一个使用加法和乘法运算符的例子。您仍然需要根据需要添加其他。
#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>
std::vector<int>& operator+(std::vector<int>& a, std::vector<int>& b) {
std::transform (a.begin(), a.end(), b.begin(), a.begin(), std::plus<int>());
return a;
}
std::vector<int>& operator*(std::vector<int>& a, std::vector<int>& b) {
std::transform (a.begin(), a.end(), b.begin(), a.begin(), std::multiplies<int>());
return a;
}
int main() {
int a[6] = {1,2,3,4,5,6};
int b[6] = {6,7,8,9,10,11};
std::vector<int> foo(a, a+6);
std::vector<int> bar(b, b+6);
foo = foo + bar;
std::cout << foo[0] <<std::endl;
}
- 用于将C++代码转换为 Web 程序集的脚本未终止
- 如何将 c++ get 函数代码转换为 opencv 算法中使用的 python
- 将 OpenCV 2 中的ANN_MLP代码转换为 OpenCV 3 代码
- 将 c++ 代码转换为 python,使用运算符?
- 使用 jni 将返回带有模板的对象的 Java 代码转换为 c++
- 如何在 Poco 中将工作 HTTP 代码转换为 HTTPS
- 将C++代码转换为 R 代码以生成数据
- 如何将C++ lambda 函数代码转换为 C#?
- 将 python、numpy 和 scipy 代码转换为兼容C++代码?
- 将本机C 代码转换为Java
- 将C++非托管代码转换为 C#
- 将Qt的QML代码转换为C++
- 将此C 代码转换为MIPS
- 如何将此代码转换为两个以上的数字(计算HCF)
- 想要将此 Matlab 代码转换为 OpenCV 代码
- 尝试将 C++11 代码转换为 C++03 时默认函数模板参数出错
- 将阻止同步代码转换为异步
- 将视觉C 代码转换为Borland C 构建器
- 如何将VDT的Pade Exp fast_ex()的双重版本的标量代码转换为SSE2?
- 将 ML 代码转换为 C++