comp.lang.ada
 help / color / mirror / Atom feed
From: "Robert I. Eachus" <rieachus@attbi.com>
Subject: Re: Ada 64-bit IEEE compliant float & Oracle
Date: Mon, 04 Aug 2003 23:32:08 GMT
Date: 2003-08-04T23:32:08+00:00	[thread overview]
Message-ID: <3F2EECCD.7010300@attbi.com> (raw)
In-Reply-To: 3F2E94D5.610F50F4@raytheon.com

James A. Krzyzanowski wrote:

> Problem:
> 
> We are using Rational Ada and the IEEE compliant definition for 64-bit
> floating point numbers. We recently changed our DB to Oracle which uses
> a proprietary format for storing floating point numbers with greater
> precision than the average software system could possibly need.  Oracle
> uses 17 bytes to store floating point numbers; but I have read
> documentation that they use 126 bits (not 136) to store floating point
> numbers.
> 
> We have declared new types based on the IEEE standard 64-bit float that
> have constrained ranges.  For example, we have:
> 
> type Radian_Type is new Float_64_Bit range -2_Pi .. +2_Pi;
> subtype Latitude_Type is Radian_Type range -Pi_Over_2 .. +Pi_Over_2;
> subtype Longitude_Type is Radian_Type range -Pi .. +Pi;
> 
> When we store Latitude_Type'Last in the DB and then retrieve it, we get
> a Constraint Error.

Hmmm.  I hope I don't come across as too judgmental in what I say, but...

Your first mistake is apparently in assuming that your bounds correspond 
to Ada model numbers.  If they don't, this could also happen in your Ada 
code independent of your database.

The second problem is assuming that the bounds of a TYPE are members of 
any subtype.  There is a guarentee (in a note at 3.5(57), but it deals 
with evaluating 'First and 'Last of a subtype and assigning them to 
values of the subtype. For most Ada types, this is no big deal.  A type 
declaration creates an unnamed type and a first named subtype. 
Unfortunately this doesn't hold for floating point type declarations. 
There are attributes for floating-point types called 'Safe_First and 
'Safe_Last, see A.5.3(71&72).  What is the difference? Let me give some 
examples with your declarations above:

Foo: Latitude_Type := +Pi_Over_2; -- may raise Constraint_Error;
Bar: Latitude_Type := Latitude_Type'Last; -- will not cause exception.

Foo1: Radian_Type := +2_Pi; -- may raise Constraint_Error
Foo2: Radian_Type := Radian_Type'Last -- may raise Constraint_Error!
Foo3: Radian_Type := Radian_Type'Safe_Last; -- will not cause exception.

All of this has little to do with run-time semantics, and everything to 
do with how values in program text are converted to floating-point values.

For example, the representation of your bounds could omit some (80-bit) 
values between the representation and the mathematical value.  If on the 
other hand you have chosen "2_Pi" (which is not a legal Ada identifier 
but I left it), to represent some literal, the conversions to floating 
point of that literal could be inconsistant.

Can you say can of worms?

I remember an example I gave at a SigAda meeting in Dallas.  Jerry 
Fischer was also on the panel, an he jumped up in alarm when I put up a 
slide that showed a type declaration and a subtype declaration:

type My_Integer is range -2**31..2**31-1;
subtype MI is My_Integer range -2**31..2**31-1;

And said that a compiler would accept the type declaration and could 
either accept the subtype or reject it at compile time because it would 
raise an exception at run-time!

Jerry spent about 2 minutes, following through aloud the chain of logic, 
said, "Oh, you're right!" and sat down.  I thanked Jerry for giving my 
presentation, put up a slide that showed the identical logic, and 
concluded by showing which compilers, at the time accepted it, and which 
  refused it because the subtype declaration would raise Constraint_Error.

I never figured out if any of the applause was for me for bringing the 
issue up, but I assumed most of it was for Jerry.

What is the right solution?  You either have to ensure that all of your 
literals are model numbers of the base type--in this case 64-bit 
floating point, or use some other representation.  I strongly recommend 
that whether your choose to measure angles in radians, degrees or grads, 
that the right TYPE for the job is a fixed point type.  In this case you 
can choose to measure the angles in units of Pi/2**(62), and your only 
"problem" will be that there may only be one representation of -2_Pi. 
+2_Pi will be 'Last FOR THE TYPE, but it may be unrepresentable in the 
constrained subtype.

You shouldn't have any problems with the subtypes given or the database, 
but you will always need to check that converted values are in range for 
the subtype.  Nothing to do with Ada.  If you are converting from some 
other representation to radians, the nature of computer arithmetic is 
such that an expression that is mathematically in range can evaluate at 
run-time to a point just outside the range.  Imagine you have a rotating 
radar dish, to make it easy, it rotates once every 12 seconds.  Given t 
in seconds since the dish started at azimuth 0, how do you compute the 
current dish angle?  There is no easy answer.  If t is represented in 
floating point, you can have a problem if t gets too large.  (See 
Patriot2 in the Gulf War if you don't see the problem.)  If you keep the 
time in say integer minutes plus seconds, that is better, but there 
might be a slight jitter at the end of every minute.

For the record, at least one compiler accepts Pi/(2**62) as a 'Small:

----------------------------------------------------------------------------
with Ada.Numerics; use Ada.Numerics;
with Ada.Text_IO;
procedure Rad is

type Radians is delta Pi/(2**62) range -2*Pi..2*Pi;
for Radians'Small use Pi/(2**62);

Foo: Radians := Pi/6;
package Rad_IO is new Ada.Text_IO.Fixed_IO(Radians);

begin

   Ada.Text_IO.Put(" Foo is ");
   Rad_IO.Put(Foo, 1,18,0);
   Ada.Text_IO.Put_Line(" radians.");

   Ada.Text_IO.Put(" Radians'First is ");
   Rad_IO.Put(Radians'First, 1,18,0);
   Ada.Text_IO.Put_Line(" radians.");

   Ada.Text_IO.Put(" Radians'Last is ");
   Rad_IO.Put(Radians'Last, 1,18,0);
   Ada.Text_IO.Put_Line(" radians.");

end Rad;
------------------------------------------------------------------------------
E:\Ada\Test>gnatmake -gnato rad
gnatmake -gnato rad
gcc -c -gnato rad.adb
gnatbind -x rad.ali
gnatlink rad.ali

E:\Ada\Test>rad
rad
  Foo is 0.523598775598298873 radians.
  Radians'First is -6.283185307179586480 radians.
  Radians'Last is 6.283185307179586480 radians.

E:\Ada\Test>
------------------------------------------------------------------------------
Looks fine to me, but you may want to check it out on your compiler...

-- 
"As far as I'm concerned, war always means failure." -- Jacques Chirac, 
President of France
"As far as France is concerned, you're right." -- Rush Limbaugh




      parent reply	other threads:[~2003-08-04 23:32 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-08-04 17:16 Ada 64-bit IEEE compliant float & Oracle James A. Krzyzanowski
2003-08-04 19:49 ` Stephen Leake
2003-08-04 23:32 ` Robert I. Eachus [this message]
replies disabled

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