Delphi / Borland Pascal STR程序是如何进行的

时间:2010-02-25 15:26:51

标签: delphi rounding delphi-2007 pascal

Borland Pascal 7和Delphi 2007都得到了STR程序STR,它取一个数字,一个长度和精度,然后把它转换成这样的字符串:

str(9.234:5:1, s); // -> s = '  9.2'

如果舍入是非模糊的,那么一切都很好,但如果不是(0.5 - >向上或向下?)则存在一个问题:它似乎依赖于BP中的浮点数据类型但显然在Delphi 2007中保持一致:

BP:

var
  e: extended;
  d: double;
begin
  d := 2.15;
  e := 2.15;
  str(d:5:1, s); { -> s = '  2.1' }
  str(e:5:1, s); { -> s = '  2.2' }
  { but: }
  d := 2.25
  e := 2.25
  str(d:5:1, s); { -> s = '  2.3' }
  str(e:5:1, s); { -> s = '  2.3' }

我无法找到关于双打如何被舍入的任何规则,而显然扩展总是四舍五入。

Delphi 2007显然总是独立于数据类型。

有人知道如何在BP中进行舍入以获得双值吗?

我想知道,因为我正在移植一些使用双精度到Delphi 2007的Borland Pascal代码,当我比较输出时,我得到了STR程序中的舍入导致的不一致。这些对结果并不重要,但却很难发现重要的差异。

5 个答案:

答案 0 :(得分:4)

d = 2.15和d = 2.25的情况不同:

2.15无法以float格式精确表示,因此如果不分析给定float格式中浮点值的二进制表示,则无法说明该值是如何舍入的;

2.25以float格式精确表示,舍入结果必须是可预测的;

我测试了一些以浮点格式精确表示的值的舍入,发现STR总是向上舍入为正值,向下舍入为负值。 STR不遵循“银行家的舍入”,例如:

  d := 2.25;
//  d:= roundto(d, -1);  banker's rounding is 2.2
  str(d:5:1, s); { -> s = '  2.3' }

  d:= 2.75;
//  d:= roundto(d, -1);  banker's rounding is 2.8
  str(d:5:1, s); { -> s = '  2.8' }

答案 1 :(得分:2)

我认为你看到的问题是,许多可以用十进制表示法精确表示的数字只能用二进制表示为重复小数(二进制?)。因此,可能2.15无法用双精确表示,2.14999999999234(或其他)是二进制表示最接近的。

由于数字的最接近二进制表示严格小于2.15,因此Str函数向下舍入而不是向上。

答案 2 :(得分:1)

看起来像浮点舍入错误。当您查看在Delphi中生成的汇编代码时,您可以看到为两个操作调用_Str2Ext,这会将Extended转换为字符串。所以为了做到这一点,它必须将你的Double转换为幕后的扩展:

Project1.dpr.16: str(d:5:1, s); { -> s = '  2.1' }
0040E666 DD45E8           fld qword ptr [ebp-$18]
0040E669 83C4F4           add esp,-$0c
0040E66C DB3C24           fstp tbyte ptr [esp]
0040E66F 9B               wait 

在从Double转换为Extended的某个地方,你会失去一点精确度,并且结果与你宣布相同数字(我们读取它们)的数字略有不同首先。这在浮点转换中非常常见。不确定你能做些什么。

答案 3 :(得分:0)

我对此进行了调查,发现添加0.000001会产生双打的正确结果。

答案 4 :(得分:0)

请注意,这里有两个方面。

首先,您的十进制文字值可能会舍入为二进制浮点数。这意味着汇编代码中的数字可能与您记下的数字略有不同。如果最近的机器编号略小,则可能看起来好像应该向上舍入的值被STR向下舍入。

其次,使用FPU状态字中配置的舍入来舍入生成的二进制浮点数,希望外部库未对其进行更改。