【发布时间】:2019-07-22 08:18:08
【问题描述】:
我有以下代码
const
NumIterations = 10000000;
var
i, j : Integer;
x : array[1..100] of Double;
Start : Cardinal;
S : Double;
begin
for i := Low(x) to High(x) do x[i] := i;
Start := GetTickCount;
for i := 1 to NumIterations do S := System.Math.Sum(x);
ShowMessage('Math.Sum: ' + IntToStr(GetTickCount - Start));
Start := GetTickCount;
for i := 1 to NumIterations do begin
S := 0;
for j := Low(x) to High(x) do S := S + x[j];
end;
ShowMessage('Simple Sum: ' + IntToStr(GetTickCount - Start));
end;
当为 Win32 编译时,Math.Sum 比简单循环快得多,因为 Math.Sum 是用汇编程序编写的,并且使用四重循环展开。
但是当为 Win64 编译时,Math.Sum 比简单循环要慢得多,因为在 64 位 Math.Sum 中使用 Kahan 求和。这是一种在求和过程中最大限度地减少错误堆积的准确性优化,但比简单的循环要慢得多。
即当为 Win32 编译时,我得到了针对速度优化的代码,当为 Win64 编译相同的代码时,我得到了针对准确性优化的代码。这并不是我天真地期望的那样。
Win32/64 之间的这种差异有什么合理的原因吗?双精度始终是 8 字节,因此在 Win32/64 中精度应该相同。
在当前版本的 Delphi 中,Math.Sum 是否仍以相同的方式实现(Win32 中的汇编程序和循环展开,Win64 中的 Kahan 求和)?我用的是 Delphi-XE5。
【问题讨论】:
-
可能在 32 位中,朴素是相当准确的,因为算术是使用 80 位 x87 寄存器完成的。在现实世界的设置中,我怀疑您会观察到任何性能差异,因为访问主内存的时间会淹没 Kahan sum 的额外 FP 操作。您的基准测试非常不切实际,因为数据集非常小,无法放入 L0 缓存。由于这个原因,我了解到使用这种微基准来优化代码通常是一种巨大的时间浪费。
标签: delphi delphi-xe5