Board index » delphi » Weird Trunc behaviour

Weird Trunc behaviour

Can everyone else reproduce this one? We've had it happen on at least two
different machines:

(drop a button and edit box on a new form, and attach this to the button's
OnClick event:)

procedure TForm1.Button1Click(Sender: TObject);
var
   s: string;
begin
   s := '38507.99';
   Edit1.Text := IntToStr(Trunc(100 * StrToFloat(s)));
end;

In our tests, Edit1.Text comes out to be '3850798' instead of the expected
'3850799'!!!

If this is reproducable somewhere other than here, I'll report it to borland.

Mab

|~\  /~| /~~| |~|   The .sig wears a ring of polymorph! --More--
|  \/  |/ / |_| |__ The .login hits! The .cshrc bites!
|      ' /| |_| | / ____________________________________________
| |\/|  /\  | |  /  Official member of STI:
| |  |_/  \_| | /       The Search for Terrestrial Intelligence!
-\|-----------|/------------------------------------------------
=================== http://members.dingoblue.net.au/~mabster ===

 

Re:Weird Trunc behaviour


To follow up on this: Try the following code:

procedure TForm1.Button1Click(Sender: TObject);
var
   s1, s2, s3: string;
begin
   s1 := '385079.9';
   s2 := '38507.99';
   s3 := '3850.799';
   Edit1.Text := IntToStr(Trunc(10*StrToFloat(s1)));
   Edit2.Text := IntToStr(Trunc(100*StrToFloat(s2)));
   Edit3.Text := IntToStr(Trunc(1000*StrToFloat(s3)));
end;

I get the correct answer (3850799) in Edit1 and Edit3, but an incorrect one
(3850798) in Edit2!!!

Mab

In article <eILR4.18$UC.1...@vic.nntp.telstra.net>, mhamil...@bunge.com.au

Quote
(Mab) wrote:
>Can everyone else reproduce this one? We've had it happen on at least two
>different machines:

>(drop a button and edit box on a new form, and attach this to the button's
>OnClick event:)

>procedure TForm1.Button1Click(Sender: TObject);
>var
>   s: string;
>begin
>   s := '38507.99';
>   Edit1.Text := IntToStr(Trunc(100 * StrToFloat(s)));
>end;

>In our tests, Edit1.Text comes out to be '3850798' instead of the expected
>'3850799'!!!

>If this is reproducable somewhere other than here, I'll report it to borland.

>Mab

>|~\  /~| /~~| |~|   The .sig wears a ring of polymorph! --More--
>|  \/  |/ / |_| |__ The .login hits! The .cshrc bites!
>|      ' /| |_| | / ____________________________________________
>| |\/|  /\  | |  /  Official member of STI:
>| |  |_/  \_| | /       The Search for Terrestrial Intelligence!
>-\|-----------|/------------------------------------------------
>=================== http://members.dingoblue.net.au/~mabster ===

|~\  /~| /~~| |~|   The .sig wears a ring of polymorph! --More--
|  \/  |/ / |_| |__ The .login hits! The .cshrc bites!
|      ' /| |_| | / ____________________________________________
| |\/|  /\  | |  /  Official member of STI:
| |  |_/  \_| | /       The Search for Terrestrial Intelligence!
-\|-----------|/------------------------------------------------
=================== http://members.dingoblue.net.au/~mabster ===

Re:Weird Trunc behaviour


Probably got something to do with the way this floating point number is
stored in a computer (ie. incompatible with base2).

If you don't have a problem with some numbers rounding up try using
Round instead of Trunc.

In article <UQLR4.22$UC.1...@vic.nntp.telstra.net>,
  mhamil...@bunge.com.au (Mab) wrote:

Quote
> To follow up on this: Try the following code:

