// 本代码使用在分治法的时候,不必考虑数据对齐的问题(如果考虑就复杂了),len也是偶数,所以后面的len为奇数的检查部分是没有必要的,跟一般的方法快不了多少,微乎其微,在此仅提供另外一种思路,本人原创的,如果你有更好的方法请告知
// 实现 dest = a + b ,dest, a, b都是高位在前,低位在后,即dest[0]表示数的最高位,a,b也类似
const unsigned int Base = 1000000000; // 10^9
const unsigned __int64 Base64 = 0x3B9ACA003B9ACA00;
const unsigned __int64 CarryFirst = 0x0000000100000000;
const unsigned __int64 CarryNext = 0x0000000000000001;/* add_mmx() mmx指令版本 */
__declspec(naked)
long add_mmx(unsigned long *dest, unsigned long *a, unsigned long *b, size_t len)
{
__asm
{
mov ecx, dword ptr [esp+0x10] // len
xor eax, eax
test ecx, ecx
jz add_exitpush ebp
mov ebp, ecxpush ebx
mov ebx, dword ptr [esp+0x14] // ebx = b
push esi
mov esi, dword ptr [esp+0x14] // esi = a
push edi
mov edi, dword ptr [esp+0x14] // edi = dest
sub esi, ebx // esi = a - b
lea edx, dword ptr [ebx+4*ecx-8] // &b[i]
sub edi, ebx // edi = dest - bshr ecx, 1 // len = len / 2
movq mm7, Base64 // 0x3B9ACA003B9ACA00
movq mm5, CarryFirst // 0x0000000100000000
movq mm6, CarryNext // 0x0000000000000001
pxor mm2, mm2 // carry 清零add_loop:
movq mm0, dword ptr [esi+edx] // a[i]
movq mm1, dword ptr [edx] // b[i]paddd mm0, mm2 // sum = a[i]+carry
movq mm3, mm7 // mm7 = Base64
paddd mm0, mm1 // sum += b[i]pcmpgtd mm3, mm0 // sum >= Base(10^9) ? 这里比较复杂,有讲究,必须比较2次
pandn mm3, mm5 // mm5 = CarryFirst
psrlq mm3, 32 // 获得进位 CarryFirst, mm3 >> 32
movq mm4, mm7 // mm7 = Base64
paddd mm0, mm3 // 累加进位pcmpgtd mm4, mm0 // sum >= Base(10^9) ? 进位以后,第二次比较
movq mm2, mm4 // 备份比较结果
pandn mm4, mm7 // 获得进位减法变量, 用于sum -= Base
pandn mm2, mm6 // 获得下一次的进位, CarryNextpsubd mm0, mm4 // 相当于 sum -= Base
psllq mm2, 32 // carry = CarryNext << 32movq dword ptr [edi+edx], mm0 // dest[i] = sum
sub edx, 8 // edx = &b[i] - 8, 相当于i-=2
dec ecx // len--
jne add_looptest ebp, 1 // 如果len是奇数,则累加最后一个数
jz add_fast_retmov ecx, dword ptr [esi+edx] // esi = a[i]
mov ebx, dword ptr [edx] // edx = b[i]
add ecx, ebx // sum = a[i] + b[i]
mov ebx, Base // esi = Base
add ecx, eax // sum += carry
xor eax, eax // carry = 0
cmp ecx, ebx // sum >= Base ?
jb add_sum // <
mov eax, 1 // carry = 1
sub ecx, ebx // sum -= Baseadd_sum:
mov dword ptr [edi+edx], ecx // dest[i] = sumpop edi
pop esi
pop ebx
pop ebpemms
add_exit:
retadd_fast_ret:
psrlq mm2, 32 // carry >> 32
movd eax, mm2 // 返回 carrypop edi
pop esi
pop ebx
pop ebpemms
ret
}
}