x87精度如何影响平方根?

时间:2014-05-31 00:31:25

标签: assembly x86 x87

我写了一些代码来测试fsqrt函数,结果对我来说并不完全合理。这是代码(在delphi中):

uses
 mmsystem;

var
 rand:longint=123456789;

function rng:longint;
asm
 imul eax,[rand],$08088405
 inc eax
 mov [rand],eax
end;

function int_sqrt(adata:longint):longint;
asm
 fnstcw word([esp-2])

// mov word([esp-4]),$1f3f  // 80bit precision
 mov word([esp-4]),$1c3f  // 24bit precision
 fldcw word([esp-4])

 mov [esp-8],eax
 fild longint([esp-8])

 fsqrt

 fistp longint([esp-8])
 mov eax,[esp-8]

 fldcw word([esp-2])
end;

procedure TForm1.FormCreate(Sender: TObject);
var
 start,i,r,s1,s2:longint;
 time0,time1:longint;
begin
 timebeginperiod(1);
 time0:=timegettime;

 start:=1000000000;
 for i:=(start+0) to (start+100000000) do begin
  //r:=i;
  r:=abs(rng);
//  r:=2134567890;
//  r:=$7fffffff;
  s1:=int_sqrt(r);
  s2:=trunc(sqrt(r));
  if s1<>s2 then
   showmessage('error: '+inttostr(r)+'/'+inttostr(s1)+'/'+inttostr(s2));
 end;

 time1:=timegettime;
 timeendperiod(1);
 showmessage('Milliseconds: '+inttostr(time1-time0));
end;

很简单,我正在寻找int的平方根。在int_sqrt中,其中一条精度线使x87使用24位精度作为sqrt精度,另一种是64位精度。正如预期的那样,24位版本的速度更快(10-20%取决于输入)。

这是问题所在。我没有找到一个32位(实际上是31位,最后一位是未使用的符号)int,当使用24位精度时会返回错误的结果!!

到目前为止,我唯一的理论是,只有最终结果取决于精度,而不是源或任何中间缓冲区。这是有道理的,因为31bit int的平方根的最大结果大小是16位。

这是怎么回事?

1 个答案:

答案 0 :(得分:2)

英特尔®64和IA-32架构软件开发人员手册卷。 2A Page 3-291(FILD):

  

将signed-integer源操作数转换为double   扩展精度浮点格式并将值推送到   FPU寄存器堆栈。源操作数可以是单词,双字或   四字整数。加载时没有舍入错误。

考虑数据作为80位双扩展精度浮点数存储在FPU 始终内。根据精度,FILD和FIST “忘记”位。精确度的影响是在结果足够精确时中止计算,并在之后取消的相应位

英特尔®64和IA-32架构软件开发人员手册卷。 1第8.1.5.2节(精确控制字段):

  

使用这些设置会消除双重优势   扩展精度浮点格式的64位有效位长度。   指定精度降低时,有效数的四舍五入   value将右侧未使用的位清零。

因此FSQRT对完整的80位寄存器起作用,并以24位的精度中止。我怀疑它以25的精度中止,以获得圆整的重要值。然后结果的“冗余”60位将无效。你有一个24位的结果,这对于16位整数就足够了,因为你注意到了。