> procedure TForm1.Button1Click(Sender: TObject);
> var
>    s1, s2, s3: string;
> begin
>    s1 := '385079.9';
>    s2 := '38507.99';
>    s3 := '3850.799';
>    Edit1.Text := IntToStr(Trunc(10*StrToFloat(s1)));
>    Edit2.Text := IntToStr(Trunc(100*StrToFloat(s2)));
>    Edit3.Text := IntToStr(Trunc(1000*StrToFloat(s3)));
> end;

> I get the correct answer (3850799) in Edit1 and Edit3, but an
incorrect one
> (3850798) in Edit2!!!

> Mab

> In article <eILR4.18$UC.1...@vic.nntp.telstra.net>,

mhamil...@bunge.com.au

Quote
> (Mab) wrote:
> >Can everyone else reproduce this one? We've had it happen on at
least two
> >different machines:

Sent via Deja.com http://www.deja.com/
Before you buy.

Re:Weird Trunc behaviour


Quote
In article <8f8cgm$8b...@nnrp1.deja.com>, digitalprosper...@my-deja.com wrote:
>Probably got something to do with the way this floating point number is
>stored in a computer (ie. incompatible with base2).

>If you don't have a problem with some numbers rounding up try using
>Round instead of Trunc.

Yeah, that's exactly what I've done. Were you able to reproduce it? I think it
should be reported as a bug.

Mab

Quote
>In article <UQLR4.22$UC.1...@vic.nntp.telstra.net>,
>  mhamil...@bunge.com.au (Mab) wrote:
>> To follow up on this: Try the following code:

>> procedure TForm1.Button1Click(Sender: TObject);
>> var
>>    s1, s2, s3: string;
>> begin
>>    s1 := '385079.9';
>>    s2 := '38507.99';
>>    s3 := '3850.799';
>>    Edit1.Text := IntToStr(Trunc(10*StrToFloat(s1)));
>>    Edit2.Text := IntToStr(Trunc(100*StrToFloat(s2)));
>>    Edit3.Text := IntToStr(Trunc(1000*StrToFloat(s3)));
>> end;

>> I get the correct answer (3850799) in Edit1 and Edit3, but an
>incorrect one
>> (3850798) in Edit2!!!

>> Mab

>> In article <eILR4.18$UC.1...@vic.nntp.telstra.net>,
>mhamil...@bunge.com.au
>> (Mab) wrote:
>> >Can everyone else reproduce this one? We've had it happen on at
>least two
>> >different machines:

>Sent via Deja.com http://www.deja.com/
>Before you buy.

|~\  /~| /~~| |~|   The .sig wears a ring of polymorph! --More--
|  \/  |/ / |_| |__ The .login hits! The .cshrc bites!
|      ' /| |_| | / ____________________________________________
| |\/|  /\  | |  /  mailto:mabs...@dingoblue.net.au
| |  |_/  \_| | /   http://members.dingoblue.net.au/~mabster
=\|===========|/================================================

Re:Weird Trunc behaviour


Quote
On Tue, 09 May 2000 02:37:29 GMT, mhamil...@bunge.com.au (Mab) wrote:
>Can everyone else reproduce this one? We've had it happen on at least two
>different machines:

>(drop a button and edit box on a new form, and attach this to the button's
>OnClick event:)

>procedure TForm1.Button1Click(Sender: TObject);
>var
>   s: string;
>begin
>   s := '38507.99';
>   Edit1.Text := IntToStr(Trunc(100 * StrToFloat(s)));
>end;

>In our tests, Edit1.Text comes out to be '3850798' instead of the expected
>'3850799'!!!

Why would you expect 3850799?  The number you're truncating is just a
little bit less or a little bit more than 3850799, it's definitely not
equal to it.  I wouldn't be able to predict whether you'd go up or
down in a case like this without a lot of work.

If you want to store 38507.99 exactly, you shouldn't be using Extended
(which is what StrToFloat gives you), you should be using the Currency
type.

If you want 3850799+/- to round to 3850799, you should use Round, not
Trunc.

Duncan Murdoch

Re:Weird Trunc behaviour


