Trong x87 mã này:
MyRoundValue2 := Round(MYVALUE2 * MyCalc);
được biên dịch để:
MyRoundValue2 := Round(MYVALUE2 * MyCalc);
0041C4B2 DD0508E64100 fld qword ptr [$0041e608]
0041C4B8 DC0D10E64100 fmul qword ptr [$0041e610]
0041C4BE E8097DFEFF call @ROUND
0041C4C3 A3C03E4200 mov [$00423ec0],eax
Từ kiểm soát mặc định cho các đơn vị x87 dưới Delphi RTL thực hiện các tính toán đến 80 bit chính xác. Vì vậy, đơn vị dấu chấm động nhân 5 với số closest 64 bit value to 0.9 là:
0.90000 00000 00000 02220 44604 92503 13080 84726 33361 81640 625
Lưu ý rằng giá trị này lớn hơn 0,9. Và nó chỉ ra rằng khi nhân với 5, và làm tròn tới giá trị 80 bit gần nhất, giá trị lớn hơn 4.5. Do đó Round(MYVALUE2 * MyCalc)
trả về 5.
Trên 64 bit, phép tính điểm động được thực hiện trên đơn vị SSE. Điều đó không sử dụng các giá trị trung gian 80 bit. Và nó chỉ ra rằng 5 lần gần gấp đôi đến 0,9, được làm tròn đến độ chính xác gấp đôi là chính xác 4,5. Do đó Round(MYVALUE2 * MyCalc)
trả về 4 trên 64 bit.
Bạn có thể thuyết phục các trình biên dịch 32 bit để hành xử theo cách tương tự như trình biên dịch 64 bit bằng cách lưu trữ vào một đôi hơn là dựa trên các giá trị 80 bit trung gian:
{$APPTYPE CONSOLE}
const
MYVALUE1: Double = 4.5;
MYVALUE2: Double = 5;
MyCalc: Double = 0.9;
var
MyRoundValue1: Integer;
MyRoundValue2: Integer;
d: Double;
begin
MyRoundValue1 := Round(MYVALUE1);
d := MYVALUE2 * MyCalc;
MyRoundValue2 := Round(d);
WriteLn(MyRoundValue1);
WriteLn(MyRoundValue2);
end.
Chương trình này sẽ cho kết quả tương tự như của bạn Chương trình 64 bit.
Hoặc bạn có thể buộc đơn vị x87 sử dụng trung gian 64 bit.
{$APPTYPE CONSOLE}
uses
SysUtils;
const
MYVALUE1: Double = 4.5;
MYVALUE2: Double = 5;
MyCalc: Double = 0.9;
var
MyRoundValue1: Integer;
MyRoundValue2: Integer;
begin
Set8087CW($1232); // <-- round intermediates to 64 bit
MyRoundValue1 := Round(MYVALUE1);
MyRoundValue2 := Round(MYVALUE2 * MyCalc);
WriteLn(MyRoundValue1);
WriteLn(MyRoundValue2);
end.
Nguồn
2015-07-14 19:53:27
Tôi sẽ không dám thay đổi từ kiểm soát fpu. –
@LURD Tôi dám. Có rất nhiều kịch bản mà bạn phải làm. Một ví dụ tốt là khi giao dịch với các thư viện bên ngoài. Đôi khi họ không thích nó nếu các ngoại lệ được tiết lộ. Tôi đang nhìn vào bạn Excel 2013. Trong công việc của tôi, nhận được phiên bản 32 bit để hoạt động gần với phiên bản 64 bit là quan trọng. Do đó '$ 1232' là cách phiên bản 32 bit của tôi cuộn. –
@LURD Tất nhiên, như tất cả các bạn phải mệt mỏi của tôi nói rằng, nó không giúp đỡ rằng các chức năng Delphi RTL Set8087CW không phải là threadsafe. Như tôi đã nói rất nhiều lần, tôi đã nói với Emba cách sắp xếp điều này nhưng họ sẽ không làm điều đó. Có lẽ vì họ quá sợ hãi để thay đổi. –