How is the Delphi / Borland Pascal STR Processing Procedure

Both Borland Pascal 7 and Delphi 2007 received the STR procedure, which takes a number, length, and precision, and converts it to a string as follows:

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

Everything is fine if rounding is not ambiguous, but if it is not (0.5 β†’ up or down?), A problem arises: it seems to depend on the data type of the floating point in BP, but apparently in 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' } 

I was not able to find any rule about how rounded doubles, while obviously expanded are always rounded.

Delphi 2007 seems to always be rounded regardless of the data type.

Does anyone know how rounding is done in BP for double values?

I want to know, because I'm in the middle of migrating some Borland Pascal code that uses duplicates for Delphi 2007, and when I compare the outputs, I get inconsistencies resulting from rounding in the STR procedure. This is not particularly significant for the result, but it makes it difficult to identify important differences.

+4
source share
5 answers

The cases of d = 2.15 and d = 2.25 are different:

2.15 it is impossible to accurately represent it in the float format, and therefore it is impossible to say how the value is rounded without analyzing the binary representation of the float value in the given float format;

2.25 is accurately displayed in float format, and the rounding result should be predictable;

I checked rounding for some values ​​that are accurately represented in float format and found that STR always rounds values ​​for positive values ​​and down for negative values. STR should not be rounded off by bankers, for example:

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

I think the problem you see is that many numbers that can be represented exactly in decimal notation can only be represented as repeating decimal places (binimal?) In binary format. Thus, it may be that 2.15 cannot be exactly represented as double, and that 2.14999999999234 (or something) is the closest you can get with binary representation.

Since the nearest binary representation of a number is strictly less than 2.15, the Str function is rounded down, not up.

+2
source

Looks like a floating point rounding error. When you look at the assembly code generated in Delphi, you can see that _Str2Ext is called for both operations, which converts Extended to a string. Therefore, for this you need to convert Double to Extended behind the scenes:

 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 

And somewhere in the conversion from Double to Extended, you lose a bit of precision and end up with a slightly different number than if you declared the same number (as we read them) as Extended Start with. This is quite common in floating point conversions. Not sure if you can do something about this.

+1
source

I examined this and found that adding 0.000001 would produce the correct result for doubling.

0
source

Please note that there are two aspects to this.

First, your decimal value is literally rounded to a binary floating point number. This means that the number entered in the assembly code may be slightly different from the number you wrote down. If the nearest engine number is slightly smaller, it may look as if the values ​​to be rounded are rounded to STR.

Secondly, the final floating-point binary number is rounded using the rounding configured in the FPU keyword, which I hope has not been changed by external libraries.

0
source

Source: https://habr.com/ru/post/1302379/


All Articles