俄罗斯农夫算法
2015-08-20 14:54
441 查看
引入问题
众所周知,位运算比加减乘除法省时间。那么问题来了,给你一个非高精度数a和b,要求你不用任何乘除号完成a*b的运算,如何实现。
写在第二
当当当当,俄罗斯农夫算法闪亮出场。当我真的开始着手研究这个算法时,惊讶于这方面的资料之少。想来如果可以重载一下运算符的话,如果能把每一边乘法的时间都进行优化的话,说不定能使整个算法的效率大大提高。然而当我花了半个小时才写出一个正确代码后,不仅感慨用这么多代码去换一丝丝丝的时间是否真的值得。虽然如此,即以决定,就把这个详细介绍俄罗斯农夫算法的博客写完吧。
理解算法
规则:什么是俄罗斯农民乘法?我要怎么使用它?原理:俄罗斯农民乘法的工作原理是什么?
联系:俄罗斯农民乘法是如何与二进制相关联的呢?
什么是俄罗斯农民乘法?我要怎么使用它?
资料来源:http://article.yeeyan.org/view/66573/28201
我们绝大多数人学的都是这样做大数字乘法的:
86
x 57
------
602
+ 4300
------
4902
如果你懂得乘法算式,那么这种“长式相乘”的方法是快速和相对简单的。不过,还有许多其它的计算方法。其中之一通常被称之为俄罗斯农民算法。使用它时不需要你懂得乘法算式,你只需要将数字加倍,减半再进行合计。具体规则如下:
* 把每一个数字分别写在列头。
* 将头一列的数字加倍,将第二列的数字减半。
如果在第二列的数字是奇数,将它除以二并把余数去掉。
* 如果第二列的数字是偶数,将其所在行删除。
* 继续加倍、减半和删除直到第二列的数字为1。
* 将第一列中剩余的数字相加。于是就得出了根据原始数字计算出的结果。
让我们以计算57乘以86为例。
把每一个数字分别写在列头。
57 86
将头一列的数字加倍,将第二列的数字减半。
57 86
114 43
如果第二列的数字是偶数,将其所在行删除。
57 86
114 43
继续加倍、减半和删除直到第二列的数字为1。
57 86
114 43
228 21
456 10
912 5
1824 2
3648 1
将第一列中剩余的数字相加。于是就得出了根据原始数字计算出的结果。
57 86
114 43
228 21
456 10
912 5
1824 2
+ 3648 1
4902
真实的俄罗斯农民们可能会用好几碗的鹅卵石来记录他们加倍的数字,用来代替写在列里面的数字。(当然,他们或许不会对我们的例子里那么大的数字感兴趣,要知道四千多个鹅卵石可是很难操作的哟!)俄罗斯的农民们并不是唯一使用这种算法的人,在数千年之前古埃及人就已经发明了类似的方法,而同时在今天的计算机中仍然在使用与之相关的程序。
俄罗斯农民乘法的工作原理是什么?
让我们以计算9×8为例:
9 8
18 4
36 2
72 1
72是唯一一个留在左列里的数字,所以我们的答案就是72。请注意我们在其中一边乘以2,在另一边除以2,2 × 1/2 = 1,所以对最终结果并没有影响:
9 * 8
#include<stdio.h> void main() { int m,n,s,flag; while(scanf("%d%d",&m,&n)==2) { flag=0; if(m<0) { flag=1-flag; m=0-m; } if(n<0) { flag=1-flag; n=0-n; } s=0; while(m>=1) { if(m&1==1) { s+=n; m=(m-1)>>1; n=n<<1; } else { m=m>>1; n=n<<1; } } if(flag==0) printf("%d\n",s); else printf("-%d\n",s); } }
View Code
相关文章推荐
- 一个Myeclipse同时配置多个Tomcat
- 迅为4412开发板Linux驱动教程/硬件知识及原理图的使用
- Python中列表和元组的相关语句和方法讲解
- 文章标题
- SQLite学习笔记(4)-数据库基本操作
- PN学习
- 折半查找
- 一段小插曲----银江股份
- js关闭窗口不提示
- 分类算法之朴素贝叶斯分类(Naive Bayesian classification)
- SVN文件库移植(转)
- iOS开发:代码通用性以及其规范 第一篇(附带,自定义UITextView\进度条\双表显示\瀑布流 代码设计思路)
- jvm基础知识六---分代垃圾回收
- ecshop增加一个后台菜单
- "活"的模拟退火算法
- leetcode刷题一
- java 字符串替换中文逗号
- Nginx网站自定义404错误页面
- HackerRank Extra long factorials
- java 版本 HightCharts demo