我在Delphi中編寫(xiě)一個(gè)簡(jiǎn)單的BigInteger類(lèi)型。它主要由一個(gè)動(dòng)態(tài)數(shù)組TLimb組成,其中TLimb是一個(gè)32位無(wú)符號(hào)整數(shù),以及一個(gè)32位大小的字段,該字段還保存BigInteger的符號(hào)位。要添加兩個(gè)BigInteger,我創(chuàng)建了一個(gè)適當(dāng)大小的新BigInteger,然后進(jìn)行了一些記賬,然后調(diào)用以下過(guò)程,向其傳遞三個(gè)指針,分別指向左右操作數(shù)及其結(jié)果的數(shù)組的開(kāi)頭,以及左右肢的數(shù)量。簡(jiǎn)碼:class procedure BigInteger.PlainAdd(Left, Right, Result: PLimb; LSize, RSize: Integer); asm// EAX = Left, EDX = Right, ECX = Result
PUSH ESI
PUSH EDI
PUSH EBX
MOV ESI,EAX // Left
MOV EDI,EDX // Right
MOV EBX,ECX // Result
MOV ECX,RSize // Number of limbs at Left
MOV EDX,LSize // Number of limbs at Right
CMP EDX,ECX
JAE @SkipSwap
XCHG ECX,EDX // Left and LSize should be largest
XCHG ESI,EDI // so swap@SkipSwap:
SUB EDX,ECX // EDX contains rest
PUSH EDX // ECX contains smaller size XOR EDX,EDX
@MainLoop:
MOV EAX,[ESI + CLimbSize*EDX] // CLimbSize = SizeOf(TLimb) = 4.
ADC EAX,[EDI + CLimbSize*EDX]
MOV [EBX + CLimbSize*EDX],EAX
INC EDX
DEC ECX
JNE @MainLoop
POP EDI
INC EDI // Do not change Carry Flag
DEC EDI
JE @LastLimb@RestLoop:
MOV EAX,[ESI + CLimbSize*EDX]
ADC EAX,ECX
MOV [EBX + CLimbSize*EDX],EAX
INC EDX
DEC EDI
JNE @RestLoop@LastLimb:這段代碼很好用,我對(duì)此非常滿意,直到我注意到,在我的開(kāi)發(fā)設(shè)置(iMac上的Parallels VM中為Win7)上,有一個(gè)簡(jiǎn)單的PURE PASCAL加法例程,在用變量和一些if條款,是更快的比我的平淡,簡(jiǎn)單的手工制作的匯編程序。我花了一段時(shí)間才發(fā)現(xiàn),在某些CPU(包括我的iMac和較舊的筆記本電腦)上,DECor INC和ADCor 的組合SBB可能非常慢。但是,在我的大多數(shù)其他計(jì)算機(jī)上(我還有五臺(tái)PC可以對(duì)其進(jìn)行測(cè)試,盡管其中四臺(tái)完全相同),但是速度卻相當(dāng)快。這使我在“慢速”計(jì)算機(jī)上的代碼快了將近三倍,但在“更快”計(jì)算機(jī)上的代碼卻慢了約20%。因此,現(xiàn)在,作為初始化代碼,我做了一個(gè)簡(jiǎn)單的定時(shí)循環(huán),并用它來(lái)決定是否將單元設(shè)置為調(diào)用普通程序或仿真例程。這幾乎總是正確的,但是有時(shí)它會(huì)在應(yīng)該選擇仿真例程的情況下選擇(較慢的)普通例程。但是我不知道這是否是最好的方法。
在某些CPU上的緊密循環(huán)中ADC / SBB和INC / DEC的問(wèn)題
素胚勾勒不出你
2019-09-26 11:14:15