我在Delphi中编写一个简单的BigInteger类型。它主要由一个动态数组TLimb组成,其中TLimb是一个32位无符号整数,以及一个32位大小的字段,该字段还保存BigInteger的符号位。要添加两个BigInteger,我创建了一个适当大小的新BigInteger,然后进行了一些记账,然后调用以下过程,向其传递三个指针,分别指向左右操作数及其结果的数组的开头,以及左右肢的数量。简码: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:这段代码很好用,我对此非常满意,直到我注意到,在我的开发设置(iMac上的Parallels VM中为Win7)上,有一个简单的PURE PASCAL加法例程,在用变量和一些if条款,是更快的比我的平淡,简单的手工制作的汇编程序。我花了一段时间才发现,在某些CPU(包括我的iMac和较旧的笔记本电脑)上,DECor INC和ADCor 的组合SBB可能非常慢。但是,在我的大多数其他计算机上(我还有五台PC可以对其进行测试,尽管其中四台完全相同),但是速度却相当快。这使我在“慢速”计算机上的代码快了将近三倍,但在“更快”计算机上的代码却慢了约20%。因此,现在,作为初始化代码,我做了一个简单的定时循环,并用它来决定是否将单元设置为调用普通程序或仿真例程。这几乎总是正确的,但是有时它会在应该选择仿真例程的情况下选择(较慢的)普通例程。但是我不知道这是否是最好的方法。
3 回答
烙印99
TA贡献1829条经验 获得超13个赞
我终于有一些时间来实现单寄存器寻址模式。对于很长的BigIntegers,这相差约12%(总体速度提高)。我认为现在没有什么可以挤出的了。我尝试使用更小的BigIntegers(最多1到10个肢体,平均约3个肢体),并且与简单的简单循环没有明显的时序差异,因此我将使用优化的展开循环例程(即,最后一个版本)作为替换。它变得不那么容易阅读,因此我不得不添加一些其他注释。<g>
添加回答
举报
0/150
提交
取消