Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Trunc to 2 decimals

5,832 views
Skip to first unread message

Daniel / Tecnobyte

unread,
Jun 15, 2001, 12:32:37 PM6/15/01
to
I made the routines below to truncate values double for 2 decimals.

function TruncWithInt(const X: Double): Double;
begin
Result := Int(X * 100) / 100;
end;

function TruncWithTrunc(const X: Double): Double;
begin
Result := Trunc(X * 100) / 100;
end;

function TruncWithStr(const X: Double): Double;
var
S: string;
P: integer;
begin
S := FloatToStr(X);
P := Pos(DecimalSeparator, S);
if P > 0 then
S := Copy(S, 1, P-1) + DecimalSeparator + Copy(S, P+1, 2);
Result := StrToFloat(S);
end;

In agreement with thousands of tests that I did, TruncWithStr just works as
expected. But TruncWithStr is also the slowest.

Which alternative does work like TruncWithStr, but what is fast?

Daniel

tecn...@ulbrajp.com.br


John Herbster

unread,
Jun 15, 2001, 11:47:17 AM6/15/01
to
Daniel / Tecnobyte <tecn...@ulbrajp.com.br> wrote
> ... TruncWithStr just works as expected.

Can you tell us what rounding you would like to see?

There are many kinds, such as
floor, ceil, bankers, trunc, etc. and
the type that you see with round(x*100)/100).


Daniel / Tecnobyte

unread,
Jun 15, 2001, 12:55:51 PM6/15/01
to
I want to catch the number with 2 digits after the decimal point, despising
the others.

Example:

1.45678 ===>>> 1.45
1.55555 ===>>> 1.55
2.55555 ===>>> 2.55
2.45678 ===>>> 2.45


John Herbster <jo...@petronworld.com> escreveu nas notícias de
mensagem:3b2a2e06$1_2@dnews...

John Herbster

unread,
Jun 15, 2001, 12:06:26 PM6/15/01
to
Daniel / Tecnobyte <tecn...@ulbrajp.com.br> wrote
> I want to catch the number with 2 digits after the decimal point,
despising
> the others.
>
> Example:
>
> 1.45678 ===>>> 1.45
> 1.55555 ===>>> 1.55
> 2.55555 ===>>> 2.55
> 2.45678 ===>>> 2.45

Daniel,
That sounds very close to what trunc(x*100)/100 would do. But if
you are working with floating binary point numbers (FBPN) (i.e.
double, single, extended), then you have to program with some fudge
factors. This is because when you store a number like 1.13 into a
FBPN variable like a double, you don't store exactly 1.13. Instead
it is stored as +1.12999 99999 99999 89341 85896 35984 97211 93313
59863 28125. So if you ran 1.13 through your trunc method it would
truncate toward zero and you would get something very close to 1.12,
which is not what you want.
--
Regards, John H
(Support the Movement to Include Fixed and
Floating Decimal Fraction Numbers in Delphi)


Barry Kelly

unread,
Jun 15, 2001, 1:50:26 PM6/15/01
to
In article <3b2a328a$1_2@dnews>
"John Herbster" <jo...@petronworld.com> wrote:

> (Support the Movement to Include Fixed and
> Floating Decimal Fraction Numbers in Delphi)

No!

-- Barry

Daniel / Tecnobyte

unread,
Jun 15, 2001, 3:10:29 PM6/15/01
to
I am without exit. Currency just supports 4 digits after the point. It
doesn't solve all the cases. Double causes problems of roundings!!!


John Herbster <jo...@petronworld.com> escreveu nas notícias de

mensagem:3b2a328a$1_2@dnews...

John Herbster

unread,
Jun 15, 2001, 2:18:10 PM6/15/01
to
Daniel / Tecnobyte <tecn...@ulbrajp.com.br> wrote
> I am without exit.

Daniel, If you mean "at wits end", then why don't you try something
like the following? Regards, JohnH

function MyRound(x: extended): extended;
const Fudge = 0.0001;
begin
If x >=0
then result := trunc(x*100+Fudge)/100
else result := trunc(x*100-Fudge)/100;
end;

PS: Don't get upset with Barry. He's really pretty smart most of
the time!


Barry Kelly

unread,
Jun 15, 2001, 2:20:57 PM6/15/01
to
In article <3b2a4e99_2@dnews>

"Daniel / Tecnobyte" <tecn...@ulbrajp.com.br> wrote:

> I am without exit. Currency just supports 4 digits after the point. It
> doesn't solve all the cases. Double causes problems of roundings!!!

Currency is the most accurate for supporting 2 digits of accuracy
(yes, I know it provides 4 digits but this is *in order to* provide 2
digits of accuracy).

Double is based on binary representation of floating point values. You
want to truncate a *decimal* value. There isn't a one for one
correspondence between decimal values and binary values.

For this reason, if you need more accuracy that Currency, and you need
decimal accuracy, you need to work with some other representation -
like BCD or scaled integers.

