为什么FloatToText在不同的项目中返回不同的值?

时间:2014-02-27 08:40:05

标签: delphi floating-point floating-point-precision

我这样使用FloatToText

function ExFloatToStr(Value: Extended): string;
var
  Buffer: array[0..63] of Char;
  FormatSettings: TFormatSettings;
begin
  GetLocaleFormatSettings(GetUserDefaultLCID, FormatSettings);
  SetString(Result, Buffer, FloatToText(Buffer, Value, fvExtended, ffGeneral,
    18, 0, FormatSettings));
end;

如果我传递给这个函数值9229.99,它返回一个字符串值9229.9900000000016,但它不是我想要的。 当我创建一个新项目并在那里复制上面的代码时,它运行良好。它返回9229.99。

他们在不同的项目中工作的原因可能是什么?

2 个答案:

答案 0 :(得分:5)

这实际上是一个可表示性的问题。这是SSCCE:

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows;

function ExFloatToStr(Value: Extended): string;
var
  Buffer: array[0..63] of Char;
  FormatSettings: TFormatSettings;
begin
  GetLocaleFormatSettings(GetUserDefaultLCID, FormatSettings);
  SetString(Result, Buffer, FloatToText(Buffer, Value, fvExtended, ffGeneral,
    18, 0, FormatSettings));
end;

var
  X: Double;
  Y: Extended;

begin
  X := 9229.99;
  Y := 9229.99;
  Writeln(ExFloatToStr(X));
  Writeln(ExFloatToStr(Y));
  Readln;
end.

<强>输出

9229.98999999999978
9229.99

你要18个数字。将值存储为双精度时,存储的值将变为不精确到18位十进制精度。双精度值具有15-16个精确的十进制小数位数。并且该值小于18.当您将值存储为扩展值时,可用的精度更高,足以将您的值精确存储到您请求的18位小数精度。

我总是在这件事上提到Rob Kennedy的精彩页面:http://pages.cs.wisc.edu/~rkennedy/exact-float?number=9229.99

这告诉我们,当你转换为extended和double时,你的值表示为:

9229.99 = + 9229.99000 00000 00000 21316 28207 28030 05576 13372 80273 4375
9229.99 = + 9229.98999 99999 99781 72127 15744 97222 90039 0625

这与上面的输出完全一致。

所以,我希望您会发现在现有项目中,您将在某个时刻将值存储到双精度变量中。那时你会失去Extended的额外精确度。

对于它的价值,我认为80位扩展类型是不合时宜的。它仅支持英特尔芯片,仅供32位编译器使用。根据我的经验,它提供了超过双精度的任何真正的好处。由于内存对齐,其性能很差。作为很多浮点代码的作者,我从不使用扩展。

答案 1 :(得分:2)

编译x86与x64 Windows目标时存在差异。

对于x86平台,“扩展”类型在x64平台上具有不同的“大小”。

请参阅Delphi帮助(XE2):

System.Extended offers greater precision than other real types, but is less
portable. Be careful using System.Extended if you are creating data files to
share across platforms. 

On Win32 systems, the size of System.Extended is 10 bytes. 

On Win64 systems, however, the System.Extended type is an alias for System.Double,
which is only 8 bytes. This difference can adversely affect numeric precision in
floating-point operations. For more information, see Delphi Considerations for
Cross-Platform Applications. 

Writeln(IntToStr(SizeOf(Extended))); // displays 10 on Win32 and 8 on Win64

基本上这意味着在x64平台上,您的浮点值不太重要,这可能导致与文本值的不同转换。