comp.lang.ada
 help / color / mirror / Atom feed
* Fixed point constants issue
@ 2010-09-13 17:27 Vinzent Hoefler
  2010-09-13 18:04 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 30+ messages in thread
From: Vinzent Hoefler @ 2010-09-13 17:27 UTC (permalink / raw)


Is this a GNAT bug or am I just stupid?

Suppose we have a fixed point type (with a rather large delta):

-- 8< --
with Ada.Text_IO; use Ada.Text_IO;

procedure Fixed_Point
is
    FEET_PER_METER : constant := 0.3048;
    HEIGHT         : constant := 10; -- Feet

    type Altitude is delta (2.0**15 / 50_000.0) range 0.0 .. 50_000.0;

    TEN_FEET_1 : constant          := HEIGHT * FEET_PER_METER;
    TEN_FEET_2 : constant Altitude := HEIGHT * FEET_PER_METER;
    TEN_FEET_3 : constant Altitude := TEN_FEET_1;
    TEN_FEET_4 : constant Altitude := Altitude (HEIGHT * FEET_PER_METER);
begin
    Put_Line ("10 feet ~" & Altitude'Image (TEN_FEET_1) & " m.");
    Put_Line ("10 feet ~" & Altitude'Image (TEN_FEET_2) & " m.");
    Put_Line ("10 feet ~" & Altitude'Image (TEN_FEET_3) & " m.");
    Put_Line ("10 feet ~" & Altitude'Image (TEN_FEET_4) & " m.");
end Fixed_Point;
-- 8< --

Now let's run the test:

10 feet ~ 3.0 m.
10 feet ~ 0.0 m.    <--- *oops*!?
10 feet ~ 3.0 m.
10 feet ~ 3.0 m.

I can see what's going on in case of TEN_FEET_2 ("FEET_PER_METER" equals
zero after the obviously happening type conversion to Altitude), but I
sure wouldn't expect such a behavior from an Ada compiler, especially not
when TEN_FEET_4 gives the expected result again[1].

To add to the confusion, the target compiler actually even does it the
"right" (or rather: expected) way; but after reading all the relevant
paragraphs in the ARM again and again, I still do not know if GNAT does
it wrong here, or if we just entered one of the few dark corners in the
Ada language.

Can anyone shed some light on this? This has driven us crazy for weeks now.


Vinzent.

[1] Of course, "Altitude'(HEIGHT * FEET_PER_METER)" yields "0.0" again.
     At least this is consistent with my understanding so far.

-- 
There is no signature.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 17:27 Fixed point constants issue Vinzent Hoefler
@ 2010-09-13 18:04 ` Dmitry A. Kazakov
  2010-09-13 18:25   ` Vinzent Hoefler
  2010-09-14 19:44   ` Keith Thompson
  0 siblings, 2 replies; 30+ messages in thread
From: Dmitry A. Kazakov @ 2010-09-13 18:04 UTC (permalink / raw)


On Mon, 13 Sep 2010 19:27:30 +0200, Vinzent Hoefler wrote:

> Is this a GNAT bug or am I just stupid?
> 
> Suppose we have a fixed point type (with a rather large delta):
> 
> -- 8< --
> with Ada.Text_IO; use Ada.Text_IO;
> 
> procedure Fixed_Point
> is
>     FEET_PER_METER : constant := 0.3048;
>     HEIGHT         : constant := 10; -- Feet
>
>    type Altitude is delta (2.0**15 / 50_000.0) range 0.0 .. 50_000.0;

[...]  
> Can anyone shed some light on this? This has driven us crazy for weeks now.
> 
> [1] Of course, "Altitude'(HEIGHT * FEET_PER_METER)" yields "0.0" again.
>      At least this is consistent with my understanding so far.

Hmm, what did you expect? 0.3048 (FEET_PER_METER) is 0 when Altitude. That
is because 2.0**15/50_000.0=0.65536 > 0.3048.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 18:04 ` Dmitry A. Kazakov
@ 2010-09-13 18:25   ` Vinzent Hoefler
  2010-09-13 19:05     ` Niklas Holsti
  2010-09-13 20:32     ` Dmitry A. Kazakov
  2010-09-14 19:44   ` Keith Thompson
  1 sibling, 2 replies; 30+ messages in thread
From: Vinzent Hoefler @ 2010-09-13 18:25 UTC (permalink / raw)


On Mon, 13 Sep 2010 20:04:32 +0200, Dmitry A. Kazakov  
<mailbox@dmitry-kazakov.de> wrote:

> On Mon, 13 Sep 2010 19:27:30 +0200, Vinzent Hoefler wrote:
>
>> Is this a GNAT bug or am I just stupid?
>>
>> Suppose we have a fixed point type (with a rather large delta):
>>
>> -- 8< --
>> with Ada.Text_IO; use Ada.Text_IO;
>>
>> procedure Fixed_Point
>> is
>>     FEET_PER_METER : constant := 0.3048;
>>     HEIGHT         : constant := 10; -- Feet
>>
>>    type Altitude is delta (2.0**15 / 50_000.0) range 0.0 .. 50_000.0;
>
> [...]
>> Can anyone shed some light on this? This has driven us crazy for weeks  
>> now.
>>
>> [1] Of course, "Altitude'(HEIGHT * FEET_PER_METER)" yields "0.0" again.
>>      At least this is consistent with my understanding so far.
>
> Hmm, what did you expect? 0.3048 (FEET_PER_METER) is 0 when Altitude.  
> That is because 2.0**15/50_000.0=0.65536 > 0.3048.

Yes, of course. Still, it's not quite intuitive why

  TEN_FEET_1 : constant          := HEIGHT * FEET_PER_METER;
  TEN_FEET_2 : constant Altitude := HEIGHT * FEET_PER_METER;

just because a type is given in the second case.

I would expect the compiler to evaluate the expression "HEIGHT *  
FEET_PER_METER"
_before_ converting it to the appropriate fixed point type. And, obviously  
it
does this that when evaluating

   TEN_FEET_4 : constant Altitude := Altitude (HEIGHT * FEET_PER_METER);

In our opinion, this type conversion on the right hand side shouldn't be
necessary, yet it is (with GNAT).


Vinzent.

-- 
There is no signature.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 18:25   ` Vinzent Hoefler
@ 2010-09-13 19:05     ` Niklas Holsti
  2010-09-13 20:35       ` Vinzent Hoefler
  2010-09-13 20:35       ` Jeffrey Carter
  2010-09-13 20:32     ` Dmitry A. Kazakov
  1 sibling, 2 replies; 30+ messages in thread
From: Niklas Holsti @ 2010-09-13 19:05 UTC (permalink / raw)


Vinzent Hoefler wrote:
> On Mon, 13 Sep 2010 20:04:32 +0200, Dmitry A. Kazakov 
> <mailbox@dmitry-kazakov.de> wrote:
> 
>> On Mon, 13 Sep 2010 19:27:30 +0200, Vinzent Hoefler wrote:
>>
>>> Is this a GNAT bug or am I just stupid?
>>>
>>> Suppose we have a fixed point type (with a rather large delta):
>>>
>>> -- 8< --
>>> with Ada.Text_IO; use Ada.Text_IO;
>>>
>>> procedure Fixed_Point
>>> is
>>>     FEET_PER_METER : constant := 0.3048;
>>>     HEIGHT         : constant := 10; -- Feet
>>>
>>>    type Altitude is delta (2.0**15 / 50_000.0) range 0.0 .. 50_000.0;
>>
>> [...]
>>> Can anyone shed some light on this? This has driven us crazy for 
>>> weeks now.
>>>
>>> [1] Of course, "Altitude'(HEIGHT * FEET_PER_METER)" yields "0.0" again.
>>>      At least this is consistent with my understanding so far.
>>
>> Hmm, what did you expect? 0.3048 (FEET_PER_METER) is 0 when Altitude. 
>> That is because 2.0**15/50_000.0=0.65536 > 0.3048.
> 
> Yes, of course. Still, it's not quite intuitive why
> 
>  TEN_FEET_1 : constant          := HEIGHT * FEET_PER_METER;
>  TEN_FEET_2 : constant Altitude := HEIGHT * FEET_PER_METER;
> 
> just because a type is given in the second case.

I think these cases are clear from the language rules:

The declaration of TEN_FEET_1 is a named-number declaration, so the 
expression is evaluated using the "root" multiplication operator "*" 
(Left : root_integer; Right : root_real) return root_real, which is done 
at compile-time and exactly (with unlimited precision).

 > I would expect the compiler to evaluate the expression
 > "HEIGHT * FEET_PER_METER" [for TEN_FEET_2] _before_
 > converting it to the appropriate fixed point type.

The declaration of TEN_FEET_2 is an object declaration with type 
Altitude, therefore the right-hand-side expression is expected to be of 
type Altitude and so the "*" will be resolved to the Altitude 
multiplication operator "*" (Left, Right : Altitude) return Altitude, 
with result zero.

I agree that this is a bit nasty and counter-intuitive. Perhaps the 
compiler should warn that the conversion of the universal_real number 
0.3048 to Altitude is seriously inexact, but then, what is "seriously"?

> And, obviously it does this that when evaluating
> 
>   TEN_FEET_4 : constant Altitude := Altitude (HEIGHT * FEET_PER_METER);

Here the right-hand side expression is a type conversion, in fact a 
value conversion, and so the operand HEIGHT * FEET_PER_METER is expected 
to be of any numeric type. At first sight the multiplication could be 
resolved to the root "*" or to the Altitude "*", which would thus be 
ambiguous. However, RM 8.6(29) says that the ambiguity is resolved by 
using the root "*", giving the more precise result.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 18:25   ` Vinzent Hoefler
  2010-09-13 19:05     ` Niklas Holsti
@ 2010-09-13 20:32     ` Dmitry A. Kazakov
  2010-09-13 21:08       ` Vinzent Hoefler
  1 sibling, 1 reply; 30+ messages in thread
From: Dmitry A. Kazakov @ 2010-09-13 20:32 UTC (permalink / raw)


On Mon, 13 Sep 2010 20:25:43 +0200, Vinzent Hoefler wrote:

> On Mon, 13 Sep 2010 20:04:32 +0200, Dmitry A. Kazakov  
> <mailbox@dmitry-kazakov.de> wrote:
> 
>> On Mon, 13 Sep 2010 19:27:30 +0200, Vinzent Hoefler wrote:
>>
>>> Is this a GNAT bug or am I just stupid?
>>>
>>> Suppose we have a fixed point type (with a rather large delta):
>>>
>>> -- 8< --
>>> with Ada.Text_IO; use Ada.Text_IO;
>>>
>>> procedure Fixed_Point
>>> is
>>>     FEET_PER_METER : constant := 0.3048;
>>>     HEIGHT         : constant := 10; -- Feet
>>>
>>>    type Altitude is delta (2.0**15 / 50_000.0) range 0.0 .. 50_000.0;
>>
>> [...]
>>> Can anyone shed some light on this? This has driven us crazy for weeks  
>>> now.
>>>
>>> [1] Of course, "Altitude'(HEIGHT * FEET_PER_METER)" yields "0.0" again.
>>>      At least this is consistent with my understanding so far.
>>
>> Hmm, what did you expect? 0.3048 (FEET_PER_METER) is 0 when Altitude.  
>> That is because 2.0**15/50_000.0=0.65536 > 0.3048.
> 
> Yes, of course. Still, it's not quite intuitive why
> 
>   TEN_FEET_1 : constant          := HEIGHT * FEET_PER_METER;
>   TEN_FEET_2 : constant Altitude := HEIGHT * FEET_PER_METER;
> 
> just because a type is given in the second case.

Different types, different behavior.

> I would expect the compiler to evaluate the expression "HEIGHT *  
> FEET_PER_METER" _before_ converting it to the appropriate fixed point type.

Why? "*" is defined on Altitude. You should rather wonder why the result is
different for TEN_FEET_4. Multiplication is inexact taking rounding this or
that way you get different results.

> And, obviously it does this that when evaluating
> 
>    TEN_FEET_4 : constant Altitude := Altitude (HEIGHT * FEET_PER_METER);

Well, it does not, because here another type is involved.

But what about:

   X : constant Altitude := 0.3048; -- The result is 0

Does it wonder you? You should consider fixed point values intervals. So 0
is actually something like [0, 0.65536[. When multiplied to 10 it becomes
[0, 6.5536[. That thing has 10 intervals of 0.65536 width in it. "0"=[0,
0.65536[ and "3"=[3.048, 3.70336[ are just two of them. The choice is more
or less arbitrary.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 19:05     ` Niklas Holsti
@ 2010-09-13 20:35       ` Vinzent Hoefler
  2010-09-13 20:35       ` Jeffrey Carter
  1 sibling, 0 replies; 30+ messages in thread
From: Vinzent Hoefler @ 2010-09-13 20:35 UTC (permalink / raw)


On Mon, 13 Sep 2010 21:05:58 +0200, Niklas Holsti  
<niklas.holsti@tidorum.invalid> wrote:

> Vinzent Hoefler wrote:
>
>  > I would expect the compiler to evaluate the expression
>  > "HEIGHT * FEET_PER_METER" [for TEN_FEET_2] _before_
>  > converting it to the appropriate fixed point type.
>
> The declaration of TEN_FEET_2 is an object declaration with type  
> Altitude, therefore the right-hand-side expression is expected to be of  
> type Altitude and so the "*" will be resolved to the Altitude  
> multiplication operator "*" (Left, Right : Altitude) return Altitude,  
> with result zero.

That's what I suspected. So, although the result is seriously wrong  
compared
to the mathematical result of the given static expression, the compiler is
still correct? :(

> I agree that this is a bit nasty and counter-intuitive. Perhaps the  
> compiler should warn that the conversion of the universal_real number  
> 0.3048 to Altitude is seriously inexact, but then, what is "seriously"?

Well, GNAT warns with a "static fixed-point value is not a multiple of
Small", but this one is quite useless, because that warning is issued for
virtually every expression in the example, so it's hard to identify the
real problematic cases.

>> And, obviously it does this that when evaluating
>>    TEN_FEET_4 : constant Altitude := Altitude (HEIGHT * FEET_PER_METER);
>
> Here the right-hand side expression is a type conversion, in fact a
> value conversion, and so the operand HEIGHT * FEET_PER_METER is expected
> to be of any numeric type. At first sight the multiplication could be
> resolved to the root "*" or to the Altitude "*", which would thus be
> ambiguous. However, RM 8.6(29) says that the ambiguity is resolved by
> using the root "*", giving the more precise result.

Right. That was the part of the ARM I didn't read. Obviously I was too
focused on the fixed point arithmetic model in Annex G 2.3.

So, it's the other compiler that does it wrong (according to my colleague,
only GNAT gives the "wrong" results)? I may run a short test tomorrow to
confirm that this is really the case.

There isn't any paragraph in the ARM that would allow the compiler to
arbitrarily choose any of both interpretations, is there?


Vinzent.

-- 
There is no signature.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 19:05     ` Niklas Holsti
  2010-09-13 20:35       ` Vinzent Hoefler
@ 2010-09-13 20:35       ` Jeffrey Carter
  2010-09-13 21:06         ` Vinzent Hoefler
                           ` (2 more replies)
  1 sibling, 3 replies; 30+ messages in thread
From: Jeffrey Carter @ 2010-09-13 20:35 UTC (permalink / raw)


On 09/13/2010 12:05 PM, Niklas Holsti wrote:
>
> The declaration of TEN_FEET_1 is a named-number declaration, so the
> expression is evaluated using the "root" multiplication operator "*"
> (Left : root_integer; Right : root_real) return root_real, which is done
> at compile-time and exactly (with unlimited precision).

Right.

>  > I would expect the compiler to evaluate the expression
>  > "HEIGHT * FEET_PER_METER" [for TEN_FEET_2] _before_
>  > converting it to the appropriate fixed point type.
>
> The declaration of TEN_FEET_2 is an object declaration with type
> Altitude, therefore the right-hand-side expression is expected to be of
> type Altitude and so the "*" will be resolved to the Altitude
> multiplication operator "*" (Left, Right : Altitude) return Altitude,
> with result zero.

More likely,

function "*" (Left : in Integer; Right : in Altitude) return Altitude;

[ARM 4.5.5(14)]. Feet_Per_Meter will be converted to Altitude before calling 
this function, resulting in a value of 0.0.

Note that this changed between Ada 83 and Ada 95. In Ada 83, the expression is 
evaluated exactly at compile time using universal_real, just as for the named 
number. In Ada 95, this was changed to use the "*" function defined for Altitude.

If the target compiler gives 3.0 as the value, then perhaps it is an Ada-83 
compiler.

There is a further wrinkle with the Ada 95 (and current Ada) rule. If "*" has 
not been overridden, this is a static expression and is evaluated at compile 
time. If "*" has been overridden, then this is not a static expression and it 
will be evaluated at run time.

-- 
Jeff Carter
"Mr. President, we must not allow a mine-shaft gap!"
Dr. Strangelove
33

--- news://freenews.netfront.net/ - complaints: news@netfront.net ---



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 20:35       ` Jeffrey Carter
@ 2010-09-13 21:06         ` Vinzent Hoefler
  2010-09-14  5:39         ` Niklas Holsti
  2010-09-24 14:43         ` Markus Schöpflin
  2 siblings, 0 replies; 30+ messages in thread
From: Vinzent Hoefler @ 2010-09-13 21:06 UTC (permalink / raw)


On Mon, 13 Sep 2010 22:35:46 +0200, Jeffrey Carter  
<spam.jrcarter.not@spam.not.acm.org> wrote:

> If the target compiler gives 3.0 as the value, then perhaps it is an  
> Ada-83 compiler.

I thought of that, too, but consider it unlikely. We use quite a lot of
Ada95 features in the meantime and it still compiles. It also says "Ada95"
in the documentation.


Vinzent.

-- 
There is no signature.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 20:32     ` Dmitry A. Kazakov
@ 2010-09-13 21:08       ` Vinzent Hoefler
  2010-09-14  6:54         ` J-P. Rosen
  2010-09-14  7:47         ` Dmitry A. Kazakov
  0 siblings, 2 replies; 30+ messages in thread
From: Vinzent Hoefler @ 2010-09-13 21:08 UTC (permalink / raw)


On Mon, 13 Sep 2010 22:32:05 +0200, Dmitry A. Kazakov  
<mailbox@dmitry-kazakov.de> wrote:

> On Mon, 13 Sep 2010 20:25:43 +0200, Vinzent Hoefler wrote:
>
>> Yes, of course. Still, it's not quite intuitive why
>>
>>   TEN_FEET_1 : constant          := HEIGHT * FEET_PER_METER;
>>   TEN_FEET_2 : constant Altitude := HEIGHT * FEET_PER_METER;
>>
>> just because a type is given in the second case.
>
> Different types, different behavior.

Well well. So this subtle difference between using a named number and a
typed constant (where the actual type *may* be a fixed point type) has
lead to quite not so subtle constraint errors.

>> I would expect the compiler to evaluate the expression "HEIGHT *
>> FEET_PER_METER" _before_ converting it to the appropriate fixed point  
>> type.
>
> Why? "*" is defined on Altitude. You should rather wonder why the result  
> is different for TEN_FEET_4.

I did wonder. :) I did a lot of different things trying to understand the
issue to my satisfaction. We now know how to get around it, but knowing a
workaround and actually understanding it are two different things.

> Multiplication is inexact taking rounding this or that way you get
> different results.

Yes, honestly I just wasn't really expecting that the compiler would
actually choose the multiplication operator of the fixed point type in
something that looks like a static expression.

>> And, obviously it does this that when evaluating
>>
>>    TEN_FEET_4 : constant Altitude := Altitude (HEIGHT * FEET_PER_METER);
>
> Well, it does not, because here another type is involved.

Yes. So, the expression HEIGHT * FEET_PER_METER in the one case is
evaluated by using the result type's multiplication operator and if the
conversion is present, it is not, giving the more precise result.

That's still a bit crazy, IMHO.

> But what about:
>
>    X : constant Altitude := 0.3048; -- The result is 0
>
> Does it wonder you?

No. That behavior is crystal-clear and expected.

It's having to add all those conversions just to make sure the values come
out as expected that's disturbing me a bit. It is something I wouldn't
expect from Ada.

As you can probably imagine, there are a lot more packages with appropriate
constants involved than in this shortened test case. And a lot of those
constants are used for fixed point values with totally different ranges
and deltas. So the actual problems do not show immediately.


Vinzent.

-- 
There is no signature.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 20:35       ` Jeffrey Carter
  2010-09-13 21:06         ` Vinzent Hoefler
@ 2010-09-14  5:39         ` Niklas Holsti
  2010-09-24 14:43         ` Markus Schöpflin
  2 siblings, 0 replies; 30+ messages in thread
From: Niklas Holsti @ 2010-09-14  5:39 UTC (permalink / raw)


Jeffrey Carter wrote:
> On 09/13/2010 12:05 PM, Niklas Holsti wrote:
>>
>> The declaration of TEN_FEET_2 is an object declaration with type
>> Altitude, therefore the right-hand-side expression is expected to be of
>> type Altitude and so the "*" will be resolved to the Altitude
>> multiplication operator "*" (Left, Right : Altitude) return Altitude,
>> with result zero.
> 
> More likely,
> 
> function "*" (Left : in Integer; Right : in Altitude) return Altitude;

Yes, my typo, sorry.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 21:08       ` Vinzent Hoefler
@ 2010-09-14  6:54         ` J-P. Rosen
  2010-09-14 18:28           ` Vinzent Hoefler
  2010-09-14  7:47         ` Dmitry A. Kazakov
  1 sibling, 1 reply; 30+ messages in thread
From: J-P. Rosen @ 2010-09-14  6:54 UTC (permalink / raw)


Le 13/09/2010 23:08, Vinzent Hoefler a écrit :
>>> And, obviously it does this that when evaluating
>>>
>>>    TEN_FEET_4 : constant Altitude := Altitude (HEIGHT * FEET_PER_METER);
>>
>> Well, it does not, because here another type is involved.
> 
> Yes. So, the expression HEIGHT * FEET_PER_METER in the one case is
> evaluated by using the result type's multiplication operator and if the
> conversion is present, it is not, giving the more precise result.
> 
> That's still a bit crazy, IMHO.
> 
Every language with overloading has to decide whether resolution goes
from the outside to the inside, or the other way round. In the case of
Ada, it is the "enclosing context" that determines the type of what's in
it. If the enclosing context is a type conversion, it tells nothing
about the expected type of its argument, hence the fall back to
universal types. If the enclosing context is typed, it determines the
type of the "*" operator.
-- 
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 21:08       ` Vinzent Hoefler
  2010-09-14  6:54         ` J-P. Rosen
@ 2010-09-14  7:47         ` Dmitry A. Kazakov
  2010-09-14 17:42           ` Vinzent Hoefler
  1 sibling, 1 reply; 30+ messages in thread
From: Dmitry A. Kazakov @ 2010-09-14  7:47 UTC (permalink / raw)


On Mon, 13 Sep 2010 23:08:08 +0200, Vinzent Hoefler wrote:

> On Mon, 13 Sep 2010 22:32:05 +0200, Dmitry A. Kazakov  
> <mailbox@dmitry-kazakov.de> wrote:
> 
>> On Mon, 13 Sep 2010 20:25:43 +0200, Vinzent Hoefler wrote:
>>
>>> Yes, of course. Still, it's not quite intuitive why
>>>
>>>   TEN_FEET_1 : constant          := HEIGHT * FEET_PER_METER;
>>>   TEN_FEET_2 : constant Altitude := HEIGHT * FEET_PER_METER;
>>>
>>> just because a type is given in the second case.
>>
>> Different types, different behavior.
> 
> Well well. So this subtle difference between using a named number and a
> typed constant (where the actual type *may* be a fixed point type) has
> lead to quite not so subtle constraint errors.

Yes, because multiplication you have in mind is not the one effectively
implemented for fixed point types. Fixed-point operations are exact, but
inaccurate in terms of real numbers. You seem to expect them inexact, but
accurate.

>> Multiplication is inexact taking rounding this or that way you get
>> different results.
> 
> Yes, honestly I just wasn't really expecting that the compiler would
> actually choose the multiplication operator of the fixed point type in
> something that looks like a static expression.

If there were a way to disallow predefined multiplication, but there is no
one, AFAIK.

And you have this same problem with all other operations. Consider 0.4+0.4
is it 0 or 0.65536?

> Yes. So, the expression HEIGHT * FEET_PER_METER in the one case is
> evaluated by using the result type's multiplication operator and if the
> conversion is present, it is not, giving the more precise result.
> 
> That's still a bit crazy, IMHO.

No, fixed point multiplication was intentionally defined that way.

> It's having to add all those conversions just to make sure the values come
> out as expected that's disturbing me a bit. It is something I wouldn't
> expect from Ada.

Well, I don't disagree, but the part of the problem is a non-intended use.
It is difficult to say how the compiler could detect that.

In your use case, the only solution I see were literals made intervals
rather than universal numbers. That would statically detect that HEIGHT *
FEET_PER_METER has the width greater than Small and warn about implicit
conversion to Altitude possibly raising Precision_Loss_Error.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-14  7:47         ` Dmitry A. Kazakov
@ 2010-09-14 17:42           ` Vinzent Hoefler
  2010-09-15  8:35             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 30+ messages in thread
From: Vinzent Hoefler @ 2010-09-14 17:42 UTC (permalink / raw)


On Tue, 14 Sep 2010 09:47:03 +0200, Dmitry A. Kazakov
<mailbox@dmitry-kazakov.de> wrote:

> Well, I don't disagree, but the part of the problem is a non-intended  
> use.

Well, the actually intended use was to create a range constrained subtype
 from an existing full-range fixed point type:

-- 8< -- snip --
    type BASE_TYPE is delta 1.0 / 64.0 range 0.0 .. 1.0;
    for BASE_TYPE'Small use 1.0 / 128.0;

    UPPER_BOUND_1 : constant           := 51.0 * 0.01;
    UPPER_BOUND_2 : constant BASE_TYPE := 51.0 * 0.01;
    UPPER_BOUND_3 : constant BASE_TYPE := BASE_TYPE (51.0 * 0.01);

    subtype SUB1_TYPE is BASE_TYPE range 0.0 .. UPPER_BOUND_1;
    subtype SUB2_TYPE is BASE_TYPE range 0.0 .. UPPER_BOUND_2;
    subtype SUB3_TYPE is BASE_TYPE range 0.0 .. UPPER_BOUND_3;
-- 8< -- snip --

(Further details of the test procedure omitted to save space.)

The numbers are arbitrarily chosen and in the real code we weren't using
constants, but rather the raw expression like in
"range 0.0 .. SOME_CONSTANT * SOME_OTHER_CONSTANT" (but that doesn't  
actually
matter, the issue remains the same, if not to say totally consistent).

Now, interestingly, the resulting ranges of the subtypes seem to be
compiler-dependent:

-- 8< -- snip --
~/project/fixed_point_issue> build fixed_point.bld
Registering Ada Sources
Compiling /home/hoefler/project/fixed_point_issue/fixed_point.adb
because "fixed_point.o" doesn't exist
Linking fixed_point
Translating symbols for fixed_point
Done
~/project/fixed_point_issue> simppc -ada fixed_point
BASE_TYPE:  0.00000000000000 ..  1.00000000000000
SUB1_TYPE:  0.00000000000000 ..  0.50781250000000
SUB2_TYPE:  0.00000000000000 ..  0.50781250000000
SUB3_TYPE:  0.00000000000000 ..  0.50781250000000
~/project/fixed_point_issue> gnatmake -f fixed_point
gnatgcc -c fixed_point.adb
gnatbind -x fixed_point.ali
gnatlink fixed_point.ali
~/project/fixed_point_issue> ./fixed_point
BASE_TYPE:  0.00000000000000 ..  0.99218750000000
SUB1_TYPE:  0.00000000000000 ..  0.50781250000000
SUB2_TYPE:  0.00000000000000 ..  0.39843750000000
SUB3_TYPE:  0.00000000000000 ..  0.50781250000000
-- 8< --

After all it really looks like the target compiler actually uses an Ada83
mode(l) here, although the code definitely is Ada95, and also both  
compilers
claim to be Ada95 compilers.

> It is difficult to say how the compiler could detect that.

Well, it did. By raising Constraint_Error for an assignment of a value  
within
the supposed range of the subtype. The virtues of unit testing.  
Fortunately,
it wasn't the other way around.


Vinzent.

-- 
There is no signature.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-14  6:54         ` J-P. Rosen
@ 2010-09-14 18:28           ` Vinzent Hoefler
  0 siblings, 0 replies; 30+ messages in thread
From: Vinzent Hoefler @ 2010-09-14 18:28 UTC (permalink / raw)


On Tue, 14 Sep 2010 08:54:20 +0200, J-P. Rosen <rosen@adalog.fr> wrote:

> Every language with overloading has to decide whether resolution goes
> from the outside to the inside, or the other way round. In the case of
> Ada, it is the "enclosing context" that determines the type of what's in
> it. If the enclosing context is a type conversion, it tells nothing
> about the expected type of its argument, hence the fall back to
> universal types. If the enclosing context is typed, it determines the
> type of the "*" operator.

I understand that. What I don't understand is that two different compilers  
do
seem to handle it differently. Actually, I just wanted to know which one  
does
it wrong. ;)

Now, to make matters worse:

ARM 3.5(9):
"[...] the evaluation of the range evaluates these simple_expressions
in an arbitrary order, and converts them to the type of the range."

which I read as "_first_ evaluate and _then_ convert". But this only  
applies to
the dynamic case, right?

Then:

ARM 3.5(5):
"For a subtype_indication containing a range_constraint, [...], the type  
of the
range shall resolve to that of the type determined by the subtype_mark of  
the
subtype_indication. For a range of a given type, the simple_expressions of  
the range
(likewise, the simple_expressions of the equivalent range for a
range_attribute_reference) are expected to be of the type of the range."

Which is quite specific and seems to happen here.

Yet, this is not the end:

ARM 3.5.9(3) defines a fixed point definition to have a  
"real_range_specification",
which according to ARM 3.5.7(5) "is expected to be of any real type; the  
types
need not be the same".

Now, I suspect that in

type    Fixed_1 is         delta 0.5 range 0.0 .. 50.0 * 0.1;
subtype Fixed_2 is Fixed_1           range 0.0 .. 50.0 * 0.1;

(where "One_Tenth" shall be a non-static function).

Fixed_1 and Fixed_4 have a range of 0.0 .. 5.0 then, whilst Fixed_2's  
range suddenly
is 0.0 .. 0.0 again, right?


Vinzent.

-- 
There is no signature.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 18:04 ` Dmitry A. Kazakov
  2010-09-13 18:25   ` Vinzent Hoefler
@ 2010-09-14 19:44   ` Keith Thompson
  1 sibling, 0 replies; 30+ messages in thread
From: Keith Thompson @ 2010-09-14 19:44 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> On Mon, 13 Sep 2010 19:27:30 +0200, Vinzent Hoefler wrote:
>> Is this a GNAT bug or am I just stupid?
>> 
>> Suppose we have a fixed point type (with a rather large delta):
>> 
>> -- 8< --
>> with Ada.Text_IO; use Ada.Text_IO;
>> 
>> procedure Fixed_Point
>> is
>>     FEET_PER_METER : constant := 0.3048;
>>     HEIGHT         : constant := 10; -- Feet
>>
>>    type Altitude is delta (2.0**15 / 50_000.0) range 0.0 .. 50_000.0;
>
> [...]  
>> Can anyone shed some light on this? This has driven us crazy for weeks now.
>> 
>> [1] Of course, "Altitude'(HEIGHT * FEET_PER_METER)" yields "0.0" again.
>>      At least this is consistent with my understanding so far.
>
> Hmm, what did you expect? 0.3048 (FEET_PER_METER) is 0 when Altitude. That
> is because 2.0**15/50_000.0=0.65536 > 0.3048.

Close, but actually it's because 2.0**15/50_000.0=0.65536 > 0.5.

Altitude'Delta = 0.65536.  Altitude'Small = 0.5.  If you want the
'Small to be the same as the 'Delta, you have to specify it (or
use a power of 2.0).

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-14 17:42           ` Vinzent Hoefler
@ 2010-09-15  8:35             ` Dmitry A. Kazakov
  2010-09-15 17:24               ` Vinzent Hoefler
  0 siblings, 1 reply; 30+ messages in thread
From: Dmitry A. Kazakov @ 2010-09-15  8:35 UTC (permalink / raw)


On Tue, 14 Sep 2010 19:42:52 +0200, Vinzent Hoefler wrote:

> On Tue, 14 Sep 2010 09:47:03 +0200, Dmitry A. Kazakov
> <mailbox@dmitry-kazakov.de> wrote:
> 
>> Well, I don't disagree, but the part of the problem is a non-intended  
>> use.
> 
> Well, the actually intended use was to create a range constrained subtype
>  from an existing full-range fixed point type:
> 
> -- 8< -- snip --
>     type BASE_TYPE is delta 1.0 / 64.0 range 0.0 .. 1.0;
>     for BASE_TYPE'Small use 1.0 / 128.0;

But use suggests rather:

   type Base_Type is delta 0.01 digits 3 range 0.0..1.0;

or

   type Base_Type is delta 0.01 digits 3 range -1.0..1.0;

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-15  8:35             ` Dmitry A. Kazakov
@ 2010-09-15 17:24               ` Vinzent Hoefler
  2010-09-15 20:11                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 30+ messages in thread
From: Vinzent Hoefler @ 2010-09-15 17:24 UTC (permalink / raw)


On Wed, 15 Sep 2010 10:35:22 +0200, Dmitry A. Kazakov  
<mailbox@dmitry-kazakov.de> wrote:

> On Tue, 14 Sep 2010 19:42:52 +0200, Vinzent Hoefler wrote:
>
>> -- 8< -- snip --
>>     type BASE_TYPE is delta 1.0 / 64.0 range 0.0 .. 1.0;
>>     for BASE_TYPE'Small use 1.0 / 128.0;
>
> But use suggests rather:
>
>    type Base_Type is delta 0.01 digits 3 range 0.0..1.0;
>
> or
>
>    type Base_Type is delta 0.01 digits 3 range -1.0..1.0;

No. These are bus-protocol types (read: hardware types) where MSB values,  
bit sizes
and (valid) range are given, so we definitely want to make sure that the  
compiler
uses the correct representation. Thus, a "simple" digits constraint is  
ruled out
here.

Usually such a type definition looks similar to that:

       type Foo is delta 1.638_400 / 2**13 range -0.819_200 .. 0.819_200;
       for Foo'Small use 1.638_400 / 2**13;
       for Foo'Size use 13;

For reading from the bus we use the (full-range) base type and checking  
its range
before assigning it to the appropriate object of the constrained subtype.


Vinzent.

-- 
There is no signature.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-15 17:24               ` Vinzent Hoefler
@ 2010-09-15 20:11                 ` Dmitry A. Kazakov
  0 siblings, 0 replies; 30+ messages in thread
From: Dmitry A. Kazakov @ 2010-09-15 20:11 UTC (permalink / raw)


On Wed, 15 Sep 2010 19:24:23 +0200, Vinzent Hoefler wrote:

> On Wed, 15 Sep 2010 10:35:22 +0200, Dmitry A. Kazakov  
> <mailbox@dmitry-kazakov.de> wrote:
> 
>> On Tue, 14 Sep 2010 19:42:52 +0200, Vinzent Hoefler wrote:
>>
>>> -- 8< -- snip --
>>>     type BASE_TYPE is delta 1.0 / 64.0 range 0.0 .. 1.0;
>>>     for BASE_TYPE'Small use 1.0 / 128.0;
>>
>> But use suggests rather:
>>
>>    type Base_Type is delta 0.01 digits 3 range 0.0..1.0;
>>
>> or
>>
>>    type Base_Type is delta 0.01 digits 3 range -1.0..1.0;
> 
> No. These are bus-protocol types (read: hardware types) where MSB values,  
> bit sizes and (valid) range are given, so we definitely want to make sure that the  
> compile uses the correct representation.

OK, I would never do it this way. In similar cases I use a modular or
integer type. Which is converted to a floating point or fixed point type
suitable for further computations or processing.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-13 20:35       ` Jeffrey Carter
  2010-09-13 21:06         ` Vinzent Hoefler
  2010-09-14  5:39         ` Niklas Holsti
@ 2010-09-24 14:43         ` Markus Schöpflin
  2010-09-24 20:05           ` Vinzent Hoefler
  2010-09-24 21:38           ` Jeffrey Carter
  2 siblings, 2 replies; 30+ messages in thread
From: Markus Schöpflin @ 2010-09-24 14:43 UTC (permalink / raw)


Forgive me for resurrecting an old thread, but when trying to understand 
the issue, I came up with more questions...

Am 13.09.2010 22:35, schrieb Jeffrey Carter:

> Note that this changed between Ada 83 and Ada 95. In Ada 83, the expression
> is evaluated exactly at compile time using universal_real, just as for the
> named number. In Ada 95, this was changed to use the "*" function defined
> for Altitude.

Are you sure about that? Because I compiled and ran the following program 
with an Ada 83 compiler (DEC Ada) and I got a different result. Note that I 
modified the delta to 0.5 to avoid any issues resulting from delta /= small.

---%<---
with TEXT_IO; use TEXT_IO;

procedure FIXED_POINT
is
    type ALTITUDE is delta 0.5 range 0.0 .. 50_000.0;

    package ALTITUDE_IO is new FIXED_IO (ALTITUDE);

    FEET_PER_METER : constant := 0.3048;
    HEIGHT         : constant := 10; -- Feet

    TEN_FEET_1 : constant          := HEIGHT * FEET_PER_METER;
    TEN_FEET_2 : constant ALTITUDE := HEIGHT * FEET_PER_METER;
begin
    ALTITUDE_IO.PUT (TEN_FEET_1); NEW_LINE; -- gives 3.0
    ALTITUDE_IO.PUT (TEN_FEET_2); NEW_LINE; -- gives 5.0 (*)
end FIXED_POINT;
--->%---

(*) This certainly looks like FEET_PER_METER is converted to ALTITUDE 
before doing the multiplication.

Another question regarding the implicit conversion from universal_real to 
ALTITUDE: Does ARM83-3.5.6 apply here? And what does this mean: "If the 
universal_real value is a safe number, the implicit conversion delivers the 
corresponding value; if it belongs to the range of safe numbers but is not 
a safe number, then the converted value can be any value within the range 
defined by the safe numbers next above and below the universal_real value." 
Is the compiler free to convert FEET_PER_METER to either 0.0 or 0.5?

Regards,
Markus



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-24 14:43         ` Markus Schöpflin
@ 2010-09-24 20:05           ` Vinzent Hoefler
  2010-09-24 21:38           ` Jeffrey Carter
  1 sibling, 0 replies; 30+ messages in thread
From: Vinzent Hoefler @ 2010-09-24 20:05 UTC (permalink / raw)


On Fri, 24 Sep 2010 16:43:29 +0200, Markus Schöpflin <no@spam.spam> wrote:

>     TEN_FEET_1 : constant          := HEIGHT * FEET_PER_METER;
>     TEN_FEET_2 : constant ALTITUDE := HEIGHT * FEET_PER_METER;
> begin
>     ALTITUDE_IO.PUT (TEN_FEET_1); NEW_LINE; -- gives 3.0
>     ALTITUDE_IO.PUT (TEN_FEET_2); NEW_LINE; -- gives 5.0 (*)
> end FIXED_POINT;
> --->%---
>
> (*) This certainly looks like FEET_PER_METER is converted to ALTITUDE  
> before doing the multiplication.

Now that's interesting. Let me re-iterate: We have an Ada95 compiler  
behaving
as expected (although not necessarily intuitive) (GNAT), an Ada95 compiler
behaving like what's supposed to be an Ada83 difference (GreenHills, to
finally reveal the name), and now an Ada83 compiler behaving as if it were
an Ada95 compiler.

At least according to what I understood so far... seriously, I'm no less
confused than I was before.

> Another question regarding the implicit conversion from universal_real  
> to ALTITUDE: Does ARM83-3.5.6 apply here? And what does this mean: "If  
> the universal_real value is a safe number, the implicit conversion  
> delivers the corresponding value; if it belongs to the range of safe  
> numbers but is not a safe number, then the converted value can be any  
> value within the range defined by the safe numbers next above and below  
> the universal_real value." Is the compiler free to convert  
> FEET_PER_METER to either 0.0 or 0.5?

This would by my understanding, Ada95 puts it in different terms, but
basically the compiler seems to be allowed to choose any of both choices.

But IANALL (although today a call from my co-worker started with
"Ada Support there?" *g*).


Vinzent.

-- 
There is no signature.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-24 14:43         ` Markus Schöpflin
  2010-09-24 20:05           ` Vinzent Hoefler
@ 2010-09-24 21:38           ` Jeffrey Carter
  2010-09-24 22:42             ` Vinzent Hoefler
  2010-09-27 17:58             ` Adam Beneschan
  1 sibling, 2 replies; 30+ messages in thread
From: Jeffrey Carter @ 2010-09-24 21:38 UTC (permalink / raw)


On 09/24/2010 07:43 AM, Markus Schöpflin wrote:
>
> Are you sure about that? Because I compiled and ran the following
> program with an Ada 83 compiler (DEC Ada) and I got a different result.
> Note that I modified the delta to 0.5 to avoid any issues resulting from
> delta /= small.
>
> ---%<---
> with TEXT_IO; use TEXT_IO;
>
> procedure FIXED_POINT
> is
> type ALTITUDE is delta 0.5 range 0.0 .. 50_000.0;
>
> package ALTITUDE_IO is new FIXED_IO (ALTITUDE);
>
> FEET_PER_METER : constant := 0.3048;
> HEIGHT : constant := 10; -- Feet
>
> TEN_FEET_1 : constant := HEIGHT * FEET_PER_METER;
> TEN_FEET_2 : constant ALTITUDE := HEIGHT * FEET_PER_METER;
> begin
> ALTITUDE_IO.PUT (TEN_FEET_1); NEW_LINE; -- gives 3.0
> ALTITUDE_IO.PUT (TEN_FEET_2); NEW_LINE; -- gives 5.0 (*)
> end FIXED_POINT;
> --->%---
>
> (*) This certainly looks like FEET_PER_METER is converted to ALTITUDE
> before doing the multiplication.

That is interesting. I learned Ada 83 in 1984; I was explicitly taught that 
static universal (sub)expressions were evaluated exactly by the compiler, using 
universal operations. For example, I was taught that in

Pi : constant := 3.14159;

X : Float;
...
Reduce : loop
    exit Reduce when X < Pi / 2;

    X := X - Pi / 2;
end loop Reduce;

both occurrences of "Pi / 2" would be evaluated exactly by the compiler. Perhaps 
I was taught wrong.

-- 
Jeff Carter
"We use a large, vibrating egg."
Annie Hall
44



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-24 21:38           ` Jeffrey Carter
@ 2010-09-24 22:42             ` Vinzent Hoefler
  2010-09-25  0:16               ` Jeffrey Carter
  2010-09-27 17:58             ` Adam Beneschan
  1 sibling, 1 reply; 30+ messages in thread
From: Vinzent Hoefler @ 2010-09-24 22:42 UTC (permalink / raw)


On Fri, 24 Sep 2010 23:38:11 +0200, Jeffrey Carter  
<spam.jrcarter.not@spam.not.acm.org> wrote:

> That is interesting. I learned Ada 83 in 1984; I was explicitly taught  
> that static universal (sub)expressions were evaluated exactly by the  
> compiler, using universal operations.

3.5.9 says:

Multiplication and division of fixed point values deliver results of a  
fixed point type with
an arbitrarily fine accuracy [...] which is referred to [...] as  
/universal_fixed/.

And then 4.5.8 (referenced by 3.5.9) seems quite clear about that:

The bounds on a real value resulting from a predefined operation are  
defined by the three
following steps:

(1) A model interval of the appropriate type or subtype is associated with  
the value of
     each operand.
(2) A new interval is formed by applying the (exact) mathematical  
operation to operands
     from the model intervals produced in step (1). [...]


Vinzent.

-- 
There is no signature.



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-24 22:42             ` Vinzent Hoefler
@ 2010-09-25  0:16               ` Jeffrey Carter
  2010-09-27 10:33                 ` Markus Schöpflin
  0 siblings, 1 reply; 30+ messages in thread
From: Jeffrey Carter @ 2010-09-25  0:16 UTC (permalink / raw)


On 09/24/2010 03:42 PM, Vinzent Hoefler wrote:
>
> 3.5.9 says:
>
> Multiplication and division of fixed point values deliver results of a
> fixed point type with
> an arbitrarily fine accuracy [...] which is referred to [...] as
> /universal_fixed/.

Yes. But these are not fixed-point values. One is universal_integer and the 
other is universal_real. The question is whether "*" is the one defined for 
universal_real or for the fixed-point type. In the latter case, the 
universal_real value would be converted to the fixed-point type before calling "*".

ARM83 4.10 says that static, universal expressions are evaluated exactly. The 
question seems to be whether the expression is universal. ARM83 4.4 seems to be 
the place to look for that, but I'm not sure which it requires.

-- 
Jeff Carter
"We use a large, vibrating egg."
Annie Hall
44



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-25  0:16               ` Jeffrey Carter
@ 2010-09-27 10:33                 ` Markus Schöpflin
  2010-09-27 18:57                   ` Jeffrey Carter
  0 siblings, 1 reply; 30+ messages in thread
From: Markus Schöpflin @ 2010-09-27 10:33 UTC (permalink / raw)


Am 25.09.2010 02:16, schrieb Jeffrey Carter:
> On 09/24/2010 03:42 PM, Vinzent Hoefler wrote:
>>
>> 3.5.9 says:
>>
>> Multiplication and division of fixed point values deliver results of a
>> fixed point type with
>> an arbitrarily fine accuracy [...] which is referred to [...] as
>> /universal_fixed/.
>
> Yes. But these are not fixed-point values. One is universal_integer and the
> other is universal_real. The question is whether "*" is the one defined for
> universal_real or for the fixed-point type. In the latter case, the
> universal_real value would be converted to the fixed-point type before
> calling "*".
>
> ARM83 4.10 says that static, universal expressions are evaluated exactly.
> The question seems to be whether the expression is universal. ARM83 4.4
> seems to be the place to look for that, but I'm not sure which it requires.

We have three different overloads for "*" to consider. One is

   universal_integer * universal_real -> universal_real [4.10]

The next is

   INTEGER * ALTITUDE -> ALTITUDE [4.5.5]

The third is

   ALTITUDE * ALTITUDE -> ALTITUDE [4.5.5]

I think the key to the answer is in ARM83 4.6: "Apart from the explicit 
type conversions, the only allowed form of type conversion is the implicit 
conversion of a value of the type universal_integer or universal_real into 
another numeric type. An implicit conversion of an operand of type 
universal_integer to another integer type, or of an operand of type 
universal_real to another real type, can only be applied if the operand is 
either a numeric literal, a named number, or an attribute; such an operand 
is called a convertible universal operand in this section. An implicit 
conversion of a convertible universal operand is applied if and only if the 
innermost complete context (see 8.7) determines a unique (numeric) target 
type for the implicit conversion, and there is no legal interpretation of 
this context without this conversion."

There is no conversion from universal_integer to ALTITUDE, therefore the 
third overload cannot be chosen.

The implicit conversion from universal_real to ALTITUDE is only done when 
the operand is either a numeric literal, a named number, or an attribute. 
This rules out the first overload.

Therefore we have only the second overload left which is chosen because of 
an implicit conversion from universal_integer to INTEGER and from 
universal_real to ALTITUDE.

And the different results we're seeing are due to [3.5.6] which, if I 
understand the text correctly, allows the result of the conversion from 
FEET_PER_METER to be either 0 or 0.5.

Can someone confirm this reasoning?

Markus



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-24 21:38           ` Jeffrey Carter
  2010-09-24 22:42             ` Vinzent Hoefler
@ 2010-09-27 17:58             ` Adam Beneschan
  1 sibling, 0 replies; 30+ messages in thread
From: Adam Beneschan @ 2010-09-27 17:58 UTC (permalink / raw)


On Sep 24, 2:38 pm, Jeffrey Carter
<spam.jrcarter....@spam.not.acm.org> wrote:
> On 09/24/2010 07:43 AM, Markus Schöpflin wrote:
>
>
>
>
>
>
>
> > Are you sure about that? Because I compiled and ran the following
> > program with an Ada 83 compiler (DEC Ada) and I got a different result.
> > Note that I modified the delta to 0.5 to avoid any issues resulting from
> > delta /= small.
>
> > ---%<---
> > with TEXT_IO; use TEXT_IO;
>
> > procedure FIXED_POINT
> > is
> > type ALTITUDE is delta 0.5 range 0.0 .. 50_000.0;
>
> > package ALTITUDE_IO is new FIXED_IO (ALTITUDE);
>
> > FEET_PER_METER : constant := 0.3048;
> > HEIGHT : constant := 10; -- Feet
>
> > TEN_FEET_1 : constant := HEIGHT * FEET_PER_METER;
> > TEN_FEET_2 : constant ALTITUDE := HEIGHT * FEET_PER_METER;
> > begin
> > ALTITUDE_IO.PUT (TEN_FEET_1); NEW_LINE; -- gives 3.0
> > ALTITUDE_IO.PUT (TEN_FEET_2); NEW_LINE; -- gives 5.0 (*)
> > end FIXED_POINT;
> > --->%---
>
> > (*) This certainly looks like FEET_PER_METER is converted to ALTITUDE
> > before doing the multiplication.
>
> That is interesting. I learned Ada 83 in 1984; I was explicitly taught that
> static universal (sub)expressions were evaluated exactly by the compiler, using
> universal operations. For example, I was taught that in
>
> Pi : constant := 3.14159;
>
> X : Float;
> ...
> Reduce : loop
>     exit Reduce when X < Pi / 2;
>
>     X := X - Pi / 2;
> end loop Reduce;
>
> both occurrences of "Pi / 2" would be evaluated exactly by the compiler. Perhaps
> I was taught wrong.

Hmmm...  in looking into this, I bumped into AI83-165 which would make
it appear that the use of Pi/2 in both occurrences is illegal.  But
maybe that AI got superseded by some other AI.  I don't know.

                                   -- Adam



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-27 10:33                 ` Markus Schöpflin
@ 2010-09-27 18:57                   ` Jeffrey Carter
  2010-09-28  8:16                     ` Markus Schöpflin
  0 siblings, 1 reply; 30+ messages in thread
From: Jeffrey Carter @ 2010-09-27 18:57 UTC (permalink / raw)


On 09/27/2010 03:33 AM, Markus Schöpflin wrote:
>
> The implicit conversion from universal_real to ALTITUDE is only done
> when the operand is either a numeric literal, a named number, or an
> attribute. This rules out the first overload.

I don't follow this.

-- 
Jeff Carter
"Sir Lancelot saves Sir Gallahad from almost certain temptation."
Monty Python & the Holy Grail
69



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-27 18:57                   ` Jeffrey Carter
@ 2010-09-28  8:16                     ` Markus Schöpflin
  2010-09-28 17:28                       ` Jeffrey Carter
  0 siblings, 1 reply; 30+ messages in thread
From: Markus Schöpflin @ 2010-09-28  8:16 UTC (permalink / raw)


Am 27.09.2010 20:57, schrieb Jeffrey Carter:
 > On 09/27/2010 03:33 AM, Markus Schöpflin wrote:
 >>
 >> The implicit conversion from universal_real to ALTITUDE is only done
 >> when the operand is either a numeric literal, a named number, or an
 >> attribute. This rules out the first overload.
 >
 > I don't follow this.

Could you please elaborate?

To quote ARM83 4.6 again: "An implicit conversion of an operand of type 
[...] universal_real to another real type, can only be applied if the 
operand is either a numeric literal, a named number, or an attribute; [...]"

So an implicit conversion will never be applied to the result of 
universal_integer * universal_real, as the operand of the conversion is an 
expression. But an implicit conversion to ALTITUDE would be needed for 
universal_integer * universal_real -> universal_real to be used.

On the other hand, the line "TEN_FEET_3 : constant Altitude := TEN_FEET_1;" 
from the original example does use an implicit conversion, precisely 
because TEN_FEET_1 is a named number of type universal_real.

Or am I completely off track here?

Markus




^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-28  8:16                     ` Markus Schöpflin
@ 2010-09-28 17:28                       ` Jeffrey Carter
  2010-10-05  6:27                         ` Randy Brukardt
  0 siblings, 1 reply; 30+ messages in thread
From: Jeffrey Carter @ 2010-09-28 17:28 UTC (permalink / raw)


On 09/28/2010 01:16 AM, Markus Schöpflin wrote:
>
> To quote ARM83 4.6 again: "An implicit conversion of an operand of type
> [...] universal_real to another real type, can only be applied if the
> operand is either a numeric literal, a named number, or an attribute;
> [...]"
>
> So an implicit conversion will never be applied to the result of
> universal_integer * universal_real, as the operand of the conversion is
> an expression. But an implicit conversion to ALTITUDE would be needed
> for universal_integer * universal_real -> universal_real to be used.

Having read the section, I see what you're saying now. I was unclear because of 
the use of "operand"; I thought it referred to an operand of "*", but it refers 
to the operand of the implicit type conversion.

This does seem to indicate that

function "*" (Left : Integer; Right : Altitude) return Altitude;

is used in this case, and what I was taught is incorrect.

It would be nice to hear from someone who implemented an Ada-83 compiler. We 
know you're out there.

-- 
Jeff Carter
"People called Romanes, they go the house?"
Monty Python's Life of Brian
79



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-09-28 17:28                       ` Jeffrey Carter
@ 2010-10-05  6:27                         ` Randy Brukardt
  2010-10-05 18:40                           ` Jeffrey Carter
  0 siblings, 1 reply; 30+ messages in thread
From: Randy Brukardt @ 2010-10-05  6:27 UTC (permalink / raw)


"Jeffrey Carter" <spam.jrcarter.not@spam.not.acm.org> wrote in message 
news:i7t9el$95r$1@tornado.tornevall.net...
...
> It would be nice to hear from someone who implemented an Ada-83 compiler. 
> We know you're out there.

I don't remember for certain, but my recollection is that Ada 83 always 
implicitly converts the leaves of an expression tree; that is operations on 
universal types are only used for named numbers, operands of type 
conversions and the like. I don't think Ada 95 changed this significantly 
(the way the rules are presented was changed a lot, but that's not 
particularly important). I remember hearing the exact evaluation saw as 
well, but I don't think it was ever true other than in very limited cases.

                                  Randy (who did write an Ada 83 compiler).











^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Fixed point constants issue
  2010-10-05  6:27                         ` Randy Brukardt
@ 2010-10-05 18:40                           ` Jeffrey Carter
  0 siblings, 0 replies; 30+ messages in thread
From: Jeffrey Carter @ 2010-10-05 18:40 UTC (permalink / raw)


On 10/04/2010 11:27 PM, Randy Brukardt wrote:
> "Jeffrey Carter"<spam.jrcarter.not@spam.not.acm.org>  wrote in message
> news:i7t9el$95r$1@tornado.tornevall.net...
> ...
>> It would be nice to hear from someone who implemented an Ada-83 compiler.
>> We know you're out there.
>
>                                    Randy (who did write an Ada 83 compiler).

I know. I used it.

-- 
Jeff Carter
"English bed-wetting types."
Monty Python & the Holy Grail
15



^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2010-10-05 18:40 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-13 17:27 Fixed point constants issue Vinzent Hoefler
2010-09-13 18:04 ` Dmitry A. Kazakov
2010-09-13 18:25   ` Vinzent Hoefler
2010-09-13 19:05     ` Niklas Holsti
2010-09-13 20:35       ` Vinzent Hoefler
2010-09-13 20:35       ` Jeffrey Carter
2010-09-13 21:06         ` Vinzent Hoefler
2010-09-14  5:39         ` Niklas Holsti
2010-09-24 14:43         ` Markus Schöpflin
2010-09-24 20:05           ` Vinzent Hoefler
2010-09-24 21:38           ` Jeffrey Carter
2010-09-24 22:42             ` Vinzent Hoefler
2010-09-25  0:16               ` Jeffrey Carter
2010-09-27 10:33                 ` Markus Schöpflin
2010-09-27 18:57                   ` Jeffrey Carter
2010-09-28  8:16                     ` Markus Schöpflin
2010-09-28 17:28                       ` Jeffrey Carter
2010-10-05  6:27                         ` Randy Brukardt
2010-10-05 18:40                           ` Jeffrey Carter
2010-09-27 17:58             ` Adam Beneschan
2010-09-13 20:32     ` Dmitry A. Kazakov
2010-09-13 21:08       ` Vinzent Hoefler
2010-09-14  6:54         ` J-P. Rosen
2010-09-14 18:28           ` Vinzent Hoefler
2010-09-14  7:47         ` Dmitry A. Kazakov
2010-09-14 17:42           ` Vinzent Hoefler
2010-09-15  8:35             ` Dmitry A. Kazakov
2010-09-15 17:24               ` Vinzent Hoefler
2010-09-15 20:11                 ` Dmitry A. Kazakov
2010-09-14 19:44   ` Keith Thompson

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