-- Barry

--
One must sometimes choose between expressiveness, safety, and
performance. But a scarcity of one isn't always excused by an
abundance of another. - Thant Tessman
Team JEDI: http://www.delphi-jedi.org
NNQ - Quoting Style in Newsgroup Postings
http://web.infoave.net/~dcalhoun/nnq/nquote.html

Daniel / Tecnobyte

unread,
Jun 15, 2001, 5:40:25 PM6/15/01
to
How to work with BCD in Delphi?

Barry Kelly <dyn...@eircom.net> escreveu nas notícias de
mensagem:qbkkitobnpge0foce...@4ax.com...

Manuel Algora

unread,
Jun 15, 2001, 5:21:16 PM6/15/01
to
On Fri, 15 Jun 2001 18:50:26 +0100, Barry Kelly <dyn...@eircom.net>
wrote:

Yes!

(Why not? Given that Delphi does supports such weird entities as
Boolean and String).

Manuel Algora
m...@encomix.es

John Herbster

unread,
Jun 15, 2001, 5:32:34 PM6/15/01
to

Daniel / Tecnobyte <tecn...@ulbrajp.com.br> wrote in message
news:3b2a71ba_1@dnews...

> How to work with BCD in Delphi?

Daniel, D5 includes a type named "TBCD" but no routines that I can
find for working with it. So I put +TBCD +Delphi +arithmetic into
http://www.google.com and found the following leads. Regards, JohnH

http://www.turbopower.com/products/SysTools/bcd/
Describes TruboPower's type TBCD which may or may not be the same as
Delphi's TBCD.

http://home.kimo.com.tw/bruce0211/Kylix/15652/chapter02.html
By Charlie Calvert, describing the Kylix (and maybe D6) Advanced
Features of the Object Pascal Syntax which includes a mention of new
routines for handling the TBcd type.


Daniel / Tecnobyte

unread,
Jun 15, 2001, 6:07:59 PM6/15/01
to
> function MyRound(x: extended): extended;
> const Fudge = 0.0001;
> begin
> If x >=0
> then result := trunc(x*100+Fudge)/100
> else result := trunc(x*100-Fudge)/100;
> end;

This function fails.

MyRound(0.559999) = 0.56


Daniel / Tecnobyte

unread,
Jun 15, 2001, 6:32:59 PM6/15/01
to
Yes!


Manuel Algora <m...@encomix.es> escreveu nas notícias de
mensagem:ttukitc1id9ceu1tl...@4ax.com...

Eric Haas

unread,
Jun 16, 2001, 7:33:32 PM6/16/01
to

How much precision do you need? You can always change the Fudge
constant (e.g., Fudge = 0.0000001).

John Herbster

unread,
Jun 16, 2001, 8:12:29 PM6/16/01
to
"Daniel / Tecnobyte" <tecn...@ulbrajp.com.br> wrote

Daniel, As Eric, pointed out, you can change the fudge factor to
suit your application. But, if you make it too small, then you will
have a problem like:
var s1,s2: single;
begin
s1 := 0.13;
s2 := MyRound(s1);
ShowMessage(FormatFloat('#0.00',s2));
end;

showing "0.12". The exact values will be

s1 = +0.12999 99952 31628 41796 875
s2 = +0.11999 99973 17790 98510 74218 75

As you can see, there are problems with mixing floating binary point
numbers and decimal fractions.

Regards, JohnH


Bryan Valencia

unread,
Jun 19, 2001, 4:25:41 PM6/19/01
to
function TruncWithFormat(x:double):Double;
var
b:string;
begin
b:=format('%0.2f',[x]);
result:=strtofloat(b);
end;

BUT!

There is a floating point decimal problem in the processor on all Intel and
clone systems. Certain numbers CANNOT be represented exactly, so you enter
4.03, and the computer thinks it's 4.029999999999999999.


Sometimes the best solution if you need 2 place accuracy is to store values as
"cents" in INTEGER vars, and only convert them to display or store them in
databases.


Daniel / Tecnobyte wrote:

--
Bryan Valencia
Software Development Engineer


Bruce Roberts

unread,
Jun 19, 2001, 4:30:00 PM6/19/01
to

"Bryan Valencia" <br...@209software.com> wrote in message

> There is a floating point decimal problem in the processor on all Intel
and
> clone systems. Certain numbers CANNOT be represented exactly, so you
enter

The problem is not with the Intel or any other CPU. Its not a "problem" but
a characteristic/limitation of the storage format. All CPU/FPU have the same
behavior with "floating point" formats.


Bryan Valencia

unread,
Jun 19, 2001, 4:54:24 PM6/19/01
to
Sorry, but BCD math units (like the one in my old Atari 800) never had this
problem.

Bruce Roberts wrote:

--

Barry Kelly

