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

首先,标准乘法:

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

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

 int plusMultiplication(int a, int b) {
var t = a > b ? b : a, r = 0;
if (t == a) {
a = b;
b = t;
} while (b-- > 0) r += a;
return r;
}

最后,位移乘法。计算机进行位移操作的速度是非常快的,因此,如果能把乘法换算成位移操作的话,速度会不会更快?但是根据计算机二进制的特点,每次向左位移,相当于是乘了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的幂的代码如下:

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

位移乘法实现的代码

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函数即可得出结果,但这样就起不到自己练习位运算和递归的目的了。

递归算法之不用乘号的乘法——用位移实现乘法(dart语言实现)的更多相关文章

  1. 矩阵乘法 codevs 1287 矩阵乘法

    1287 矩阵乘法  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold       题目描述 Description 小明最近在为线性代数而头疼,线性代数确实很抽象 ...

  2. 补码一位乘法(Booth算法,C语言实现)

    补码一位乘法 首先了解下什么是补码? 补码概念的理解,需要先从“模”的概念开始. 我们可以把模理解为一个容器的容量.当超出这个 容量时,会自动溢出.如:我们最常见到的时钟,其容量 是 12,过了 12 ...

  3. 大整数算法[11] Karatsuba乘法

    ★ 引子         前面两篇介绍了 Comba 乘法,最后提到当输入的规模很大时,所需的计算时间会急剧增长,因为 Comba 乘法的时间复杂度仍然是 O(n^2).想要打破乘法中 O(n^2) ...

  4. 大整数算法[09] Comba乘法(原理)

    ★ 引子          原本打算一篇文章讲完,后来发现篇幅会很大,所以拆成两部分,先讲原理,再讲实现.实现的话相对复杂,要用到内联汇编,要考虑不同平台等等. 在大整数计算中,乘法是非常重要的,因为 ...

  5. 【老鸟学算法】大整数乘法——算法思想及java实现

    算法课有这么一节,专门介绍分治法的,上机实验课就是要代码实现大整数乘法.想当年比较混,没做出来,颇感遗憾,今天就把这债还了吧! 大整数乘法,就是乘法的两个乘数比较大,最后结果超过了整型甚至长整型的最大 ...

  6. Algorithm --> 矩阵链乘法

    动态规划--矩阵链乘法 1.矩阵乘法       Note:只有当矩阵A的列数与矩阵B的行数相等时A×B才有意义.一个m×r的矩阵A左乘一个r×n的矩阵B,会得到一个m×n的矩阵C. #include ...

  7. [转]大整数算法[11] Karatsuba乘法

    ★ 引子         前面两篇介绍了 Comba 乘法,最后提到当输入的规模很大时,所需的计算时间会急剧增长,因为 Comba 乘法的时间复杂度仍然是 O(n^2).想要打破乘法中 O(n^2) ...

  8. python_九九乘法表

    # 九九乘法表 print(" 九九乘法表") for table_x in range(1,10): for table_y in range(1,table_x +1): pr ...

  9. For循环练习之99乘法表和转义字符

    之前说了for循环的概念以及常用到的操作,那么我们接下来做几个巩固练习: 1.打印99乘法表: 99乘法表的形式: 1*1 = 1 1*2 = 2 2*2 = 4 1*3 = 3 2*3 = 6 3* ...

随机推荐

  1. [易学易懂系列|rustlang语言|零基础|快速入门|(9)|Control Flows流程控制]

    [易学易懂系列|rustlang语言|零基础|快速入门|(9)] 有意思的基础知识 Control Flows 我们今天再来看看流程控制. 条件控制 if-else if -else: / Simpl ...

  2. Linux(Centos7)下redis5缓存服务集群分布式搭建

    注意:可以查看Redis官网查看集群搭建方式,连接如下 https://redis.io/topics/cluster-tutorial 集群中应该至少有三个节点,每个节点有一备份节点.需要6台服务器 ...

  3. 【NOIP2016提高A组模拟8.17】(雅礼联考day1)Matrix

    题目 分析 假设,我们从\(F_{i,2}\)出发,那么对\(F_{n,n}\)的贡献就是\(某个系数乘以a^{n-i}b^{n-1}r_i\): 同理,如果从\(F_{2,i}\)出发,那么对\(F ...

  4. 如何使用dump文件进行调试

    转载[文尾出处链接] 1 简介第一次遇到程序崩溃的问题,之前为单位开发了一个插件程序,在本机运行没有出现问题,但把生成的可执行文件拷贝到服务器上一运行程序,刚进入插件代码,插件服务就崩溃了,当时被这个 ...

  5. 导出csv文件(使用a标签)

    https://blog.csdn.net/oscar999/article/details/16342699   productsCSV(e) { const { download } = this ...

  6. 这个 'ip' 竟然把我搞蒙圈了……

    1.查看redis连接配置(某项目) <bean id="redisCacheServer" class="com.spring.cache.RedisCacheS ...

  7. [CF118D]Caesar's Legions 题解

    题意简述 一个01序列由\(n_1\)个0和\(n_2\)个1组成,求最长连续0串长度不超过\(k_1\),最长连续1串长度不超过\(k_2\)的序列的方案总数 题解 状态 方案总数 变量 已经取了i ...

  8. arguments详解——函数内命名参数之映射

    首先,arguments对象是所有(非箭头)函数中都可用的局部变量.你可以使用arguments对象在函数中引用函数的参数.此对象包含传递给函数的每个参数,第一个参数在索引0处. arguments对 ...

  9. oracle 数据库优化【转载】

    版权声明:本文为CSDN博主「咫尺的梦想ing」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/u01305 ...

  10. 数据库MySQL(课下作业,必做) 20175225

    作业要求: 1.下载附件中的world.sql.zip, 参考http://www.cnblogs.com/rocedu/p/6371315.html#SECDB,导入world.sql,提交导入成功 ...