2010-02-25 76 views
4

两个,Borland公司帕斯卡尔7和Delphi 2007年已经拿到了程序STR这需要一个号码,长度和精度,并把它转换成一个像这样的字符串:如何在Delphi/Borland的帕斯卡尔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' } 

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

德尔福2007年显然总是独立于数据类型四舍五入。

是否有人知道在BP中舍入是如何完成双值的?

我想知道,因为我正在移植一些使用双打到Delphi 2007的Borland Pascal代码,当我比较输出时,我得到了STR过程中四舍五入造成的不一致。这些对结果无关紧要,但却很难找出重要的差异。

+0

为什么试图弄清楚它是如何工作的,当它可以改变所有的Str()调用到FloatToStr调用时出现问题? – 2010-02-25 19:03:20

+0

他无法更改BP代码。只有将Delphi代码更改为FloatToStr才会向他购买任何东西。 – 2010-02-26 09:53:33

+0

请注意,在传递给Str()之前,double可能会转换为扩展。这意味着扩展后的2.15和2.15之后的扩展可以有不同的值,因此可能会有所不同。否则,接受的答案是正确的:2.25可以精确地表示(.25是2^-2),通过扩展和双精度来表示,而2.15不能。 – 2016-06-06 15:41:57

回答

4

d = 2.15和d = 2的情况。25是不同的:

2.15不能在浮点格式精确表示,因此它不可能说该值是如何,而不需要分析在给定的浮点格式的浮点值的二进制表示圆形;

2.25在浮点格式精确表示,和舍入结果必须是可预测的;

我已经测试其上为浮点格式精确表示,发现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' } 
+0

好观察!将这与我的答案结合起来,你对发生了什么有了一个很好的想法。 – 2010-02-25 18:21:44

2

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

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

+0

我认为你是对的。但是,如何才能找出给定双重价值的情况?我会试验一下... – dummzeuch 2010-02-25 15:50:47

+0

+1我认为你是对的。使用源卢克。 – 2010-02-25 15:54:31

+0

@dummzeuch - 如果你想要确切的数字,你不应该使用双打,而是缩放整数。请看http://rvelthuis.de/articles/articles-floats.html,以获取有关该主题的非常好的解释。 – 2010-02-25 15:56:55

0

我调查了这一点,发现加0.000001会产生双打的正确结果。

+0

我无法更改BP源代码,我只是将其作为参考。我已经得到的测试数据已经使用编译好的BP程序进行处理。我想知道它是如何工作的,所以我可以(暂时)在Delphi中重现此行为。 – dummzeuch 2010-02-25 15:48:35

1

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

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 

而且在某个地方,从双到扩展的转换,你失去的精确一点点,并与结束了与如果您宣布相同数字(因为我们阅读它们)作为扩展名开头,数字略有不同。这在浮点转换中很常见。不知道你有什么可以做的。

0

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

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

其次,使用在FPU状态字中配置的四舍五入来舍入得到的二进制浮点数,该舍入有希望未被外部库改变。