Round

时间:2015-07-14 19:33:16

标签: delphi delphi-xe7

我知道关于浮点数的近似问题,所以我理解4.5如果近似为4.4999999999999991,可以向下舍入到4。我的问题是为什么使用相同类型的32位和64位存在差异。

在下面的代码中,我有两个计算。在32位中,MyRoundValue1的值为4,MyRoundValue2的值为5.在64位中它们都是4.不应该结果与32位和64位一致吗?

{$APPTYPE CONSOLE}
const
  MYVALUE1: Double = 4.5;
  MYVALUE2: Double = 5;
  MyCalc: Double = 0.9;
var
  MyRoundValue1: Integer;
  MyRoundValue2: Integer;
begin
  MyRoundValue1 := Round(MYVALUE1);
  MyRoundValue2 := Round(MYVALUE2 * MyCalc);
  WriteLn(IntToStr(MyRoundValue1));
  WriteLn(IntToStr(MyRoundValue2));
end.

2 个答案:

答案 0 :(得分:7)

在x87中这段代码:

MyRoundValue2 := Round(MYVALUE2 * MyCalc);

编译为:

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

Delphi RTL下x87单元的默认控制字执行80位精度的计算。因此浮点单位将{乘以closest 64 bit value to 0.9乘以5,即:

0.90000 00000 00000 02220 44604 92503 13080 84726 33361 81640 625

请注意,此值大于0.9。事实证明,当乘以5并四舍五入到最接近的80位值时,该值大于4.5。因此Round(MYVALUE2 * MyCalc)返回5.

在64位时,浮点数学运算在SSE单元上完成。这不使用80位中间值。事实证明,最接近0.9倍的5倍,舍入到双精度正好是4.5。因此Round(MYVALUE2 * MyCalc)在64位上返回4。

通过存储为double而不是依赖于中间80位值,您可以说服32位编译器的行为与64位编译器相同:

{$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.

该程序产生与64位程序相同的输出。

或者您可以强制x87单元使用64位中间体。

{$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.

答案 1 :(得分:3)

System.Round 在内部接受扩展值。在32位计算中,FPU中的扩展。在64位扩展中类似于 Double 。内部表示可能差别很大,以产生差异。