0

假设我目前有以下代码:

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”和“n”。但你明白了。

这里的目标是开发一种输入方程式的方法,该方法可以更容易地阅读和检查错误。我对非宏解决方案持开放态度,尽管在我看来宏在这里可能会有所帮助。


关于我在上面发布的非工作代码片段来说明我想象的解决方案可能看起来如何......是否可以以宏替换仅发生在 For 循环体内的方式使用宏?或者至少直到For -loop 语句之后?

4

5 回答 5

2

一个可行的解决方案是在 the 之前定义所有宏for,然后#undef在 for 之后定义所有宏。例子:

#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

在我看来,宏不是这个问题的最佳解决方案,但我找不到任何其他解决方案。

于 2013-08-13T16:05:14.580 回答
1

这里好的老式循环局部变量有什么问题?我将假设您将向量称为更有意义的东西,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;
}
于 2013-08-13T16:22:08.513 回答
1

将概念上不同的事物分开通常是个好主意。这通常对提高代码的清晰度、可维护性和灵活性大有帮助。

这里至少有两个不同的东西:

  1. 您遍历数据数组。

  2. 你计算一些东西。

你能做的最好的事情就是把这些东西分成不同的函数,或者更好的类。这样的事情会做:

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 );
}

请注意有关此类解决方案的以下事项:

  1. 如果您对存储容器改变主意(例如,正如 Mark B 所建议的,出于性能原因将 P[2][2][10] 更改为 P[10][2][2]),您的计算代码将不会完全不受影响,只有相对简单的循环会有所改变。

  2. 如果您需要在 10 个不同的地方执行相同的计算,则不必复制计算代码:您只需在那里调用 MyFavoriteMatrix。

  3. 您发现计算代码需要更改您只需要在一个地方修改它:在 MyFavoriteMatrix 构造函数中。

  4. 每段代码看起来都很整洁,因此出现拼写错误的机会更少。

通过分离概念上不同的东西——计算和迭代,你得到的一切。

于 2013-08-13T16:53:38.337 回答
1

没有人建议使用参考文献感到惊讶。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;
}
于 2013-08-13T18:45:24.497 回答
0

这就是运营商旨在帮助解决的问题。这是一个使用加法和乘法运算符的示例。您仍然需要根据需要添加其他内容。

#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;
}
于 2013-08-13T16:56:19.123 回答