Using the fldcw instruction it's possible to change the precision of the FPU unit to 24 or more bits. However after doing some testing I'm starting to think that very few x87 operations are in fact using that setting.
I haven't tested all operations but on this test machine so far, it looks like only fdiv and fsqrt stop computing at the selected precision, and that all other operations (fadd fsub fmul...) always compute full extended precision.
If that was the case I would expect it to be because those 2 instructions (fdiv and fsqrt) are significantly slower then most other x87 FPU instructions so when lower precision is sufficient it's possible to speed them up, but really, I'm just wondering if this has always been the case or if it's a quirk of the very recent processor used in my test machine.
edit: here's delphi code to show it
program Project1;
uses
windows,dialogs,sysutils;
{$R *.res}
const
test_mul:single=1234567890.0987654321;
var
i:longint;
s:single absolute i;
s1,s2,s3:single;
procedure test_24;
asm
mov word([esp-2]),$103f // 24bit precision, trunc
fldcw word([esp-2])
fld [s]
fmul [test_mul]
fstp [s1]
end;
procedure test_53;
asm
mov word([esp-2]),$123f // 53bit precision, trunc
fldcw word([esp-2])
fld [s]
fmul [test_mul]
fstp [s2]
end;
procedure test_64;
asm
mov word([esp-2]),$133f // 64bit precision, trunc
fldcw word([esp-2])
fld [s]
fmul [test_mul]
fstp [s3]
end;
begin
i:=0;
repeat
test_24;
test_53;
test_64;
if (s1<>s2) or (s2<>s3) then begin
showmessage('Error at step:'+inttostr(i));
break;
end;
inc(i);
until i=0;
showmessage('No difference found between precisions');
end.
edit2: false alarm, I was mistaken, I was storing as single instead of extended so couldn't catch the difference, here's a fixed test, thanks to hans passant for catching my mistake:
program Project1;
uses
windows,dialogs,sysutils;
{$R *.res}
const
test_mul:single=1234567890.0987654321;
var
i:longint;
errors:cardinal;
s:single absolute i;
s1,s2,s3:extended;
procedure test_24;
asm
mov word([esp-2]),$103f // 24bit precision, trunc
fldcw word([esp-2])
fld [s]
fmul [test_mul]
fstp [s1]
end;
procedure test_53;
asm
mov word([esp-2]),$123f // 53bit precision, trunc
fldcw word([esp-2])
fld [s]
fmul [test_mul]
fstp [s2]
end;
procedure test_64;
asm
mov word([esp-2]),$133f // 64bit precision, trunc
fldcw word([esp-2])
fld [s]
fmul [test_mul]
fstp [s3]
end;
begin
errors:=0;
i:=0;
repeat
test_24;
test_53;
test_64;
if (s1<>s2) or (s2<>s3) then begin
inc(errors);
end;
inc(i);
until i=0;
showmessage('Number of differences between precisions: '+inttostr(errors));
end.