comp.lang.ada
 help / color / mirror / Atom feed
From: "David C. Hoos, Sr." <david.c.hoos.sr@ada95.com>
Subject: Re: fixed type (delta) in ada and GNAT bug
Date: 1999/11/27
Date: 1999-11-27T00:00:00+00:00	[thread overview]
Message-ID: <81ohhe$m39$1@holly.prod.itd.earthlink.net> (raw)
In-Reply-To: 383F808E.66464E08@easystreet.com

The reason "why mutiplication between fixed type in ada produce a
big round off error," is that the language standard specifies the
'Small attribute of an "ordinary_fixed_point_definition" to be a
[integer] power of 2 (RM95 3.5.9 (8).

However, from a mathematical point of view, the multiplication of
a money value by a money value is nonsense.  It only makes sense to
multiply (or divide) money values by dimensionless quantities, such
as the number of items purchased, or an interest rate.  These
quantities should be expressed in the programming language by some
type other than a money type.

There are two ways of specifying the 'Small attribute to be an
integer power of 10 -- specify the 'Small attribute directly with
an attribute_definition_clause (this method is not restricted to
integer powers of 10 -- any desired value equal to or less than
the delta is allowed), or define the type with s
decimal_fixed_point_definition -- see RM95 3.5.9 (4).

The little program presented here demonstrates four different ways
of defining a fixed-point type, and shows the resulting attributes
of each.

It also uncovered a GNAT bug in the 'image attribute for types
defined by an ordinary_fixed_point_definition and having the 'Small
attribute specified by an attribute_definition_clause.

Specifically, for a 64-bit fixed point type, the values in the
extreme regions of it range (i.e, values with a magnitude equal to
or greater than (10 ** 18) * T'Small -- where T'Small is an integer
power of 10) require 19 decimal digits to exactly express the value.
The 'image attribute of such values is always 0, and the next-to-last
digit is rounded.

The bug is being reported separately to ACT in a form suitable for
their automated e-mail processor.

The program output shows this bug.

-- begin source code --
with Ada.Text_IO;
procedure Fixed_Point is
   type Money_1 is delta 0.01 range 0.0 .. 100_000_000.00;
   type Money_2 is delta 0.01 digits 10 range 0.00 .. 10_000_000.00;
   type Money_3 is delta 0.01 range
     -0.01 * (2 ** 63 - 1) .. 0.01 * (2 ** 63 - 1);
   for Money_3'Small use 0.01;
   type Money_4 is delta 0.01 digits 10;
   type Integer_64 is range - 2 ** 63 .. 2 ** 63 - 1;
   Bad_Money : Money_3;
begin
   Ada.Text_IO.Put_Line
     ("Money_1'Small =" & Float'Image (Float (Money_1'Small)));
   Ada.Text_IO.Put_Line
     ("Money_1'Size  =" & Positive'Image (Money_1'Size));
   Ada.Text_IO.Put_Line
     ("Money_1'First =" & Money_1'Image (Money_1'First));
   Ada.Text_IO.Put_Line
     ("Money_1'Last  =" & Money_1'Image (Money_1'Last));
   Ada.Text_IO.New_Line;
   Ada.Text_IO.Put_Line
     ("Money_2'Small =" & Float'Image (Float (Money_2'Small)));
   Ada.Text_IO.Put_Line
     ("Money_2'Size  =" & Positive'Image (Money_2'Size));
   Ada.Text_IO.Put_Line
     ("Money_2'First =" & Money_2'Image (Money_2'First));
   Ada.Text_IO.Put_Line
     ("Money_2'Last  =" & Money_2'Image (Money_2'Last));
   Ada.Text_IO.New_Line;
   Ada.Text_IO.Put_Line
     ("Money_3'Small =" & Float'Image (Float (Money_3'Small)));
   Ada.Text_IO.Put_Line
     ("Money_3'Size  =" & Positive'Image (Money_3'Size));
   Ada.Text_IO.Put_Line
     ("Money_3'First =" & Money_3'Image (Money_3'First));
   Ada.Text_IO.Put_Line
     ("Money_3'Last  =" & Money_3'Image (Money_3'Last));
   Ada.Text_IO.New_Line;
   Ada.Text_IO.Put_Line
     ("Money_4'Small =" & Float'Image (Float (Money_4'Small)));
   Ada.Text_IO.Put_Line
     ("Money_4'Size  =" & Positive'Image (Money_4'Size));
   Ada.Text_IO.Put_Line
     ("Money_4'First =" & Money_4'Image (Money_4'First));
   Ada.Text_IO.Put_Line
     ("Money_4'Last  =" & Money_4'Image (Money_4'Last));
   Ada.Text_IO.New_Line;
   Ada.Text_IO.Put_Line
     ("Intger_64'Size  =" & Positive'Image (Integer_64'Size));
   Ada.Text_IO.Put_Line
     ("Intger_64'First =" & Integer_64'Image (Integer_64'First));
   Ada.Text_IO.Put_Line
     ("Intger_64'Lsst  =" & Integer_64'Image (Integer_64'Last));
   Ada.Text_IO.New_Line;
   Bad_Money := 10000000000000000.16;
   for I in 1 .. 30 loop
      Ada.Text_IO.Put_Line
     ("Bad_Money =" & Money_3'Image (Bad_Money));
      Bad_Money := Bad_Money - Money_3'Small;
   end loop;
end Fixed_Point;
-- end source code --

-- begin program output --
Money_1'Small = 7.81250E-03
Money_1'Size  = 34
Money_1'First = 0.00
Money_1'Last  = 100000000.00

Money_2'Small = 1.00000E-02
Money_2'Size  = 30
Money_2'First = 0.00
Money_2'Last  = 10000000.00

Money_3'Small = 1.00000E-02
Money_3'Size  = 64
Money_3'First =-92233720368547758.10
Money_3'Last  = 92233720368547758.10

Money_4'Small = 1.00000E-02
Money_4'Size  = 35
Money_4'First =-99999999.99
Money_4'Last  = 99999999.99

Intger_64'Size  = 64
Intger_64'First =-9223372036854775808
Intger_64'Lsst  = 9223372036854775807

Bad_Money = 10000000000000000.20
Bad_Money = 10000000000000000.10
Bad_Money = 10000000000000000.10
Bad_Money = 10000000000000000.10
Bad_Money = 10000000000000000.10
Bad_Money = 10000000000000000.10
Bad_Money = 10000000000000000.10
Bad_Money = 10000000000000000.10
Bad_Money = 10000000000000000.10
Bad_Money = 10000000000000000.10
Bad_Money = 10000000000000000.10
Bad_Money = 10000000000000000.10
Bad_Money = 10000000000000000.00
Bad_Money = 10000000000000000.00
Bad_Money = 10000000000000000.00
Bad_Money = 10000000000000000.00
Bad_Money = 10000000000000000.00
Bad_Money = 9999999999999999.99
Bad_Money = 9999999999999999.98
Bad_Money = 9999999999999999.97
Bad_Money = 9999999999999999.96
Bad_Money = 9999999999999999.95
Bad_Money = 9999999999999999.94
Bad_Money = 9999999999999999.93
Bad_Money = 9999999999999999.92
Bad_Money = 9999999999999999.91
Bad_Money = 9999999999999999.90
Bad_Money = 9999999999999999.89
Bad_Money = 9999999999999999.88
Bad_Money = 9999999999999999.87
-- end program output --

Al Christians <achrist@easystreet.com> wrote in message
news:383F808E.66464E08@easystreet.com...
> I ran your test with GNAT 3.12p under Windows NT on Pentium Pro.  I
> get the answer = 68.55.  Equally no good or even a little worse.
>
> Your fixed point numbers are all binary fixed point.  This is all
> according to the book; don't worry.
>
> Delta = 0.01 works out to use binary fixed point with 7 bits to the
> right of the binary point, ie numbers are represented as some number
> of 128ths; 1/128 is less than 0.01, so these are good to 2 decimal
> digits to the right of the decimal point.  Unfortunately, it looks
> like your 0.20 value gets represented by GNAT as 25/128, even though
> 26/128 is a little closer, neither is very close.  Whatever Ada you
> were using is using 26/128 and is a little more accurate than GNAT
> 3.12p, but there's a way around this either way (below).
>
> If I do this:
>
> a:     constant := 351.0;
> b:     constant := 1.0/5.0;
> d:     constant := a * b;
> c:     constant money := d;
>
> Then c comes out with the right value of 70.2.  a, b, and
> d, are each of type universal_real, with beaucoups of significant
> digits, and therefore c comes out ok.
>
>
> But if I do this:
>
> a:     constant := 351.0;
> b:     constant := 1.0/5.0;
> c:     constant money := a * b;
>
> Then c still comes out 68.55.  Looks like the a and b get converted
> to the money type before they get multiplied.  Ouch.
>
> But to make money a decimal fixed point type type, do this:
>
> -----------------------------------------------------------
>
> with Ada.Text_IO;
>
> procedure Money_Test is
>
> type money is delta 0.01 digits 10 range 0.0..10_000_000.00;
>
> a:     money;
> b:     money;
> c:     money;
>
> package money_io is new ada.text_io.decimal_io(money);
>
>
> begin
> a     := 351.0;
> b     := 0.20;
> c     := (a * b);
> money_io.put(c);  -- Prints 70.2
> end Money_Test;
>
> --------------------------------------------------------------
>
> This gives the right answer with no error.  The range constraint
> on the money type is optional; the digits + delta part combined
> make the numbers act like decimal numbers.
>
>
>
> Al
>
>
> Nap wrote:
> >
> > does anyone know why mutiplication between fixed type in ada produce a
> > big round off error?
> >
> > type money is delta 0.01 range 0.0..100_000_000.00;
> > a, b, c : money;
> >
> > package money_io is new ada.text_io.fixed_io(money);
> >
> > a := 351.00;
> > b := 0.20;
> > c := a * b;
> >
> > money_io.put(c);
> >
> > -- the output should be 70.2 but it prints 71.3 instead.
> > -- this is so frustrating. typecasting (back to float) doesn't help
> > either.
> >
> > Thanks,
> > Nap






  reply	other threads:[~1999-11-27  0:00 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1999-11-27  0:00 fixed type (delta) in ada Nap
1999-11-26  0:00 ` Al Christians
1999-11-27  0:00   ` David C. Hoos, Sr. [this message]
1999-11-28  0:00 ` Nick Roberts
1999-11-30  0:00   ` Simon Wright
1999-11-28  0:00 ` Robert Dewar
1999-11-27  0:00   ` Al Christians
1999-11-28  0:00     ` Preben Randhol
1999-11-28  0:00     ` Florian Weimer
1999-11-28  0:00       ` Al Christians
1999-11-29  0:00         ` Preben Randhol
1999-11-29  0:00           ` Al Christians
1999-11-29  0:00             ` Preben Randhol
1999-11-29  0:00     ` Robert Dewar
1999-11-29  0:00       ` Al Christians
1999-11-29  0:00         ` Lutz Donnerhacke
1999-11-29  0:00           ` Preben Randhol
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox