你能用C语言的宏实现阶乘吗?

qmelpv7a  于 2023-02-15  发布在  其他
关注(0)|答案(1)|浏览(81)

我正在寻找一个使用宏计算阶乘的例子。我没有找到任何有效的东西。有什么具体的原因吗?是因为C的实现吗?
我知道你不能在宏中使用递归,但是有一种方法可以使用迭代阶乘函数,为什么在C中不能使用阶乘宏呢?
下面是我找到的阶乘函数迭代实现的一个例子,以供参考:

int factorial(int N) {
    int product = 1;
    for (int j = 1; j <= N; j++)
        product *= j;
    return product;
}
ijxebb2r

ijxebb2r1#

我想不出在一般情况下将其作为宏的方法,但只有很少的int值可以定义阶乘函数:如果int具有32位,则其调用N > 12的未定义行为。
下面是利用这一点的许多方法:

static int const factorials[13] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 
                                    362880, 3628800, 39916800, 479001600 };
#define FACT(n)  ((n) < 0 ? 1 : (n) > 12 ? INT_MAX : factorials[n])

或者:

#define FACT(n) ((n) <= 1 ? 1 : \
                 (n) == 2 ? 2 : \
                 (n) == 3 ? 6 : \
                 (n) == 4 ? 24 : \
                 (n) == 5 ? 120 : \
                 (n) == 6 ? 720 : \
                 (n) == 7 ? 5040 : \
                 (n) == 8 ? 40320 : \
                 (n) == 9 ? 362880 : \
                 (n) == 10 ? 3628800 : \
                 (n) == 11 ? 39916800 : \
                 (n) == 12 ? 479001600 : INT_MAX)

请注意,这两个函数都会多次计算n
内联函数是一种更好的方法。在现代优化编译器上,您的factorial()可以编译为常量参数的常量:
一个使用Matt Godbolt's online compiler和clang 3.9 -O2的简短示例非常有启发性:
factorial函数可编译成235行英特尔SIMD代码,而int test(void) { return factorial(12); }仅生成2条指令:

test():                               # @test()
        mov     eax, 479001600
        ret

即使使用-Os优化大小,也会产生49行汇编代码,这太大了,因为-O1只有10行。

相关问题