zoukankan      html  css  js  c++  java
  • 递归算法之不用乘号的乘法——用位移实现乘法(dart语言实现)

      前两天突发奇想,写一个乘法的实现,但不用乘号*。并测试一下性能如何。因此就有了下面的代码:(本文主要目的是为了玩递归和位移,因此仅限自然数)

    首先,标准乘法:

    1 int commonMultiplication(int a, int b) => a * b;

    第二,从数学的角度,乘法其实就是加法,只是加法的简写而已,因此 a * b 可以理解为 b 个 a 相加;故得出用加法代替的乘法。为了减少加法的次数,取 a, b 两数的最小值进行循环:

     1 int plusMultiplication(int a, int b) {
     2   var t = a > b ? b : a, r = 0;
     3   if (t == a) {
     4     a = b;
     5     b = t;
     6   }
     7 
     8   while (b-- > 0) r += a;
     9   return r;
    10 }

    最后,位移乘法。计算机进行位移操作的速度是非常快的,因此,如果能把乘法换算成位移操作的话,速度会不会更快?但是根据计算机二进制的特点,每次向左位移,相当于是乘了2的n次方,怎么办?我们看看例子:

      31 * 18

    怎么用位移来实现呢?首先我们取小的数:18,进行拆解。拆解的算法是,任何一个自然数,在计算机中都可以用二进制表示,那么,任何一个自然数,也可以拆解为2的幂的和。比如 18 的二进制表示 为  10010,拆解成十进制,即为 18 = 16 + 2;那么上面可以拆解为:

      31 * 18 = 31 * (16 + 2) = 31 * 16 + 31 * 2

    此时即可换成位移的算法:

      31 * 18 = 31 * (16 + 2) = 31 * 16 + 31 * 2 = 31 * 2^4 + 31 * 2^1 = (31 << 4) + (31 << 1)

    是不是转成了位移?这里要注意对乘数 18 的处理,位移的关键是找到乘数 b 如何拆解为 2 的幂,这里要递归拆解,以18为例,第一次的关键是找到16这个2的幂,然后用18 - 16,结果等于 2,继续找2等于多少2的幂,直到差小于2为止。同时,考虑到a*b,在实际计算中即使小的乘数也很大的情况,采用类似二分搜索的方式,给定阶数,从大的阶数向小的阶数递归。阶数的设定可以参考计算机的位数,即32位还是64位。因此,计算一个数可以拆分出来的最大2的幂的代码如下:

    1 int _bitShift(int d, int order) {
    2   if (order == 0) return 0;
    3   var i = 0;
    4   for (var t = d; (t >>= order) > 0; d = t, t = d) i += order;
    5   return i + _bitShift(d, order >> 1);
    6 }

    位移乘法实现的代码

    int bitMultiplication(int a, int b, int order) {
      var t = a > b ? b : a, r = 0;
      if (t == a) {
        a = b;
        b = t;
      }
    
      for (var i = _bitShift(b, order); i > 0; i = _bitShift(b, order)) {
        r += a << i;
        b -= 1 << i;
      }
    
      return b == 1 ? r + a : r;
    }

    经过采用随机大数进行多次循环测试,结果显示,用加法实现的乘法速度最慢,最快的仍然是 普通乘法,即用乘号的乘法;位移乘法居中。看来底层的计算机指令还是对*乘法做了优化。

    最后说明一下,本文纯属原创,没有使用dart 自带math包,尤其是在求一个数可以拆出来的最大的2的幂的数字时。否则直接用math包中的log函数即可得出结果,但这样就起不到自己练习位运算和递归的目的了。

  • 相关阅读:
    MYSQL删除表的记录后如何使ID从1开始
    Python chardet 字符编码判断
    中文搜索引擎技术揭密
    python 处理中文网页时,忽略特殊字符,忽略异常
    cmd 之基础命令
    自己写的删除主键的存储过程
    朝花夕拾delphi的三层结构
    ERWIN中的一对多标识关系和一对多非标识关系
    翻页用的SQL
    关于 Ajax 的一篇通俗易懂的文章
  • 原文地址:https://www.cnblogs.com/outerspace/p/10846106.html
Copyright © 2011-2022 走看看