【问题标题】:Russian Peasant Multiplication俄罗斯农民乘法
【发布时间】:2026-02-11 19:20:03
【问题描述】:

这是我对Russian Peasant Multiplication 的简短实现。如何改进?

限制:仅在 a>0,b>0

时有效
for(p=0;p+=(a&1)*b,a!=1;a>>=1,b<<=1);

【问题讨论】:

  • 我喜欢最佳代码,所以我会给你一个赞成票,但你应该在上面的 cmets 中承认你的预编辑帖子没有初始化。
  • @Lance 是的,你是对的,我会修改这个
  • 我赞成,因为短的在线缩进可能很差。不过,阅读漂亮的缩进代码会非常愉快。
  • spx 看起来人们讨厌你。我不知道为什么
  • 是的,人们讨厌我,只是讨厌周围的人。我不知道为什么,也许你有答案?紧凑的代码会产生仇恨,我不能说它以任何可以想象的方式具有教学/指导性。意图明显的意图是虚荣(我会在地狱中燃烧)。这可能是您提到的仇恨的可能解释。你怎么看?

标签: c algorithm optimization multiplication


【解决方案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(a b &optional (sum 0)) "返回 a 和 b 的乘积, 通过农民的繁殖来实现。” (如果(= 1) (+ b 总和) (农民-mult(地板(/ a 2)) (* b 2) (+ sum (* b (logand a 1))))))

【讨论】:

    【解决方案2】:

    我觉得这很可怕 从编译器的角度来看,这是完全相同的代码,并且(希望)更清晰

    int sum = 0;
    while(1)
    {
        sum += (a & 1) * b;
        if(a == 1)
           break;
    
        a = a / 2;
        b = b * 2;
    }
    

    现在我已经写出来了,我明白了。

    【讨论】:

    • 是的,那是我的第一个实现 :) 然后我想起了一些技巧 :)
    • 我希望我永远不必和你一起写代码,永远。我不明白为什么有人会采用上述类似的东西并生产出你所拥有的东西,除非他们在混淆 C 竞赛条目中做出半开玩笑的尝试。 :|
    • 我认为位移会比除法或乘法更快,我不确定是否所有编译器都会这样做。 (虽然他们可能,但这里不确定)。
    • 位移比乘法或除法更快,但任何体面的编译器都会尽可能将乘法乘以常数优化为一组位移。我遇到的唯一没有的编译器是 IAR H8 编译器。我怀疑这不是这里的目标平台。
    • 弗拉德 - 我也能读英文,但这并不意味着我喜欢这样。
    【解决方案3】:

    有一个非常简单的方法可以改善这一点:

    p = a * b;
    

    它甚至还有一个优势,a 或 b 可以小于 0。

    如果你看看它是如何工作的,你会发现它只是正常的手动乘法执行二进制。你的计算机内部是这样处理的 (1),所以使用俄罗斯农民方法的最简单方法是使用内置乘法。

    (1) 也许它有一个更复杂的算法,但原则上你可以说,它适用于这个算法

    【讨论】:

      【解决方案4】:

      循环中还有一个乘法。如果你想降低乘法的成本,你可以改用这个:

      for(p=0;p+=(-(a&1))&b,a!=1;a>>=1,b<<=1);
      

      【讨论】:

      • 是的,这是真的,我的朋友,太棒了!谢谢 :) 但是限制 b>0 把你救到了这里,如果不是这样你就错了。
      【解决方案5】:

      正如其他人所说,我并不觉得它特别糟糕、模糊或不可读,而且我不理解所有这些反对意见。这就是说,这就是我将如何“改进”它:

      // 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 );
      

      【讨论】:

        【解决方案6】:

        这是一场代码混淆比赛?我认为你可以做得更好。首先,使用误导性的变量名而不是无意义的变量名。

        【讨论】:

          【解决方案7】:

          p 未初始化。

          如果a 为零会怎样?

          如果a 为负数会怎样?

          更新:我看到您已更新问题以解决上述问题。虽然您的代码现在似乎可以正常工作(溢出问题除外),但它的可读性仍然低于应有的水平。

          【讨论】:

          • p 将被初始化为 0 乘法,这里仅适用于 a>0,b>0 :) 感谢询问
          【解决方案8】:

          我认为它不完整,而且很难阅读。您正在寻找什么样的具体反馈?

          【讨论】:

          • a,b 是数字,在 for 循环之后 p 将是他们的产品。在那里,不难阅读。
          • 它比它需要的更难阅读,并且写它的人不是判断它是否难以阅读的人。添加几个换行符有什么问题?
          • 添加换行符会破坏紧凑性:)
          • 您的意思是“添加换行符会破坏不可读性”。不会改变编译后的大小。
          • 您为什么不直接用汇编编写代码,然后停止使用 C 之类的游戏语言。您显然是一位出色的程序员,您可能应该从事教学或咨询工作。
          【解决方案9】:
          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;
          }
          

          【讨论】:

            【解决方案10】:

            不加乘除:

            function RPM(int a, int b){
                int rtn;
                for(rtn=0;rtn+=(a&1)*b,a!=1;a>>=1,b<<=1);
                return rtn;
            }
            

            【讨论】:

            • err... (a&1)*b IS 是一个乘法。 :)