The problem lies in the fact that both StrToFloat and Trunc use floating
point values of type Extended. Extended type values are not guaranteed to be
100% accurate. You should use Double type instead.

procedure TForm1.Button1Click(Sender: TObject);
var
  s: String;
  f: Double;
begin
  s := '38507.99';
  f := 100 * StrToFloat(s);
  Edit1.Text := IntToStr(Trunc(f));
end;

"Mab" <mhamil...@bunge.com.au> schreef in bericht
news:eILR4.18$UC.1842@vic.nntp.telstra.net...

Quote
> Can everyone else reproduce this one? We've had it happen on at least two
> different machines:

> (drop a button and edit box on a new form, and attach this to the button's
> OnClick event:)

> procedure TForm1.Button1Click(Sender: TObject);
> var
>    s: string;
> begin
>    s := '38507.99';
>    Edit1.Text := IntToStr(Trunc(100 * StrToFloat(s)));
> end;

> In our tests, Edit1.Text comes out to be '3850798' instead of the expected
> '3850799'!!!

> If this is reproducable somewhere other than here, I'll report it to
borland.

> Mab

> |~\  /~| /~~| |~|   The .sig wears a ring of polymorph! --More--
> |  \/  |/ / |_| |__ The .login hits! The .cshrc bites!
> |      ' /| |_| | / ____________________________________________
> | |\/|  /\  | |  /  Official member of STI:
> | |  |_/  \_| | /       The Search for Terrestrial Intelligence!
> -\|-----------|/------------------------------------------------
> =================== http://members.dingoblue.net.au/~mabster ===

Re:Weird Trunc behaviour


Quote
"Mab" <mhamil...@bunge.com.au> wrote in message

news:eILR4.18$UC.1842@vic.nntp.telstra.net...

Quote
>    s := '38507.99';
>    Edit1.Text := IntToStr(Trunc(100 * StrToFloat(s)));
> end;

> In our tests, Edit1.Text comes out to be '3850798' instead of the expected
> '3850799'!!!

I vote that this is a bug.

You would need to study the assembly code that this expression creates
to find out exactly what's going on.  At first I thought that the problem
might
be related to being on the "edge" of the limits of single precision
arithmetic,
but the following works with an "x" variable:

procedure TForm1.Button1Click(Sender: TObject);
var
   x:  Single;
   s:  string;
begin
   s := '38507.99';
   x := 100.0*StrToFloat(s);
   Edit1.Text := IntToStr(Trunc(x)) +                       // 3850799
                 ' ' +
                 IntToStr(Trunc(100.0*StrToFloat(s)));      // 3850798
end;

--
efg

Earl F. Glynn     E-mail:  EarlGl...@att.net
Overland Park, KS  USA

efg's Computer Lab:  http://www.efg2.com/Lab

Re:Weird Trunc behaviour


Quote
On Tue, 09 May 2000 02:37:29 GMT, mhamil...@bunge.com.au (Mab) wrote:
>Can everyone else reproduce this one? We've had it happen on at least two
>different machines:

>(drop a button and edit box on a new form, and attach this to the button's
>OnClick event:)

>procedure TForm1.Button1Click(Sender: TObject);
>var
>   s: string;
>begin
>   s := '38507.99';
>   Edit1.Text := IntToStr(Trunc(100 * StrToFloat(s)));
>end;

>In our tests, Edit1.Text comes out to be '3850798' instead of the expected
>'3850799'!!!

You are under the delusion that floating point values are stored
_exactly_ in the computer.

This is wrong.

The bit pattern composing the floating point value 38507.99 probably
means something like 38507.98828125 and when truncating this, you get
the observed result.

The above value (38507.98828125) is what 38507.99 stored in a 'single'
variable shows when displayed with 18 decimals:

var
  s: single; {double, extended, currency}
begin
  s := 38507.99;
  Edit1.Text := Format('%30.18f', [s]);
  Edit2.Text := Format('%30.18f', [Trunc(s*100)/100]);
