如何将递归函数转换为mex代码?

时间:2016-08-24 11:25:12

标签: matlab mex

我有一个递归函数在MATLAB代码中选择如下:

   function nk=choose(n, k)
        if (k == 0)
            nk=1;
        else
            nk=(n * choose(n - 1, k - 1)) / k;
        end
    end

该代码用于计算n和k之间的组合。我想通过使用mex代码来加速它。我试着写一个mex代码

double choose(double* n, double* k)
{
   if (k==0) 
        return 1;
   else
        return (n * choose(n - 1, k - 1)) / k;
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    double *n, *k, *nk;
    int mrows, ncols;
    plhs[0] = mxCreateDoubleMatrix(1,1, mxREAL);
    /* Assign pointers to each input and output. */
    n = mxGetPr(prhs[0]);    
    k = mxGetPr(prhs[1]);
    nk = mxGetPr(plhs[0]);
    /* Call the recursive function. */
    nk=choose(n,k);
}

然而,它不起作用。你能帮我修改一下可以实现上述MATLAB代码的mex代码吗?感谢

2 个答案:

答案 0 :(得分:1)

不需要mex二项式系数可以在Matlab中实现:

function nk=nchoosek2(n, k)
    if n-k > k
        nk = prod((k+1:n) .* prod((1:n-k).^ (-1/(n-k))));
    else
        nk = prod((n-k+1:n) .* prod((1:k).^ (-1/k)) ) ;
    end
end

答案 1 :(得分:1)

以下代码修复了您的C mex实现 问题不在于递归当然...... 您的代码使用指针而不是值(在C中,仅在正确的位置使用指针很重要)。

您可以使用Matlab内置功能:nchoosek
请参阅:http://www.mathworks.com/help/matlab/ref/nchoosek.html

以下代码有效:

//choose.c

#include "mex.h"

double choose(double n, double k)
{
    if (k==0) 
    {
        return 1;
    }
    else
    {
        return (n * choose(n - 1, k - 1)) / k;
    }
}


void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    double *n, *k, *nk;
    int mrows, ncols;
    plhs[0] = mxCreateDoubleMatrix(1,1, mxREAL);
    /* Assign pointers to each input and output. */
    n = mxGetPr(prhs[0]);    
    k = mxGetPr(prhs[1]);
    nk = mxGetPr(plhs[0]);

    /* Call the recursive function. */
    //nk=choose(n,k);
    *nk = choose(*n, *k);
}

在Matlab中编译: mex choose.c

执行:
choose(10,5)
ans =

252

这不是低效的实施......
我正在帮助修复你的实现,被用作“低效的例子”。

衡量rahnema1执行的执行情况:
tic; n = 1000000; k = 500000; nk = prod((k + 1:n)。* prod((1:n-k)。^( - 1 /(n-k)))); toc
经过的时间是0.022855秒。

衡量choose.mexw64实施的执行情况:
tic; n = 1000000; k = 500000; nk =选择(1000000,500000); toc
经过时间为0.007952秒 (花费的时间少于prod((k + 1:n)。* prod((1:n-k)。^( - 1 /(n-k)))))。

测量Matlab递归,得到误差(即使对于n = 700和k = 500):
ic; n = 700; k = 500; nk = RecursiveFunctionTest(n,k); toc
达到最大递归限制500。使用set(0,'RecursionLimit',N)更改限制。请注意,超出可用堆栈空间可以 崩溃MATLAB和/或您的计算机。

tic; n = 700; k = 400; nk = RecursiveFunctionTest(n,k); toc
经过的时间是0.005635秒。 非常低效......

测量Matlab内置函数nchoosek:
tic; nchoosek(1000000,500000); toc
警告:结果可能不准确。系数大于9.007199e + 15,仅精确到15位  在92岁的nchoosek 经过的时间是0.005081秒。

结论:
您需要在不使用递归的情况下实现C mex文件,并采取措施。

没有递归的测量:

static double factorial(double number) 
{
    int x;
    double fac = 1;

    if (number == 0)
    {
        return 1.0;
    }    

    for (x = 2; x <= (int)number; x++)
    {
        fac = fac * x;
    }

    return fac;
}



double choose(double n, double k)
{
    if (k == 0) 
    {
        return 1.0;
    }
    else
    {
        //n!/((n–k)! k!) 
        return factorial(n)/(factorial(n-k)*factorial(k));
    }
}

tic;choose(1000000, 500000);toc

  

经过的时间是0.003079秒。

更快...