Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Delphi 7. Error in format function result


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 9 - Last Post: Aug 10, 2016 8:11 AM Last Post By: Carlos Saez
Carlos Saez

Posts: 20
Registered: 12/26/06
Delphi 7. Error in format function result  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 6, 2016 3:11 PM
I'm not sure this is the proper forum to post this question. If not, please advice.

In Delphi7 I have a problem with rounding using the format function in a sentence as the one below. With some values the result is rounded up and with others it is truncated. But in all cases it should have been rounded up.

astring:=Format('%7.2f',[adouble])

Some examples where format seems to truncate the result:

adouble: 2.135 astring: 2.13
adouble: 1.015 astring: 1.01
adouble: 4.895 astring: 4.89

Some examples where format rounds up the result:

adouble: 1.227 astring: 1.23
adouble: 0.525 astring: 0.53
adouble: 4.495 astring: 4.50

Are you aware of this problem?. Is there any advice you can offer me?.

Thanks,
Carlos
John Treder

Posts: 349
Registered: 8/2/02
Re: Delphi 7. Error in format function result  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 6, 2016 8:09 PM   in response to: Carlos Saez in response to: Carlos Saez
Carlos Saez wrote:

I'm not sure this is the proper forum to post this question. If not, please advice.

In Delphi7 I have a problem with rounding using the format function in a sentence as the one below. With some values the result is rounded up and with others it is truncated. But in all cases it should have been rounded up.

astring:=Format('%7.2f',[adouble])

Some examples where format seems to truncate the result:

adouble: 2.135 astring: 2.13
adouble: 1.015 astring: 1.01
adouble: 4.895 astring: 4.89

Some examples where format rounds up the result:

adouble: 1.227 astring: 1.23
adouble: 0.525 astring: 0.53
adouble: 4.495 astring: 4.50

Are you aware of this problem?. Is there any advice you can offer me?.

Thanks,
Carlos

If you set the douuble value by entering the string "2.135" into the StrToFloat function, and then, without rounding, look at the result of the FloatToStr function, you will see that the stored value of the double is not precicely 2.1350000000000. Depending on the exact string you enter, it's quite likely to be a bit larger or smaller.
Then,when you call Format, the Format function (effectively) calls Round, which performs a "banker's rounding" on the value.
What's surprising is that you get the answer you expect any more than half the time.
Look up the topics "banker's rounding" and "floating point precision" on Google or your favorite search engine. I have books dating from the 1970s that deal with thiis issue. It isn't new, it isn't a bug, it's the way binary computers work.

--
Tred
Roy Lambert

Posts: 1,063
Registered: 8/7/01
Re: Delphi 7. Error in format function result  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 6, 2016 11:36 PM   in response to: Carlos Saez in response to: Carlos Saez
Carlos

Probably the best approach is to do it manually eg something like

100* TRUNC((Value * 100) + 0.5)

Roy Lambert

Carlos Saez

Posts: 20
Registered: 12/26/06
Re: Delphi 7. Error in format function result  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 7, 2016 3:03 AM   in response to: Roy Lambert in response to: Roy Lambert
Roy Lambert wrote:
Carlos

Probably the best approach is to do it manually eg something like

100* TRUNC((Value * 100) + 0.5)

Roy Lambert

The sentences:

double1:=2.135;
double2:= 100* TRUNC((double1 * 100) + 0.5);

assign 2.13 to double2, although the sentence:

double2:= 100* TRUNC((2.135 * 100) + 0.5);

assigns 2.14 to double2, so the result seems to depend on the source of the value.

In my actual case, the source can be the result form a SQL sentence or an entry from the user.

Format function seems to work fine in most cases. I've only detected this behaviour in 5/2500 cases, comparing results between two systems, one of them developped in Delphi, using format function.

Any additional advice will be appreciated.

Thanks,
Carlos

Roy Lambert