end;

Using 'double' instead, we get 38507.989999999998 and still a problem:

Going up to the 'extended' type seems to help, it gives the value:
38507.990000000000000000 in Edit1, but there's still a problem when
truncating.

Finally, using 'currency' you seem to get the correct behaviour. Both
Edit1 and Edit2 are 'correct'. The 'currency' data type is in fact a
'fixed point integer', and are _exact_ up to four decimals.

------------------------------------
Anders Isaksson, Sweden

BlockCAD: http://user.tninet.se/~hbh828t/proglego.htm
Gallery:  http://user.tninet.se/~hbh828t/gallery.htm

Re:Weird Trunc behaviour


Quote
"Mab" <mhamil...@bunge.com.au> wrote in message

news:eILR4.18$UC.1842@vic.nntp.telstra.net...
Quote
> Can everyone else reproduce this one? We've had it happen on at least two
> different machines:

> (drop a button and edit box on a new form, and attach this to the button's
> OnClick event:)

> procedure TForm1.Button1Click(Sender: TObject);
> var
>    s: string;
> begin
>    s := '38507.99';
>    Edit1.Text := IntToStr(Trunc(100 * StrToFloat(s)));
> end;

> In our tests, Edit1.Text comes out to be '3850798' instead of the expected
> '3850799'!!!

> If this is reproducable somewhere other than here, I'll report it to

borland.

When I first saw this post I immediately assumed that it was simply a
rounding error induced problem. Indeed
    trunc (100 * StrToFloat ('38507.99'))
produces 3850798 where as
    round (100 * StrToFloat ('38507.99'))
produces 3850799. However
    s := '38507.99';
    f := 100 * StrToFloat (s);
    edit1.text := format ('%e', [f]);
displays 3.85079900000000E+006, while
    f := trunc (100 * StrToFloat (s));
    edit2.text := format ('%e', [f]);
displays 3.85079800000000E+006. These results are the same for f as real,
single, double, and extended. I also wondered if the '100 *' was introduce a
REAL intermediate and replaced it with an extended variable.

I still think that the problem is rounding related, but if it is I don't
really understand why FORMAT reports the numbers it does. I would have
expected it to show an approximation of 3850799, e.g. something like
3.850798686887967+006.

- Show quoted text -

Quote

> Mab

> |~\  /~| /~~| |~|   The .sig wears a ring of polymorph! --More--
> |  \/  |/ / |_| |__ The .login hits! The .cshrc bites!
> |      ' /| |_| | / ____________________________________________
> | |\/|  /\  | |  /  Official member of STI:
> | |  |_/  \_| | /       The Search for Terrestrial Intelligence!
> -\|-----------|/------------------------------------------------
> =================== http://members.dingoblue.net.au/~mabster ===

Re:Weird Trunc behaviour


On Tue, 9 May 2000 11:23:00 -0400, "Bruce Roberts"

Quote
<no.junk.please....@attcanada.net> wrote:
>When I first saw this post I immediately assumed that it was simply a
>rounding error induced problem... However
>    s := '38507.99';
>    f := 100 * StrToFloat (s);
>    edit1.text := format ('%e', [f]);
>displays 3.85079900000000E+006, while
>    f := trunc (100 * StrToFloat (s));
>    edit2.text := format ('%e', [f]);
>displays 3.85079800000000E+006. These results are the same for f as real,
>single, double, and extended. I also wondered if the '100 *' was introduce a
>REAL intermediate and replaced it with an extended variable.

It's a rounding problem.  The value 38507.99 can't be stored in real,
single, double or extended, so when you multiply by 100, you don't get
3850799.  Take a look at the bit pattern in the floating point unit
and you'll see exactly what gets stored instead.

Duncan Murdoch

Re:Weird Trunc behaviour


