- 注册时间
- 2010-2-12
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 1214
- 在线时间
- 小时
|
发表于 2018-1-13 00:56:52
|
显示全部楼层
本帖最后由 只是呼吸 于 2018-1-13 01:38 编辑
以下是我自己写的牛顿迭代除法函数。
除法函数的入口条件:
要添加<math.h> 头文件。
qut[]-------存储商。商为\(10^8\)进制。
temp[]-----临时变量(存储中间结果)
Work[]-----临时变量(存储倒数)
Cdiv[]------规约化了的被除数。采用\(10^8\)进制。LENdividend 是 Cdiv[]的长度减1.
divR[]------规约化了的除数。采用\(10^8\)进制。LENdivR 是 divR[]的长度减1.其中divR[]的最高项一定要有9位十进制数
当除数是一个单精度的 unsigned long 时,调用其它函数处理,不进入 Newton_div()。
- void Newton_div(UINT32 * const qut,UINT32 * const temp,UINT32 * const Work,UINT32 * const Cdiv,int LENdividend, UINT32 * const divR,int LENdivR)
- {
- UINT64 h64=100000000000000000;//17个 0
- int len,i,s,N,LEN2,LenWork;
- len=LENdividend-LENdivR+1;//计算商的有效位数len=LL-LR
- N=(int)(floor(log(len)/log(2))); //计算迭代的次数 N=floor(LOG(Len)/LOG(2)); ;
- Work[0]=(UINT32)(h64/divR[LENdivR]); //求初商,估商s0=100000000 00000000/divR[LR];
- Work[0]/=10;
- Work[0]--;
-
- LenWork=0;
- len=1;
-
- for(i=0;i<=N;i++)
- {
- ALU_mul(qut,divR,Work,LENdivR+1,LenWork+1);// 1 乘法函数:求a*s0
-
- s=LENdivR+LenWork+1;
- s=Newton_LeftZero(qut,s);// 寻找 qut[] 的非零最高位的下标 函数
-
- Newton_sub(qut,s); // 2 减法函数, 2-a*s0
- ALU_mul(temp,qut,Work,s+2,LenWork+1); /// 乘法(2-a*s0)*s0
-
- LEN2=s+LenWork+2;
- LEN2=Newton_LeftZero(temp,LEN2);// 寻找 temp[] 的非零最高位的下标 函数
- Newton_clear(Work,LenWork+2); //清零函数 把 Work[] 清零
- len<<=1; // 精度加倍
- LenWork=len;// 计算迭代后的精度,也正好是Work 的长度
-
- Newton_set(Work,temp,LEN2,LenWork);///赋值,运算关系Work<--temp, 赋的长度是LenWork, 裁剪掉temp 中的多余的右边的数(低位)。
-
- Newton_Zero(qut,s+4); // 清零函数 把 qut[] 清零
- Newton_Zero(temp,LEN2+4); //清零函数 把 temp[] 清零
- }///迭代的边界
-
- len=LENdividend-LENdivR+1;
- for(i=0;i<=len-1;i++)
- {
- Work[i]=Work[LenWork+1+i-len];//取Work左面的len位,赋给Work.
- }
- for(i=len;i<=LenWork;i++) ///将多余的数清零
- Work[i]=0;
-
- ALU_mul(qut,Cdiv,Work,LENdividend+1,len); /// 乘法,用倒数乘 被除数得到商。qut[] 存储商
- s=Newton_LeftZero(qut,LENdividend+len+1);// 寻找 qut[] 的非零最高位的下标 函数
- len=quotient_Num(Cdiv,divR,LENdividend,LENdivR,qut[s]);/// 求商的精确长度的函数,(不是把商求出来,只是求出商的精确长度)
- for(i=0;i<=len-1;i++)
- {
- qut[i]=qut[s+i-len+1];//取Work左面的s位,赋给Work.
- }
-
- for(i=len;i<=s;i++) ///将多余的数清零
- qut[i]=0;
-
- // return 0;
- }//*///
复制代码
乘法函数就是我写的那个“大整数乘法代码”,把它做了优化后暂时用着。
减法函数是专门针对牛顿除法的.代码如下:
- static int Newton_sub(UINT32 *dst,int size2)///
- {
- int i,s=0;
-
- while(dst[s]==0)
- {
- s++;
- }
- dst[s]=100000000-dst[s];
-
- for(i=s+1;i<=size2;i++)
- {
- dst[i]=99999999-dst[i];
- }
-
- dst[size2+1]=1;//(///
- return 0;
- }////////
复制代码
其余的函数都没有什么特殊的,就不写出来了。
这个牛顿除法终于完工,花了很多时间,一开始的时候,一个数字都不对。后来才慢慢正确。
实际运算:35800位十进制数 除以 11000位十进制数,我写的牛顿除法用时 35毫秒。我写的试商除法用时 110毫秒。
可能是乘法不好,这么大的数字用硬乘法也许勉强了。等下一步写一个karatsuba乘法试试。
|
|