unread,
Jun 19, 2001, 7:22:58 PM6/19/01
to
In article <3B2FBC00...@209software.com>
Bryan Valencia <br...@209software.com> wrote:

> Sorry, but BCD math units (like the one in my old Atari 800) never had this
> problem.

They are still fixed precision.

Also, BCD aren't floating-point; they can't deal efficiently with very
large / very small numbers.

-- Barry

--
If you're not part of the solution, you're part of the precipitate.

Bruce Roberts

unread,
Jun 19, 2001, 11:28:08 PM6/19/01
to

"Bryan Valencia" <br...@209software.com> wrote in message
news:3B2FBC00...@209software.com...

> Sorry, but BCD math units (like the one in my old Atari 800) never had
this
> problem.

I'm sure they didn't. Just as BCD on Intel and other CPU don't have this
problem. But BCD is not a "floating point" format.


Sue D. Nom

unread,
Jun 20, 2001, 3:33:34 PM6/20/01
to
Bryan Valencia wrote:

> There is a floating point decimal problem in the processor on all Intel and
> clone systems.

No, this is not correct. ALL floating point processors will have errors. Here is
why.

It is not possible to exactly represent many decimal fractions in a binary float
field. For example, 0.1 cannot be represented exactly in a 32 bit float with a 23
bit mantissa. It is not the number of decimal digits, but rather whether the
number can be represented in terms of 1 / (2^n) where n is the bit position in the
mantissa. For example

bit 1 - 1 / (2^1) = 0.5
bit 2 - 1 / (2^2) = 0.25
bit 3 - 1 / (2^3) = 0.125
bit 4 - 1 / (2^4) = 0.0625
and so on until you get to
bit 23 - 1 / (2^23) = 0.00000011920928955078125

No matter how you combine the bits you cannot get to 0.1, although you can get
close.

Currency information must be stored as integer values with implied decimal
places. Unfortuntely, although Delphi offers a currency type with 4 implied
decimal places, the field definitions for currency are of type float, and the
error will crop up. You might save the currency fields as strings to avoid this
problem.

The other problem with reals in a computer is that they are not continuous but are
only a subset of all possible reals. For Intel type CPU’s the real formats are as
follows:

Type Min to Max Value Mantissa Exponent
Single 1.5 x 10-45 .. 3.4 x 10 38 7-8 4
Double 5.0 x 10-324 .. 1.7 x 10 308 15-16 8
Extended 3.4 x 10-4932 .. 1.1 x 10 4932 19-20 10

(Source – Delphi V5 doc files)

Because of the limited number of digits in the mantissa, there are only a finite
set of real numbers that can be represented. To simplify for an example: suppose
that we have a mantissa of 1 place and an exponent of 1 place. Then, 1 E 0 is 1,
2 E 0 is 2, and so on... note that you cannot represent 2.1 with a limited
mantissa. Similarly, 1 E 1 is 10, 2 E 1 is 20, and so on, so you can't even
represent 11, 12, 13, and so on. 1 E 2 is 100, 2 E 2 is 200, so you have a gap of
100 real numbers in between each representable number... you cannot represent 150
with this limited example data type. This problem is partially alleviated by using
double, 64 bit reals which have many bits in the mantissa, but as the exponent
becomes very large... or very small, you get large gaps in the number system...
maintaining numerical accuracy is a big problem in areas such as the computation
of orbits and space craft trajectories.


JQP

unread,
Jun 21, 2001, 10:45:22 AM6/21/01
to
"Bryan Valencia" <br...@209software.com> wrote in message
news:3B2FBC00...@209software.com...

> Sorry, but BCD math units (like the one in my old Atari 800) never had
this
> problem.

Please show me the decimal value your old Atari used for the square root of
2?


John Carlyle-Clarke

unread,
Jun 22, 2001, 7:26:28 AM6/22/01
to

You don't even need an irrational number. 1/3 would do it. Also, I am
certain that it would be possible to work out a simple number that a
bicimal system can represent precisely that a decimal system can't. Just as
1/3 in base three would be 0.1 while it is a recurring decimal, I am sure
there would be equivalent examples for bicimal.

--
John Carlyle-Clarke, Software Engineer
Blakell Europlacer, Blandford

"Many have tried to formulate rules for software development. We are
guided by the ways in which they fail to work."

(S. O'Hara-Smith, a.f.c)


John Herbster

unread,
Jul 5, 2001, 9:27:37 AM7/5/01
to
Barry Kelly <dyn...@eircom.net> wrote
>> ... BCD aren't floating-point; they can't deal efficiently with

very large / very small numbers.

BCD implementations *can be* floating point.


Bryan Valencia

unread,
Jul 16, 2001, 2:13:59 PM7/16/01
to
Yes, my Atari 800 (8 bit) machine had a more limited resolution (duh),
but it knew that 0.03+0.01 was not 0.03999999999999993457856476

So I guess the phrase "deal with" can cut both ways.

John Herbster wrote:

--

0 new messages