找回密码
 欢迎注册
查看: 7616|回复: 3

[原创] 大整数的平方代码

[复制链接]
发表于 2016-1-11 21:55:42 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?欢迎注册

×
gxqcn曾经说过,大整数的平方有快速算法。经本人实践后,果然如此。虽然我写的程序显得幼稚,但平方算法确实比调用乘法要快大约一倍的时间。
以下是本人的习作。

      编译环境:Windows xp ,vc++6.0,debug模式,32位环境。
      硬件设备:AMD Athlon(tm) II X2  250          3.0GHz     2.00G的内存
      运行时间:一个14700位(十进制)数的平方,用时<2.7毫秒。
      函数原形: void _axa_( UINT32 *result, UINT32 * left,int LL)
             其中:*result 平方后的结果。 * left 待平方的数字。LL, *left的长度。
             进制:采用10000 0000(10^8)进制。十进制数高位对应数组较大的下标,十进制数的低位对应数组较小的下标。
      特别声明:1)*result 要用到的存贮空间,是待平方数* left 的实际空间的4倍。
                        2)待平方数* left 的长度不能超过14700位十进制数。


  1.    //   特别声明:1)*result 要用到的存贮空间,是待平方数* left 的实际空间的4倍。
  2.    //          2)待平方数* left 的长度不能超过14700位十进制数。
  3.    //          3)  如果采用VC++6.0以外的编译器,请确保每个存贮单元为32位。
  4.    //          4)  *result的空间在使用之前要进行清零

  5. _declspec(naked)
  6. void _axa_( unsigned int *result, unsigned int *left,int LL)
  7. {
  8. #undef LEFT_REG
  9. #undef RIGHT_REG
  10. #undef RESULT_REG
  11. #define LEFT_REG        esi
  12. #define RIGHT_REG        edi
  13. #define RESULT_REG        ebp
  14.        
  15.         __asm
  16.         {
  17.         push        esi
  18.         push        edi
  19.         push        ebx
  20.         push        ebp
  21. ///------------------------------------------------------------------------////               

  22.         mov        RIGHT_REG, dword ptr[esp +  08h+16]   ;  right
  23.         mov        ebx,dword ptr[esp+0Ch+16]     ; //LL
  24.         sub         ebx,1   ///控制外层循环。
  25.         je            kkkk            

  26. loop01:
  27.        mov        eax,dword ptr[esp+0Ch+16]  ////每次读取新的LL。eax用于控制
  28.        mov        ecx,ebx                   ;;///赋值给ecx控制内层循环
  29.        sub         eax,ebx              

  30.         mov       LEFT_REG,  dword ptr [esp + 08h+16]   ; //left每次进入内循环时取新值。
  31.         lea          LEFT_REG,[LEFT_REG+4*eax]    ////这个eax控制LEFT_REG的位置

  32.         shl          eax,1;;///乘以2
  33.         sub        eax,1 ;;

  34.         mov      RESULT_REG, dword ptr[esp + 04h+16]   ;
  35.         lea         RESULT_REG,[RESULT_REG+8*eax]///这个eax控制RESULT_REG的位置
  36. loop00:
  37.         mov      eax,dword ptr [LEFT_REG]
  38.         mul       dword ptr [RIGHT_REG]            

  39.         add       dword ptr [RESULT_REG],eax
  40.         adc       dword ptr [RESULT_REG+4],edx        

  41.         lea        LEFT_REG,[LEFT_REG+4]
  42.         lea        RESULT_REG,[RESULT_REG+8]
  43.         dec       ecx
  44.         jnz        loop00;;///内层循环

  45.         lea        RIGHT_REG,[RIGHT_REG+4]
  46.        dec       ebx
  47.         jnz       loop01/////外层循环
  48. /*//---------------------------------------------------------------///
  49.    以上loop00和loop01循环,用来求非平方项的乘积,
  50.    结果保存在两个相邻的RESULT[i]和RESULT[i+1]中,
  51.    不考虑最终的模10^8进位

  52. ///---------------------------------------------------------------*///     


  53.         mov         RESULT_REG, dword ptr[esp + 04h+16]
  54.         mov         ecx,dword ptr[esp+0Ch+16]  ///每次读取新的LL
  55.         shl            ecx,1;;///乘以2
  56.         sub          ecx,3
  57. loop02:
  58.         mov        eax,dword ptr [RESULT_REG+8]
  59.         shld         dword ptr[RESULT_REG+12],eax,1
  60.         shl           dword ptr[RESULT_REG+8],1

  61.         lea          RESULT_REG,[RESULT_REG+8]
  62.         dec         ecx
  63.         jnz          loop02
  64. /*///-----------------------------------------------------------------------------------------////
  65.     以上的loop02用来将非平方项的结果乘以2, 不考虑最终的模10^8进位

  66.           
  67. ////-----------------------------------------------------------------------------------------*////
  68. kkkk:
  69.         mov        ecx,dword ptr[esp+0Ch+16]
  70.         mov        RESULT_REG, dword ptr[esp + 04h+16]
  71.         mov        LEFT_REG, dword ptr[esp +  08h+16]   ;  right
  72. loop03:
  73.         mov        eax,dword ptr [LEFT_REG]
  74.         mul          dword ptr [LEFT_REG]

  75.         add        dword ptr [RESULT_REG],eax
  76.         adc        dword ptr [RESULT_REG+4],edx

  77.         lea        RESULT_REG,[RESULT_REG+16]
  78.         lea        LEFT_REG,[LEFT_REG+4]
  79.         dec        ecx
  80.         jnz        loop03
  81. /*///-------------------------------------------------------------------------------////
  82.           以上的loop03用来把平方项加到结果中,不考虑进位。

  83. ////-------------------------------------------------------------------------------*////

  84.         xor        edx,edx
  85.         mov      ebx,100000000
  86.         mov      ecx,dword ptr[esp+0Ch+16]
  87.         shl         ecx,1
  88.         mov      RESULT_REG, dword ptr[esp + 04h+16]   ; result
  89. loop04:
  90.         mov      eax,dword ptr [RESULT_REG+4]  ///取本位的高32位做除法
  91.         div         ebx

  92.         add        dword ptr [RESULT_REG+12],eax///商加在下一个数的高32位
  93.         mov       eax, dword ptr [RESULT_REG]  ///取本位数的低32位做除法
  94.         div          ebx

  95.         mov       dword ptr [RESULT_REG],edx  ///本位的余数,就是结果
  96.         xor         edx,edx
  97.         add        dword ptr [RESULT_REG+8],eax ///本位的商,加在下一位的低32位上。
  98.         adc        dword ptr [RESULT_REG+12],edx;;

  99.         lea        RESULT_REG, [RESULT_REG+8]
  100.         sub       ecx,1
  101.         jnz        loop04
  102. /*///---------------------------------------------------------------------------////
  103.     以上的loop04语句用来将RESULT[i*8+4]和RESULT[i*8]组成的64位中间结果进位到
  104.     RESULT[(i+1)*8+4]和RESULT[(i+1)*8]并获得正确结果
  105. ////----------------------------------------------------------------------------*////
  106.         mov        ecx,dword ptr[esp+0Ch+16]
  107.         shl           ecx,1

  108.         mov        edx,1
  109.         xor          ebx,ebx
  110.         mov        RESULT_REG, dword ptr[esp + 04h+16]   ; result
  111. loop05:
  112.         mov       eax, dword ptr [RESULT_REG+8*edx]
  113.         mov       dword ptr [RESULT_REG+4*edx],eax

  114.         mov       dword ptr[RESULT_REG+8*edx],ebx
  115.         mov       dword ptr[RESULT_REG+8*edx+4],ebx

  116.         add        edx,1
  117.         sub        ecx,1
  118.         jnz         loop05

  119. /*//--------------------------------------------------------------------------/////
  120.         以上的loop05语句,用来把正确结果移动到正常位置,
  121.         并将多余的数清零。
  122. //*-------------------------------------------------------------------------*////


  123.         pop        ebp
  124.         pop        ebx
  125.         pop        edi
  126.         pop        esi

  127.         ret
  128.         }
  129. }/////*///




