Contributor: TERJE MATHISEN

{
> Still, I expect as a programmer for the CPU to have the right answer 100%
> of the time! My own errors are bad enough. :) It's still a bug and until
> it's 100% accurate and no less, it's not desirable to me and I would think
> others shall agree. Anything less is unreliable and unreliable doesn't
> cut it.

This is getting off-topic for the echo.  Please, if what you have to say has
nothing to do with programming in Pascal, don't say it here.

Here's something just posted to comp.lang.pascal on Usenet:

 From: Terje.Mathisen@hda.hydro.com (Terje Mathisen)
 Subject: FDIV fix for BP (fast & exact)
 Date: 1 Dec 1994 11:07:51 GMT

I have been working with Cleve Moler (from MathWorks) and Tim Coe about a sw
workaround for the Pentium FDIV bug.  Here is a BP version of the algorithm:

The FDIV_FIX unit defines a single function:

function fdiv(x: extended; y: extended): extended;

which will use about 25% more cycles than a single fdiv call, but always return
exact results for all double precision numbers, including the special cases of
Nan, Inf and denormal.
It also handles all extended precision numbers, giving a maximum error of a
single bit in the last position (1ulp).  This error can only be introduced if
the FDIV operations fails.
During the unit startup code, I test the FDIV instruction, and if if fails,
initialize a 16-byte table of critical nibble values.

If FDIV passes, the table is left empty, and no fixups will be done on
divisions.
=============== FDIV_FIX.PAS ===========================
}
{$N+,E-,G+}
Unit FDIV_FIX;

Interface

function fdiv(x, y : Extended): Extended;

const
  fdiv_risc_table : array [0..15] of byte = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
  fdiv_scale : single = 0.9375;
  one_shl_63_l : Longint = $5f000000;
var
  one_shl_63 : single absolute one_shl_63_l;

Implementation

function fdiv(x, y : Extended): Extended;
Assembler;
asm
  fld [x]
@restart:
  mov bx,word ptr [y+6]
  fld [y]
  add bx,bx
   jnc @denormal
{$IFOPT G+}
  shr bx,4
{$ELSE}
  mov cl,4
  shr bx,cl
{$ENDIF}
  cmp bl,255
   jne @ok
{$IFOPT G+}
  shr bx,8
{$ELSE}
  mov bl,bh
  and bx,255
{$ENDIF}
  cmp byte ptr fdiv_risc_table[bx],bh
   jz @ok
  fld [fdiv_scale]
  fmul st(2),st
  fmulp st(1),st
   jmp @ok
@denormal:
  or bx,word ptr [y]
  or bx,word ptr [y+2]
  or bx,word ptr [y+4]
   jz @zero
  fld [one_shl_63]
  fmul st(2),st
  fmulp st(1),st
  fstp [y]
   jmp @restart
@zero:
@ok:
  fdivp st(1),st
end;

const
  a_bug : single = 4195835.0;
  b_bug : single = 3145727.0;

Procedure fdiv_init;
var
  r : double;
  i : Integer;
begin
  r := a_bug / b_bug;
  if a_bug - r * b_bug > 1.0 then begin
    i := 1;
    repeat
      fdiv_risc_table[i] := i;
      Inc(i,3);
    until i >= 16;
  end;
end;

begin
  fdiv_init;
end.