让我们看看我们是否可以在不依赖 1 的情况下做一些半优雅的事情。
- 我们当然会使用递归来代替循环。
- 我们将使用 函数指针数组,而不是 if 来终止递归!
(我们仍然需要比较运算符,例如< 和==。)
编辑: damaru 首先使用了函数指针技巧。
这给出:[所有代码都未经测试,手头没有 C 编译器!]
typedef int (*unary_fptr)(int);
int ret_1(int n) {
return 1;
}
int fact(int n) {
unary_fptr ret_1_or_fact[] = {ret_1, fact};
return multiply(ret_1_or_fact[n > 1](sub_1(n)), n);
}
我们仍然需要实现sub_1 和multiply。让我们从sub_1开始,这是对位的简单递归,直到进位停止(如果你不明白这一点,最后类似的add_1更容易思考):
int identity(int n) {
return n;
}
int sub_1(int n) {
unary_fptr sub_1_or_identity[] = {sub_1, identity};
int lsb = n & 1;
int rest = sub_1_or_identity[lsb](n >> 1);
return (rest << 1) | (lsb ^ 1);
}
multiply:我能想到的最简单的是Russian Peasant multiplication,将其简化为二进制移位和加法。使用条件,递归公式如下所示:
/* If we could use conditionals */
int multiply(int a, int b) {
int subproduct;
if(a <= 1) {
subproduct = 0;
} else {
subproduct = multiply(a >> 1, b << 1);
}
if(a & 1) {
return add(b, subproduct);
} else {
return subproduct;
}
}
没有条件,我们必须使用两次调度数组技巧:
typedef int (*binary_fptr)(int, int);
int ret_0(int a, int b) {
return 0;
}
int multiply(int a, int b) {
binary_fptr ret_0_or_multiply = {ret_0, multiply};
int subproduct = ret_0_or_multiply[a >= 2](a >> 1, b << 1);
binary_fptr ret_0_or_add = {ret_0, add};
return ret_0_or_add[a & 1](subproduct, b);
}
现在我们想念的是add。您现在应该猜到它会如何进行 - 同时递归两个数字的位,这将问题减少到移位和add_1:
int add(int a, int b) {
int lsb = (a & 1) ^ (b & 1);
int carry = (a & 1) & (b & 1);
binary_fptr ret_0_or_add = {ret_0, add};
int subsum = ret_0_or_add[(a >= 2) & (b >= 2)](a >> 1, b>> 1);
unary_fptr identity_or_add_1 = {identity, add_1};
return identity_or_add_1[carry](subsum << 1);
}
而add_1 是对位的简单递归,直到进位停止:
int add_1(int n) {
unary_fptr identity_or_add_1[] = {identity, add_1};
int lsb = n & 1;
int rest = identity_or_add_1[lsb](n >> 1);
return (rest << 1) | (lsb ^ 1);
}
我想就是这样! [如上所述,所有代码都未经测试!]