复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2016-1-11 23:13:05 | 显示全部楼层
这里给出一楼函数的一个调用示例:



  1. #include <stdio.h>
  2. unsigned int bignum[2000]={0}, result[500000]={0};
  3. //----------------------------------------//
  4. //把一楼的代码粘贴在这里
  5. //----------------------------------------//
  6. void main()
  7. {          
  8.         int i,s,Len;
  9. //  ch[]=30000000000321456987100000009999999999999999993214
  10. //将ch[]按10^8为进位的基,存入数组bignum[]中。
  11.                 bignum[0]=99993214;
  12.                 bignum[1]=99999999;
  13.                 bignum[2]=999999;
  14.                 bignum[3]=87100000;
  15.                 bignum[4]=3214569;
  16.                 bignum[5]=0;
  17.                 bignum[6]=30;
  18. //大整数的长度是:
  19.        Len=6+1;
  20. //调用一楼的函数,注意函数的接口条件:
  21. _axa_(result,bignum,Len);
  22.         i=100;
  23.                  while((result[i]==0)&&(i>0))//前导零清除。
  24.                          {
  25.                                  i--;
  26.                          }      
  27.                 printf("%d",result[i]);//输出语句。把乘积的结果输出。
  28.                 for(s=i-1;s>=0;s--)//输出语句。把乘积的结果输出。
  29.                        printf("%08d",result[s]);

  30. //这里是实际的平方结果:
  31. //result[]=bignum[]^2=9000000000 1928741922 6103335194 5554095728 3913933484
  32. //                    0000095637 1857710787 9986428000 0000000000 046049796
  33. // 共99位数。实际输出数字是全部连在一起的,为了方便我把它写成了10位一组,                       

  34.                 printf("\n");   
  35. return 0;
  36. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2016-1-13 16:30:24 | 显示全部楼层
有更好的算法哦~~~
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2016-1-13 20:21:16 | 显示全部楼层
本帖最后由 只是呼吸 于 2016-1-13 20:43 编辑
有更好的算法哦~~~


咳咳……。我不会哦,我只会最原始的啊。这个算法就是模拟手算的平方算法,比调用乘法快。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-5-12 06:25 , Processed in 0.041587 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表