Posts: 1,063
Registered: 8/7/01
Re: Delphi 7. Error in format function result  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 7, 2016 4:51 AM   in response to: Carlos Saez in response to: Carlos Saez
Carlos

That intrigued me. So I did some messing about.

This code

procedure TForm1.Button1Click(Sender: TObject);
var
double1: double;
double2: double;
begin
double1 := 2.135;
showmessage(floattostr(double1));
double2 := (double1 * 100) + 0.5;
showmessage(floattostr(double2));
double2 := TRUNC((double1 * 100) + 0.5);
showmessage(floattostr(double2));
double2 := TRUNC((double1 * 100) + 0.5) / 100;
showmessage(floattostr(double2));
double2 := TRUNC((2.135 * 100) + 0.5) / 100;
showmessage(floattostr(double2));
end;

fails

But this

procedure TForm1.Button1Click(Sender: TObject);
var
double1: extended;
double2: extended;
begin
double1 := 2.135;
showmessage(floattostr(double1));
double2 := (double1 * 100) + 0.5;
showmessage(floattostr(double2));
double2 := TRUNC((double1 * 100) + 0.5);
showmessage(floattostr(double2));
double2 := TRUNC((double1 * 100) + 0.5) / 100;
showmessage(floattostr(double2));
double2 := TRUNC((2.135 * 100) + 0.5) / 100;
showmessage(floattostr(double2));
end;

works.

Roy Lambert

Carlos Saez

Posts: 20
Registered: 12/26/06
Re: Delphi 7. Error in format function result  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 7, 2016 9:16 AM   in response to: Roy Lambert in response to: Roy Lambert
Roy Lambert wrote:
Carlos

That intrigued me. So I did some messing about.

This code

procedure TForm1.Button1Click(Sender: TObject);
var
double1: double;
double2: double;
begin
double1 := 2.135;
showmessage(floattostr(double1));
double2 := (double1 * 100) + 0.5;
showmessage(floattostr(double2));
double2 := TRUNC((double1 * 100) + 0.5);
showmessage(floattostr(double2));
double2 := TRUNC((double1 * 100) + 0.5) / 100;
showmessage(floattostr(double2));
double2 := TRUNC((2.135 * 100) + 0.5) / 100;
showmessage(floattostr(double2));
end;

fails

But this

procedure TForm1.Button1Click(Sender: TObject);
var
double1: extended;
double2: extended;
begin
double1 := 2.135;
showmessage(floattostr(double1));
double2 := (double1 * 100) + 0.5;
showmessage(floattostr(double2));
double2 := TRUNC((double1 * 100) + 0.5);
showmessage(floattostr(double2));
double2 := TRUNC((double1 * 100) + 0.5) / 100;
showmessage(floattostr(double2));
double2 := TRUNC((2.135 * 100) + 0.5) / 100;
showmessage(floattostr(double2));
end;

works.

Roy Lambert


That was what I wanted to try next, that is, other real types, but you got first.

Format, of course, also works now.

Thank you for your support
Carlos
Carlos Saez

Posts: 20
Registered: 12/26/06
Re: Delphi 7. Error in format function result  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 10, 2016 8:10 AM   in response to: Roy Lambert in response to: Roy Lambert
FYI. Finnally I've ended up with Currency type. That's what I've learned when dealing with money operations.

Extended also produces bad result. Even format produces bad results with Currency, so I apply the rounding method you adviced me and then floattostr.

Edited by: Carlos Saez on Aug 10, 2016 8:11 AM
Jim Fleming

Posts: 113
Registered: 2/12/00
Re: Delphi 7. Error in format function result  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 7, 2016 7:55 AM   in response to: Carlos Saez in response to: Carlos Saez
It would appear to be a "bankers rounding" problem, so pay attention to what
John Treder told you.

There is a version of ROUND that does not use banker's rounding, but I
cant't search the Delphi help on this system as it doesn't have Delphi
installed. Check the Delphi Wiki and you will find it, or someone else will
tell us directly what its name is.

