From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,a8249faab338064d X-Google-Attributes: gid103376,public From: "David C. Hoos, Sr." Subject: Re: fixed type (delta) in ada and GNAT bug Date: 1999/11/27 Message-ID: <81ohhe$m39$1@holly.prod.itd.earthlink.net> X-Deja-AN: 553612467 Content-Transfer-Encoding: 7bit References: <383f6dbb.22609744@news.tstonramp.com> <383F808E.66464E08@easystreet.com> X-Posted-Path-Was: not-for-mail Content-Type: text/plain; charset="iso-8859-1" X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2314.1300 X-ELN-Date: 27 Nov 1999 12:07:10 GMT X-ELN-Insert-Date: Sat Nov 27 04:15:02 1999 Organization: Ada95 Press, Inc. Mime-Version: 1.0 Newsgroups: comp.lang.ada Date: 1999-11-27T00:00:00+00:00 List-Id: 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 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