Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/RTL/Delphi/Math Unit    [ Add a report in this area ]  
Report #:  79687   Status: Open
RoundTo gives wrong results
Project:  Delphi Build #:  14.0.3593.25826
Version:    14.0 Submitted By:   John Herbster
Report Type:  Basic functionality failure Date Reported:  11/20/2009 9:56:10 AM
Severity:    Infrequently encountered problem Last Updated: 3/20/2012 2:24:39 AM
Platform:    All versions Internal Tracking #:   273982
Resolution: None (Resolution Comments) Resolved in Build: : None
Duplicate of:  None
Voting and Rating
Overall Rating: No Ratings Yet
0.00 out of 5
Total Votes: 31
Description
[JJS]
Even after much hand wringing, coding, and testing,  <g>
A little more testing shows that there are still problems with the Math.RoundTo routine in D2010.

The criterion for correct result that I use is, where D, N, and NDFD (number decimal fraction digits) are integer variables and X, Y, and Z are variables of identical floating point types (single, double, or extended) and where
  D := 10^NDFD;
  N > 0
  X := (N*10+5)/(D*10);
  Z := RoundTo(X,-NDFD);
and
  if N is even Y := N/D else Y := (N+1)/D;
then the following should be true
  Z = Y.

A lesser criterion (called "normalization") is that where Z
is the result of the above RoundTo and W is a variable from
the same type as Z and where
  W := round(Z*D)/D;
then the following should be true
  W = Z.  

The attached test program,  T_QC79687_0a, tests both criteria.

This is a program for testing results of the decimal rounding functions.   It was written to try to test any changes in the decimal fraction rounding function Math.RoundTo that may have been incorporated into Delphi versions beyond D7.  While I am not privy to the exact changes that have been made to the rounding function, it has be suggested that something like the RoundToEX_JOH_IA32_2 function (written by John O'Harrow as copied on 2009.01.24 from QualityCentral report #14394 filed by Dennis Christensen on 2005.07.14) may be the basis for changes to Math.RoundTo in later Delphi versions later than D7.

This program tests the following four functions each with single, double, and extended input and output parameters:
    Math.RoundTo
    RoundToEX_JOH_IA32_2
    RoundToEX_JH1_Pas2
    DecimalRounding_JH1.DecimalRound(Sgl,Dbl,Ext)

The DecimalRounding_JH1 was writen by John Herbster and is inclluded in the attachments.

At present, this program only tests the accuracy of the rounding results for inputs which are halfway between adjacent points in the range of possible outputs.

Doing just a 100 tests, here are examples of problems found:

  Testing RoundToEX_JOH_IA32_2(*,-2) with type extended input and output.
    ER RoundToEX_JOH_IA32_2(95/1000,-2) [NotNormalized]
      Inp=0.09499999999999999999891579782751449556599254719913005828857421875
      Out=0.09999999999999999999457898913757247782996273599565029144287109375
      NoR=0.1000000000000000000013552527156068805425093160010874271392822265625
      SBR=0.1000000000000000000013552527156068805425093160010874271392822265625
    ER RoundToEX_JOH_IA32_2(105/1000,-2) [NotNormalized]
      Inp=0.1049999999999999999970184440256648628064795047976076602935791015625
      Out=0.09999999999999999999457898913757247782996273599565029144287109375
      NoR=0.1000000000000000000013552527156068805425093160010874271392822265625
      SBR=0.1000000000000000000013552527156068805425093160010874271392822265625
    ER RoundToEX_JOH_IA32_2(295/1000,-2) [WrongWay]
      Inp=0.29499999999999999998807377610265945122591801919043064117431640625
      Out=0.28999999999999999999241058479260146896194783039391040802001953125
      SBR=0.3000000000000000000108420217248550443400745280086994171142578125
    Inp=Input; Out=Output; NoR=NormalizedOutput; SBR=CorrectBankersOutput
    Tested from 0/100 to 100/100.
    30 errors in 100 tests (29 NotNormalized, 1 WrongWay)

  Testing RoundToEX_JH1_Pas2(*,-2) with type extended input and output.
    ER RoundToEX_JH1_Pas2(295/1000,-2) [WrongWay]
      Inp=0.29499999999999999998807377610265945122591801919043064117431640625
      Out=0.28999999999999999999241058479260146896194783039391040802001953125
      SBR=0.3000000000000000000108420217248550443400745280086994171142578125
    Inp=Input; Out=Output; NoR=NormalizedOutput; SBR=CorrectBankersOutput
    Tested from 0/100 to 100/100.
    1 error in 100 tests (1 WrongWay)

One can argue about the WrongWay error; but I would like to see an excuse for returning any result x where x <> round(x*100)/100 assuming that two decimal fraction digits was asked for.

Note that the DecimalRounding(Ext,Dbl, and Sgl) functions all seem to always give the expected bankers rounding result *and* a optional parameter allows them to round according to about 9 different rules.  To use these as a replacement for RoundTo, I suggest that
(1) they should be checked by someone other than myself;
(2) consideration be given to letting them all overload the same, perhaps new, name; and
(3) other kinds of testing should also be done.

Please send me any comments, suggestions, or questions.

--JohnH, 2009.11.28, herb-sci1@sbcglobal.net, (h)281-531-4423, (c)291-782-8991.
Steps to Reproduce:
To replicate the problems, compile and execute the attached program, T_QC79687_0a.
Workarounds
None
Attachment
T_QC79687 091128b.zip
Comments

Ralf Stocker at 11/20/2009 12:17:19 PM -
Hi John,
you are the floating point guru...that means you have to say whats to do and what lines must be corrected. Otherwise, I fear, nothing happens...nobody has your floating point knowledge.

John Herbster at 11/20/2009 1:01:06 PM -
Ralf,  I will ponder the possibilities.  It is so easy to find problems in this area; but more dificult to make good recommendations.  There is however one easy suggestion that I might be able to work up.   Thanks for the advice.  Rgds, JohnH

John Herbster at 11/21/2009 10:02:22 AM -
Mr Takahashi,
Thanks for noticing this report.
I am preparing more information, test results, and a suggested improvement.
I will post here when it is ready.
Regards, JohnH

John Herbster at 11/28/2009 10:29:35 AM -
New test program, T_QC79687_0a, is uploaded to attachments.  
Please let me know of all problems and suggestions.
Thanks, John Herbster, herb-sci1@sbcglobal.net, (h)281-531-4423, (c)281-782-8991.

John Herbster at 11/27/2009 2:45:27 PM -
A comment to all readers:

I have gotten comments recently as well as in the distance past that the number of digits I show, like

xin=0.09499999999999999999891579782751449556599254719913005828857421875
xre=0.09999999999999999999457898913757247782996273599565029144287109375
xnr=0.1000000000000000000013552527156068805425093160010874271392822265625

looks excessive and that according to the help extended has 10-20 significand digits.  So why do I show 66 or 68 significand digits?

My purpose in using the extra digits to show the *exact* number represented by the contents of a floating binary point variable, so that we can compare its value against decimal fraction numbers like 0.1 and determine whether the above xre or xnr is closer to 0.1 and so that we can determine whether the floating point representations like from StrToFloat('0.05') are closer to 0.0 or closer to 0.1.

Regards, JohnH

Server Response from: ETNACODE01