Looked it up myself:
System.Round
From RAD Studio API Documentation

Returns the value of X rounded to the integer number.
In Delphi, the Round function rounds a real-type value to an integer-type
value.

X is a real-type expression. Round returns an Int64 value that is the value
of X rounded to an integer number. The default Rounding mode is rmNearest.
If X is exactly halfway between two integer numbers, the result is always
the even number. This method of rounding is often called "Banker's
rounding."

If the rounded value of X is not within the Int64 range, a run-time error is
generated that can be handled using the EInvalidOp exception.

Note: The behavior of Round can be affected by the Set8087CW procedure or
System.Math.SetRoundMode function.
See Also
a.. System.Int
b.. System.Trunc
c.. System.Set8087CW
d.. System.Math.SetRoundMode
e.. System.Math.RoundTo
f.. System.Math.SimpleRoundTo
g.. Delphi Intrinsic Routines
h.. Mathematical Routines
i.. About Floating-Point Arithmetic
j.. Floating point precision control (Delphi for x64) ({$EXCESSPRECISION})
Code Examples
a.. SystemRound (Delphi)
b.. SetRoundMode (Delphi)
c.. SystemCos (Delphi)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Note the following comment elsewhere in the help:
SimpleRoundTo is the traditional "Round off" that was learned at
school.

--
JF

Carlos Saez

Posts: 20
Registered: 12/26/06
Re: Delphi 7. Error in format function result  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 7, 2016 9:29 AM   in response to: Jim Fleming in response to: Jim Fleming
Jim Fleming wrote:
It would appear to be a "bankers rounding" problem, so pay attention to what
John Treder told you.

There is a version of ROUND that does not use banker's rounding, but I
cant't search the Delphi help on this system as it doesn't have Delphi
installed. Check the Delphi Wiki and you will find it, or someone else will
tell us directly what its name is.

Looked it up myself:
System.Round
From RAD Studio API Documentation

Returns the value of X rounded to the integer number.
In Delphi, the Round function rounds a real-type value to an integer-type
value.

X is a real-type expression. Round returns an Int64 value that is the value
of X rounded to an integer number. The default Rounding mode is rmNearest.
If X is exactly halfway between two integer numbers, the result is always
the even number. This method of rounding is often called "Banker's
rounding."

If the rounded value of X is not within the Int64 range, a run-time error is
generated that can be handled using the EInvalidOp exception.

Note: The behavior of Round can be affected by the Set8087CW procedure or
System.Math.SetRoundMode function.
See Also
a.. System.Int
b.. System.Trunc
c.. System.Set8087CW
d.. System.Math.SetRoundMode
e.. System.Math.RoundTo
f.. System.Math.SimpleRoundTo
g.. Delphi Intrinsic Routines
h.. Mathematical Routines
i.. About Floating-Point Arithmetic
j.. Floating point precision control (Delphi for x64) ({$EXCESSPRECISION})
Code Examples
a.. SystemRound (Delphi)
b.. SetRoundMode (Delphi)
c.. SystemCos (Delphi)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Note the following comment elsewhere in the help:
SimpleRoundTo is the traditional "Round off" that was learned at
school.

--
JF


Thank you for your information.

Although my original post was not related to rounding methods but format "malfunction", the rounding method I need to use is IEEE 754 "Round to nearest, ties away from zero".

My issue has been fixed, thanks to Roy Lambert, using extended instead of double.

Carlos
Jim Fleming

Posts: 113
Registered: 2/12/00
Re: Delphi 7. Error in format function result  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 7, 2016 11:58 AM   in response to: Carlos Saez in response to: Carlos Saez
Although my original post was not related to rounding methods but format
"malfunction", the rounding method I need to use is IEEE 754 "Round to
nearest, ties away from zero".

Check out System.Math.SimpleRoundTo (<your variable>, 0) -- it may be what
you need for the rounding that is not banker's rounding.

--
JF
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02