C中的复合函数

时间:2014-06-05 09:29:20

标签: c recursion function-composition

如果我有一个函数组合f(f(f(f(x))))我怎么能把它写成C中的函数?是否可以用递归算法编写它?

例如,如果我们有以下功能会发生什么:

f(x)=cosa*X1+cosb*X2 where x=(X1,X2)

3 个答案:

答案 0 :(得分:1)

这是我的一个示例玩具程序,一个将迭代与头部和头部进行比较的练习。尾递归。

对这个问题进行一点点破解,它重新应用了一个“wibble”函数N次,并通过struct array聚合X0,X1,通过reapply_f迭代和递归函数构建系列。重构尾调用优化版本,将代码变回看起来像迭代。 (只是使用typedef'd数组,有问题你无法从函数返回它,并且在传递给函数调用时没有按值语义调用。)

输出:

Iterative Series Technique
    f0 = f(0.100000,0.900000)
    f1 = f(1.000000,-0.800000)
    f2 = f(0.200000,1.800000)
    f3 = f(2.000000,-1.600000)

Head Recursive Series Technique
    f0 = f(0.100000,0.900000)
    f1 = f(1.000000,-0.800000)
    f2 = f(0.200000,1.800000)
    f3 = f(2.000000,-1.600000)

Tail Recursive Series Technique
    f0 = f(0.100000,0.900000)
    f1 = f(1.000000,-0.800000)
    f2 = f(0.200000,1.800000)
    f3 = f(2.000000,-1.600000)

Optimised Tail Recursive Series Technique
    f0 = f(0.100000,0.900000)
    f1 = f(1.000000,-0.800000)
    f2 = f(0.200000,1.800000)
    f3 = f(2.000000,-1.600000)

Tidied Optimised Tail Recursive Series Technique
    f0 = f(0.100000,0.900000)
    f1 = f(1.000000,-0.800000)
    f2 = f(0.200000,1.800000)
    f3 = f(2.000000,-1.600000)

和C,显示迭代和递归代码的相似性:

#include <stdio.h>
#include <stdlib.h>

typedef struct aggregate {
    double X[2];
} aggregate;

void display_series(int n, aggregate series[]) {
    for (int i=0; i<=n; i++) {
        printf( "    f%d = f(%f,%f)\n", i, series[i].X[0], series[i].X[1]);
    }
    putchar( '\n');
}

void init_series(int n, aggregate series[]) {
    series[0].X[0] = 0.1; series[0].X[1] = 0.9;
    for (int i=1; i <= n; i++) {
        series[ i].X[0] = 0.0; series[ i].X[1] = 0.0;
    }
}

aggregate wibble( const aggregate in) {
    aggregate out;
    out.X[0] = in.X[0] + in.X[1];
    out.X[1] = in.X[0] - in.X[1];
    return out;
}

aggregate reapply_f_iterative(int n, aggregate (*f)(), aggregate series[]) {
    for (int i=1; i <= n; i++) {
        series[ i] = (*f)( series[ i-1]);
    }
    return series[n];
}

aggregate reapply_f_head_recursive(int n, aggregate (*f)(), aggregate series[]) {
    if (n>0) {
        reapply_f_head_recursive( n-1, f, series);
    series[n] = (*f)( series[n-1]);
    }
    return series[n];
}

aggregate reapply_f_tail_recursive( int applied, int limit, aggregate (*f)(), aggregate series[]) {
    if (applied >= limit) {
        return series[ applied];
    }
    series[applied+1] = (*f)( series[ applied]);
    return reapply_f_tail_recursive( ++applied, limit, f, series);
}

aggregate reapply_f_optimised_tail_recursive( int applied, int limit, aggregate (*f)(), aggregate series[]) {
RESTART:
    if (applied >= limit) {
        return series[ applied];
    }
    series[applied+1] = (*f)( series[ applied]);
    ++applied;
    goto RESTART;
}

aggregate reapply_f_tidied_optimised_tail_recursive( int applied, int limit, aggregate (*f)(), aggregate series[]) {
    for( ; applied < limit; ++applied) {
        series[ applied+1] = (*f)( series[ applied]);
    };
    return series[ applied];
}



int main (int argc, char **argv) {

    /* series 0..N */
    size_t N = 3;
    if (argc == 2) {
        N = strtol( argv[ 1], NULL, 0);
    }
    aggregate *series = calloc( N+1, sizeof( aggregate));

    printf( "Iterative Series Technique\n");
    init_series( N, series);
    (void) reapply_f_iterative( N, &wibble, series);
    display_series( N, series);

    printf( "Head Recursive Series Technique\n");
    init_series( N, series);
    (void) reapply_f_head_recursive( N, &wibble, series);
    display_series( N, series);

    printf( "Tail Recursive Series Technique\n");
    init_series( N, series);
    (void) reapply_f_tail_recursive( 0, N, &wibble, series);
    display_series( N, series);

    printf( "Optimised Tail Recursive Series Technique\n");
    init_series( N, series);
    (void) reapply_f_optimised_tail_recursive( 0, N, &wibble, series);
    display_series( N, series);

    printf( "Tidied Optimised Tail Recursive Series Technique\n");
    init_series( N, series);
    (void) reapply_f_tidied_optimised_tail_recursive( 0, N, &wibble, series);
    display_series( N, series);
}

答案 1 :(得分:0)

如果我正确理解了你的意思,你总是可以将计数器设置为你希望调用该函数的次数,并将其作为该函数的一个附加参数传递。然后每次调用函数一次将计数器减1,并在计数器为零时停止迭代。

答案 2 :(得分:0)

typedef struct composite {
    float X1,
    float X2
} composite;

composite f(composite x) {
    composite result;
    result.X1 = cosa*x.X1 + xosa*x.X2;
    result.X2 = sina*x.X0 - cosa*x.X2;
    return result;
}