这是我对俄罗斯农民乘法的简短实现。如何改进?
限制:仅在 a>0,b>0 时有效
for(p=0;p+=(a&1)*b,a!=1;a>>=1,b<<=1);
可以通过添加空格、适当的缩进和适当的函数体来改进它:
int peasant_mult (int a, int b) {
for (p = 0;
p += (a & 1) * b, a != 1;
a /= 2, b *= 2);
return p;}
看?现在很清楚for
声明的三个部分是如何使用的。请记住,程序主要是为人眼编写的。不可读的代码总是坏代码。
现在,为了我个人的乐趣,一个尾递归版本:
(defun 农民-mult (ab &optional (sum 0)) "返回 a 和 b 的乘积, 通过农民的繁殖来实现。” (如果(= 1) (+ b 总和) (农民-mult(地板(/ a 2)) (* b 2) (+ sum (* b (logand a 1))))))
我认为这很糟糕从编译器的角度来看,这是完全相同的代码,并且(希望)更清晰
int sum = 0;
while(1)
{
sum += (a & 1) * b;
if(a == 1)
break;
a = a / 2;
b = b * 2;
}
现在我已经写出来了,我明白了。
有一个非常简单的方法可以改善这一点:
p = a * b;
它甚至具有 a 或 b 可以小于 0 的优点。
如果你看看它是如何工作的,你会发现它只是正常的手动乘法执行二进制。您的计算机以这种方式(1)在内部进行操作,因此使用俄罗斯农民方法的最简单方法是使用内置乘法。
(1) 也许它有一个更复杂的算法,但原则上你可以说,它适用于这个算法
循环中仍然存在乘法。如果你想降低乘法的成本,你可以使用它来代替:
for(p=0;p+=(-(a&1))&b,a!=1;a>>=1,b<<=1);
正如其他人所说,我并不觉得它特别糟糕、模糊或不可读,而且我不理解所有这些反对意见。这就是说,这就是我将如何“改进”它:
// Russian Peasant Multiplication ( p <- a*b, only works when a>0, b>0 )
// See http://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication
for( p=0; p+=(a&1)*b, a!=1; a>>=1,b<<=1 );
p
未初始化。
如果a
为零会怎样?
如果a
是负数会怎样?
更新:我看到您已更新问题以解决上述问题。虽然您的代码现在似乎可以正常工作(溢出问题除外),但它的可读性仍然低于应有的水平。
这是为了代码混淆比赛?我认为你可以做得更好。首先,使用误导性的变量名而不是无意义的变量名。
我认为它不完整,而且很难阅读。你在寻找什么样的具体反馈?
int RussianPeasant(int a, int b)
{
// sum = a * b
int sum = 0;
while (a != 0)
{
if ((a & 1) != 0)
sum += b;
b <<= 1;
a >>= 1;
}
return sum;
}
没有乘法或除法的答案:
function RPM(int a, int b){
int rtn;
for(rtn=0;rtn+=(a&1)*b,a!=1;a>>=1,b<<=1);
return rtn;
}