【问题标题】:How to make my function work for arbitrary dimensionality in C如何使我的函数适用于 C 中的任意维度
【发布时间】:2021-07-08 03:47:48
【问题描述】:

我有一个数学函数,我想在 1d、2d 和 3d 空间中使用它。我编写了适用于 3-d 案例的代码,并且可以轻松地为其他案例修改它,但是我想知道是否有一种方法可以编写它,以便它适用于任意维度。基本上每个维度都有另一个嵌套循环,我不知道如何制作多个嵌套循环而不实际将它们写在代码中。

void gen_kernel_Gk(double *Gk, double L, double b, int np, int Z, int m)
{
    // Generates Kernel Function G in k-space
    // Gk is the array of the function values, it has Z * m number of values
    // L is cuttoff distance
    // b is monomer size
    // np is the degree of polymerization
    // Z is the number of modes
    // m is the dimensionality of the real space

    int i, j, k, l, index, Zhalf;
    double pref, kvec[m], k2;

    pref = pow( 2 * PI / (double)L, 2) * pow( b, 2) * (double)np / 6.0;

    Zhalf = Z / 2;

    for( i = 0; i < Z; ++i)
    {
        if( i < Zhalf)
        {
            kvec[0] = (double) pow( i, 2);
        }
        else
        {
            kvec[0] = (double) pow ( Z - i ,2);
        }

        for( j = 0; j < Z; ++j)
        {
            if( i < Zhalf)
            {
                kvec[1] = (double) pow( j, 2);
            }
            else
            {
                kvec[1] = (double) pow ( Z - j ,2);
            }

            for( k = 0 ; k < Z ; ++k)
            {
                if( k < Zhalf)
                {
                    kvec[2] = (double) pow( k, 2);
                }
                else
                {
                    kvec[2] = (double) pow ( Z - k ,2);
                }

                for( k2 = 0, l = 0; l < m; ++l)
                {
                    k2 += kvec[l];
                }

                index = i * pow( Z, 2) + j * Z + k;
                Gk[index] = 2.0 * ( exp( -k2) + k2 - 1.0) / pow( k2, 2);
            } 
        }
    }
    return;
}

【问题讨论】:

  • 您可以使用递归,也可以使用您的维度大小的堆栈来存储循环变量并在那里管理它们。递归会更简单。
  • @paddy,我有兴趣看到解决方案。递归不是我的强项,我什至不确定现在从哪里开始使用您提到的自定义堆栈解决方案,我也希望看到。
  • @GabrielStaples 我添加了答案以展示基于递归的解决方案的原理
  • 检查我的 bool nested_for(double *a0,double *a,double *a1,double *da,int &amp;ix,int N) 它基本上将所有 N 嵌套的 for 循环序列化为单次迭代调用 API ...它的 C++ 但应该很容易移植到 C。如果你想要真正的 ND math 和东西然后 C不是好选择,因为您缺少模板和类...部分您可以使用宏解决此问题,但只能达到一定程度

标签: c math nested-loops


【解决方案1】:

如果您想要任意数量的嵌套 for 循环,您可以寻求使用递归的解决方案。

具体如何操作取决于您的具体任务。下面的示例并非完全基于您的代码,而是显示原理的更通用的代码示例。希望您能看到这个想法并将其应用到您的特定任务中。

基本思想是递归函数需要参数来描述诸如维数和每个维的大小(在数组中)以及当前级别/索引等内容。为了解决特定任务,您可能需要添加额外的参数。

喜欢:

#include <stdio.h>
#include <assert.h>

void opr(const unsigned dimensions, const unsigned * dimsize, 
         unsigned curdim, unsigned * curindex)
{
  assert(curdim < dimensions);
  for (unsigned u = 0; u < dimsize[curdim]; ++u)
  {
    // Save the current index
    curindex[curdim] = u;

    // Check if the last dimension has been reached
    if (curdim == (dimensions - 1))
    {
      // yes, last dimension has been reached - now do the operation you want...
      // Here the code just do a simple print
      printf("Handle array element at ");
      for (unsigned t = 0; t < dimensions; ++t)
      {
        printf("[%u]", curindex[t]);
      }
      printf("\n");
    }
    else
    {
      // no, last dimension has NOT been reached
      // so do a recursive call for the next dimension
      opr(dimensions, dimsize, curdim + 1, curindex);
                    // notice: ^^^^^^^^^^ increase current dimension 
    }
  }
}

int main(void)
{
  unsigned dimsizeA[] = {2, 3};  // [2][3]
  unsigned dimensionsA = sizeof dimsizeA / sizeof dimsizeA[0];
  unsigned curindexA[] = {0, 0};
  opr(dimensionsA, dimsizeA, 0, curindexA);

  printf("-----------------------------------\n");

  unsigned dimsizeB[] = {2, 3, 3, 2};  // [2][3][3][2]
  unsigned dimensionsB = sizeof dimsizeB / sizeof dimsizeB[0];
  unsigned curindexB[] = {0, 0, 0, 0};
  opr(dimensionsB, dimsizeB, 0, curindexB);

  return 0;
}

输出:

Handle array element at [0][0]
Handle array element at [0][1]
Handle array element at [0][2]
Handle array element at [1][0]
Handle array element at [1][1]
Handle array element at [1][2]
-----------------------------------
Handle array element at [0][0][0][0]
Handle array element at [0][0][0][1]
Handle array element at [0][0][1][0]
Handle array element at [0][0][1][1]
Handle array element at [0][0][2][0]
Handle array element at [0][0][2][1]
Handle array element at [0][1][0][0]
Handle array element at [0][1][0][1]
Handle array element at [0][1][1][0]
Handle array element at [0][1][1][1]
Handle array element at [0][1][2][0]
Handle array element at [0][1][2][1]
Handle array element at [0][2][0][0]
Handle array element at [0][2][0][1]
Handle array element at [0][2][1][0]
Handle array element at [0][2][1][1]
Handle array element at [0][2][2][0]
Handle array element at [0][2][2][1]
Handle array element at [1][0][0][0]
Handle array element at [1][0][0][1]
Handle array element at [1][0][1][0]
Handle array element at [1][0][1][1]
Handle array element at [1][0][2][0]
Handle array element at [1][0][2][1]
Handle array element at [1][1][0][0]
Handle array element at [1][1][0][1]
Handle array element at [1][1][1][0]
Handle array element at [1][1][1][1]
Handle array element at [1][1][2][0]
Handle array element at [1][1][2][1]
Handle array element at [1][2][0][0]
Handle array element at [1][2][0][1]
Handle array element at [1][2][1][0]
Handle array element at [1][2][1][1]
Handle array element at [1][2][2][0]
Handle array element at [1][2][2][1]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多