The best way to understand this problem is to consider the familiar
number "1/3," which is a quantity that cannot be precisely represented
in Base-10.  It comes out as "almost 0.333333333...." (and the 3's go on
forever, for this number is never quite EXACTLY one-third).

The quantity "one-third" could be precisely represented in base-3, even
though (sigh..) (go figure...) the quantity "one-tenth" could not.

Anyhow, the problem is that "one tenth" can't be quite precisely
represented in base two, the native language of the so-called "float
decimal" (floating-point) format.  There is a small amount of error,
which accumulates as the numbers are processed and gradually becomes big
enough to be significant.  Or more precisely, as "a loss of significant
digits" in your answer.

The only way to -precisely- store a number like "38507.99" is to use a
different format called Binary-Coded Decimal, or BCD.  In this format,
each decimal digit occupies 4 bits (which, if eight bits is a "byte,"
obviously must be a "nybble").  The number occupies an arbitrary number
of bytes.  The sign of the number is represented by an additional
nybble, on the left or the right hand side.  Our number might be
represented by something like:  "$C0 00 38 50 79 90"  

Well, that's not the ONLY precise way.  Another way would be to multiply
the number by a fixed constant, or "scale," so that it becomes an
integer, say:  +385,079,900.  All arithmetic is done in integer mode
using equally-scaled numbers.  This example has precisely 4 digits
represented to the right of the decimal, and the rightmost two of those
digits should be considered garbage.  But a "dollars and cents" quantity
(2 digits) would be represented here in a consistent way -- and if the
rightmost two of the four digits are thrown away, the "rounding" effect
that remains in the leftmost two digits (the cents) will be consistent.
This is how systems like Microsoft Access implement their "currency"
data type.  (But it's not how Delphi does it.)

Quote
>Duncan Murdoch wrote:

> On Tue, 9 May 2000 11:23:00 -0400, "Bruce Roberts"
> <no.junk.please....@attcanada.net> wrote:

> >When I first saw this post I immediately assumed that it was simply a
> >rounding error induced problem... However
> >    s := '38507.99';
> >    f := 100 * StrToFloat (s);
> >    edit1.text := format ('%e', [f]);
> >displays 3.85079900000000E+006, while
> >    f := trunc (100 * StrToFloat (s));
> >    edit2.text := format ('%e', [f]);
> >displays 3.85079800000000E+006. These results are the same for f as real,
> >single, double, and extended. I also wondered if the '100 *' was introduce a
> >REAL intermediate and replaced it with an extended variable.

> It's a rounding problem.  The value 38507.99 can't be stored in real,
> single, double or extended, so when you multiply by 100, you don't get
> 3850799.  Take a look at the bit pattern in the floating point unit
> and you'll see exactly what gets stored instead.

> Duncan Murdoch

--
------------------------------------------------------------------
Sundial Services :: Scottsdale, AZ (USA) :: (480) 946-8259
mailto:i...@sundialservices.com  (PGP public key available.)

- Show quoted text -

Quote
> Fast(!), automatic table-repair with two clicks of the mouse!
> ChimneySweep(R):  "Click click, it's fixed!" {tm}
> http://www.sundialservices.com/products/chimneysweep

Re:Weird Trunc behaviour


Im Artikel <UQLR4.22$UC.1...@vic.nntp.telstra.net>, mhamil...@bunge.com.au
(Mab) schreibt:

Quote
>I get the correct answer (3850799) in Edit1 and Edit3, but an incorrect one
>(3850798) in Edit2!!!

All the answers are correct, according to computer logic. Incorrect is your
assumption, that floating point numbers are stored as decimal digits, exactly
as typed in with decimal digits.

The Currency data type comes close to your opinion, it only has less
significant digits than Extended. All other floating point data types are
stored differently, and are only "translated" into decimal digits during input
and output. Thus differences are inevitable in such translations, like if you'd
input text in English, store it in Chinese, and translate it back into English
again for output.

DoDi

Go to page: [1] [2]

Other Threads