// 本代码使用在分治法的时候,不必考虑数据对齐的问题(如果考虑就复杂了),len也是偶数,所以后面的len为奇数的检查部分是没有必要的,跟一般的方法快不了多少,微乎其微,在此仅提供另外一种思路,本人原创的,如果你有更好的方法请告知
// 实现 dest = a - b ,dest, a, b都是高位在前,低位在后,即dest[0]表示数的最高位,a,b也类似
const unsigned int Base = 1000000000; // 10^9
const unsigned __int64 Sign64 = 0x0000000000000000;
const unsigned __int64 BorrowFirst = 0x0000000100000000;
const unsigned __int64 BorrowNext = 0x0000000000000001;/* sub_mmx() mmx指令版本 */
__declspec(naked)
long sub_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 sub_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, BorrowFirst // 0x0000000100000000
movq mm6, BorrowNext // 0x0000000000000001
pxor mm2, mm2 // borrow 清零sub_loop:
movq mm0, dword ptr [esi+edx] // a[i]
movq mm1, dword ptr [edx] // b[i]psubd mm0, mm2 // dif = a[i]-borrow
pxor mm3, mm3 // mm3 = Sign64 (0x0000000000000000)
psubd mm0, mm1 // dif -= b[i]pcmpgtd mm3, mm0 // dif < 0 ? 这里比较复杂,有讲究,必须比较2次
pand mm3, mm5 // mm5 = BorrowFirst
psrlq mm3, 32 // 获得进位 BorrowFirst, mm3 >> 32
pxor mm4, mm4 // mm4 = Sign64 (0x0000000000000000)
psubd mm0, mm3 // 累减进位pcmpgtd mm4, mm0 // dif < 0 ? 进位以后,第二次比较
movq mm2, mm4 // 备份比较结果
pand mm4, mm7 // 获得进位加法变量, 用于dif += Base
pand mm2, mm6 // 获得下一次的进位, BorrowNextpaddd mm0, mm4 // 相当于 dif += Base
psllq mm2, 32 // borrow = BorrowNext << 32movq dword ptr [edi+edx], mm0 // dest[i] = dif
sub edx, 8 // edx = &b[i] - 8, 相当于i-=2
dec ecx // len--
jne sub_loop
///*
test ebp, 1 // 如果len是奇数,则累减最后一个数
jz sub_fast_retmov ecx, dword ptr [esi+edx] // esi = a[i]
mov ebx, dword ptr [edx] // edx = b[i]
sub ecx, ebx // dif = a[i] - b[i]
mov ebx, Base // esi = Base
add ecx, eax // dif -= borrow
xor eax, eax // borrow = 0
cmp ecx, ebx // dif < 0 ?
jb sub_dif // <
mov eax, 1 // borrow = 1
add ecx, ebx // dif += Basesub_dif:
mov dword ptr [edi+edx], ecx // dest[i] = difpop edi
pop esi
pop ebx
pop ebpemms
sub_exit:
retsub_fast_ret:
//*/psrlq mm2, 32 // borrow >> 32
movd eax, mm2 // 返回borrowpop edi
pop esi
pop ebx
pop ebpemms
//sub_exit:
ret
}
}