|
在大整数的运算程序中,无符号加法应该算最容易写的了。但要把加法的运算程序尽可能运行快一点,依旧要动一番脑筋。
这个加法程序是我在本论坛学习的过程中,参照了管理员 liangbch 的两篇文章写成的。
http://bbs.emath.ac.cn/thread-216-11-1.html 在这篇文章的第102楼,学习了汇编语言的接口技术。
http://bbs.emath.ac.cn/thread-521-3-1.html 在这篇文章,学习了把单精度除法转化为乘法的技术。
下面是我写的大整数加法程序:- /* * 声明:本函数的接口技术、单精度乘法代替单精度除法技术,学习自管理员liangbch的两篇帖子:http://bbs.emath.ac.cn/thread-216-11-1.html第102楼 和 http://bbs.emath.ac.cn/thread-521-3-1.html * liangbch依法享有著作权和解释权 *\ * dst: 目的数组,存放和。 * src1: 第一个加数,(操作数) * src2: 第二个加数,(操作数) * size1; 第一个加数的长度。 * size2: 第二个加数的长度。 * 所有数组均采用10^8进制,数组较大的下标对应10进制数的高位,数组较小的下标对应10进制数的低位。 */_declspec(naked)////这个程序能处理任意长度的两个无符号大整数之和,速度快。void big_add_ALU(unsigned long *dst,unsigned long *src1,unsigned long *src2,int size1,int size2){#undef BASE10000_MASK#define BASE10000_MASK BASE _asm { push esi push edi push ebx push ebp mov edi, dword ptr [esp+0Ch+16] mov ebp, dword ptr [esp+04h+16] xor eax,eax mov ebx, BASE10000_MASK movd mm4,eax mov esi, dword ptr [esp+08h+16] mov eax, 0xabcc7712 movd mm7,ebx movd mm5,eax xor ebx,ebx mov ecx, dword ptr [esp+14h+16] mov eax, dword ptr [esp+10h+16] cmp eax, ecx jl fffd jmp jjj fffd: mov ecx,eax // < 则跳转jjj: loop02: movd mm1, dword ptr [esi] movd mm2, dword ptr [edi] paddq mm1, mm2 paddq mm1, mm4 movq mm2, mm1 // mm2, 总和 pmuludq mm1,mm5 psrlq mm1,58 movq mm4,mm1// mm4 进位 pmuludq mm1,mm7 psubq mm2,mm1 movd dword ptr[ebp],mm2 lea edi, dword ptr [edi+4] lea ebp, dword ptr [ebp+4] lea esi, dword ptr [esi+4] dec ecx jnz loop02//--------以上是公共部分之和------------------// mov ecx, dword ptr [esp+14h+16] mov eax, dword ptr [esp+10h+16] cmp eax,ecx je exit1 jl fffdd sub eax,ecx mov ecx,eaxloop03: movd eax,mm4 cmp eax,ebx je exit2 movd mm1, dword ptr [esi] paddq mm1,mm4 movq mm2,mm1 // mm2,总和 pmuludq mm1,mm5 psrlq mm1,58 movq mm4,mm1// mm4 进位 pmuludq mm1,mm7 psubq mm2,mm1 movd dword ptr[ebp],mm2 lea esi, dword ptr [esi+4] lea ebp, dword ptr [ebp+4] dec ecx jnz loop03//////exit2: cmp ecx,ebx je exit1 loop04: mov eax,dword ptr [esi] mov dword ptr[ebp],eax lea esi, dword ptr [esi+4] lea ebp, dword ptr [ebp+4] dec ecx jnz loop04///// jmp exit1///-----------------以上是第一个加数大于第二个加数的求和-------------//fffdd: sub ecx, eaxloop05: movd eax,mm4 cmp eax,ebx je exit3 movd mm1,dword ptr [edi] paddq mm1,mm4 movq mm2,mm1 //mm2,总和 pmuludq mm1,mm5 psrlq mm1,58 movq mm4,mm1 // mm4 进位 pmuludq mm1,mm7 psubq mm2,mm1 movd dword ptr[ebp],mm2 lea edi, dword ptr [edi+4] lea ebp, dword ptr [ebp+4] dec ecx jnz loop05//////exit3: cmp ecx,ebx je exit1 loop06: mov eax,dword ptr [edi] mov dword ptr[ebp],eax lea edi, dword ptr [edi+4] lea ebp, dword ptr [ebp+4] dec ecx jnz loop06///// //--------------------------------------------//exit1: movd dword ptr [ebp],mm4 pop ebp pop ebx pop edi pop esi emms ret }}/////*///
复制代码
作为对照,我写了一个c语言的大整数加法函数- /* * 这是c语言写的大整数加法,作为对照。 * * 为了简单一点: * * 1)要求第一个加数src1的实际长度大于等于第二个加数src2的实际长度。 * 2)第二个加数的前面补零,与第一个加数的实际长度对齐。(实际处理中只需第二个加数src2的最大空间大于src1的实际长度即可) * 3)参数size1传递第一个加数的实际长度。 */void big_add_c(unsigned long *dst,unsigned long *src1,unsigned long *src2,int size1){ int i,temp=0; for(i=0;i<size1;i++) { dst[i]=src1[i]+src2[i]+temp; temp=0; if(dst[i]>=BASE) { dst[i]-=BASE; temp=1; } } dst[i]=temp;}
复制代码 |
|