comp.lang.ada
 help / color / mirror / Atom feed
* Question on types conversions - operations
@ 2009-06-13 15:51 Olivier Scalbert
  2009-06-13 16:13 ` Robert Matthews
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: Olivier Scalbert @ 2009-06-13 15:51 UTC (permalink / raw)


Hello,

I have the following three types:
     type Length is new Float;
     type Time   is new Float;
     type Speed  is new Float;

Suppose I need to compute a speed given a length and a time.

     L: Length := 100.0;
     T: Time   :=  10.0;
     S: Speed;

How to do that ?

With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.

With S := Speed(L / Length(T)), I am also not satisfy as I convert a 
time in Length ...

I am sure you have better ideas !

Good weekend,

Olivier



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

* Re: Question on types conversions - operations
  2009-06-13 15:51 Question on types conversions - operations Olivier Scalbert
@ 2009-06-13 16:13 ` Robert Matthews
  2009-06-13 16:55 ` anon
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Robert Matthews @ 2009-06-13 16:13 UTC (permalink / raw)


Olivier Scalbert wrote:

> Hello,
> 
> I have the following three types:
>      type Length is new Float;
>      type Time   is new Float;
>      type Speed  is new Float;
> 
> Suppose I need to compute a speed given a length and a time.
> 
>      L: Length := 100.0;
>      T: Time   :=  10.0;
>      S: Speed;
> 
> How to do that ?
> 
> With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.
> 
> With S := Speed(L / Length(T)), I am also not satisfy as I convert a
> time in Length ...
> 
> I am sure you have better ideas !
> 
> Good weekend,
> 
> Olivier

For some software with a LOT of maths, I used:
type Working_Real_Type is digits 16;
(which was big enough for the VAX target).
I would convert the various values (typed in a similar
way to your Length, Time etc) to Working_Real_Type
before using them in the equations. It was certainly
not ideal but it seemed a reasonable compromise between
type safety and the maths.

Robert





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

* Re: Question on types conversions - operations
  2009-06-13 15:51 Question on types conversions - operations Olivier Scalbert
  2009-06-13 16:13 ` Robert Matthews
@ 2009-06-13 16:55 ` anon
  2009-06-13 16:58 ` Dmitry A. Kazakov
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: anon @ 2009-06-13 16:55 UTC (permalink / raw)


How about :

  S := Speed ( L ) / Speed ( T ) ;

I prefer simplier, convert to resulting type then preform the algorithm.



In <4a33cb0b$0$2848$ba620e4c@news.skynet.be>, Olivier Scalbert <olivier.scalbert@algosyn.com> writes:
>Hello,
>
>I have the following three types:
>     type Length is new Float;
>     type Time   is new Float;
>     type Speed  is new Float;
>
>Suppose I need to compute a speed given a length and a time.
>
>     L: Length := 100.0;
>     T: Time   :=  10.0;
>     S: Speed;
>
>How to do that ?
>
>With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.
>
>With S := Speed(L / Length(T)), I am also not satisfy as I convert a 
>time in Length ...
>
>I am sure you have better ideas !
>
>Good weekend,
>
>Olivier




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

* Re: Question on types conversions - operations
  2009-06-13 15:51 Question on types conversions - operations Olivier Scalbert
  2009-06-13 16:13 ` Robert Matthews
  2009-06-13 16:55 ` anon
@ 2009-06-13 16:58 ` Dmitry A. Kazakov
  2009-06-13 16:59 ` sjw
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Dmitry A. Kazakov @ 2009-06-13 16:58 UTC (permalink / raw)


On Sat, 13 Jun 2009 17:51:17 +0200, Olivier Scalbert wrote:

> I have the following three types:
>      type Length is new Float;
>      type Time   is new Float;
>      type Speed  is new Float;
> 
> Suppose I need to compute a speed given a length and a time.
> 
>      L: Length := 100.0;
>      T: Time   :=  10.0;
>      S: Speed;
> 
> How to do that ?
> 
> With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.
> 
> With S := Speed(L / Length(T)), I am also not satisfy as I convert a 
> time in Length ...

Once you have said 'A', you have to say 'B':

function "/" (Left, Right : Length) return Length is abstract;
function "/" (Left, Right : Time) return Length is abstract;
function "/" (Left, Right : Speed) return Length is abstract;
function "/" (Left : Length; Right : Time) return Speed;

The first three disallow illegal operations on Length, Time and Speed.

The body of "/" is

function "/" (Left : Length; Right : Time) return Speed is
begin
   return Speed (Float (Left) / Float (Right));
end "/";

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



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

* Re: Question on types conversions - operations
  2009-06-13 15:51 Question on types conversions - operations Olivier Scalbert
                   ` (2 preceding siblings ...)
  2009-06-13 16:58 ` Dmitry A. Kazakov
@ 2009-06-13 16:59 ` sjw
  2009-06-13 17:24   ` Martin
  2009-06-15  8:40   ` Jean-Pierre Rosen
  2009-06-13 19:56 ` Jeffrey R. Carter
  2009-06-15  8:52 ` AdaMagica
  5 siblings, 2 replies; 16+ messages in thread
From: sjw @ 2009-06-13 16:59 UTC (permalink / raw)


On Jun 13, 4:51 pm, Olivier Scalbert <olivier.scalb...@algosyn.com>
wrote:

> I have the following three types:
>      type Length is new Float;
>      type Time   is new Float;
>      type Speed  is new Float;
>
> Suppose I need to compute a speed given a length and a time.
>
>      L: Length := 100.0;
>      T: Time   :=  10.0;
>      S: Speed;
>
> How to do that ?
>
> With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.
>
> With S := Speed(L / Length(T)), I am also not satisfy as I convert a
> time in Length ...

You could declare functions such as "*" (s : speed; t : time) return
length and of course "*" (t : time; s : speed) return length.

Inside, you could use
  return length (float (s) * float (t));

You could use speed'base, time'base but then what if one is
long_float?

It's always seemed a lot of work for very little gain to me, I've
declared them as subtypes rather than types and left checking for the
right answer to unit test. But then, my world is all about logic and
there are far more enumerations than reals, and very few calculations.
Also, we tend to have coordinates (x, y) or (r, theta) so it's a lot
more useful to define "*", "+" etc.




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

* Re: Question on types conversions - operations
  2009-06-13 16:59 ` sjw
@ 2009-06-13 17:24   ` Martin
  2009-06-13 19:35     ` sjw
  2009-06-14  8:22     ` sjw
  2009-06-15  8:40   ` Jean-Pierre Rosen
  1 sibling, 2 replies; 16+ messages in thread
From: Martin @ 2009-06-13 17:24 UTC (permalink / raw)


On Jun 13, 5:59 pm, sjw <simon.j.wri...@mac.com> wrote:
> On Jun 13, 4:51 pm, Olivier Scalbert <olivier.scalb...@algosyn.com>
> wrote:
>
>
>
> > I have the following three types:
> >      type Length is new Float;
> >      type Time   is new Float;
> >      type Speed  is new Float;
>
> > Suppose I need to compute a speed given a length and a time.
>
> >      L: Length := 100.0;
> >      T: Time   :=  10.0;
> >      S: Speed;
>
> > How to do that ?
>
> > With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.
>
> > With S := Speed(L / Length(T)), I am also not satisfy as I convert a
> > time in Length ...
>
> You could declare functions such as "*" (s : speed; t : time) return
> length and of course "*" (t : time; s : speed) return length.
>
> Inside, you could use
>   return length (float (s) * float (t));
>
> You could use speed'base, time'base but then what if one is
> long_float?
>
> It's always seemed a lot of work for very little gain to me, I've
> declared them as subtypes rather than types and left checking for the
> right answer to unit test. But then, my world is all about logic and
> there are far more enumerations than reals, and very few calculations.
> Also, we tend to have coordinates (x, y) or (r, theta) so it's a lot
> more useful to define "*", "+" etc.

It would be brilliant if units checking could be built into the
standard language...

Cheers
-- Martin



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

* Re: Question on types conversions - operations
  2009-06-13 17:24   ` Martin
@ 2009-06-13 19:35     ` sjw
  2009-06-14  8:22     ` sjw
  1 sibling, 0 replies; 16+ messages in thread
From: sjw @ 2009-06-13 19:35 UTC (permalink / raw)


On Jun 13, 6:24 pm, Martin <martin.do...@btopenworld.com> wrote:

> It would be brilliant if units checking could be built into the
> standard language...

It was a candidate for Ada05, wasn't it?

It would be interesting, I suppose, to mix unit checking with matrix
operations such as Kalman filters -- would it be rewarding, though?



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

* Re: Question on types conversions - operations
  2009-06-13 15:51 Question on types conversions - operations Olivier Scalbert
                   ` (3 preceding siblings ...)
  2009-06-13 16:59 ` sjw
@ 2009-06-13 19:56 ` Jeffrey R. Carter
  2009-06-14 15:55   ` Robert A Duff
  2009-06-15  8:52 ` AdaMagica
  5 siblings, 1 reply; 16+ messages in thread
From: Jeffrey R. Carter @ 2009-06-13 19:56 UTC (permalink / raw)


Olivier Scalbert wrote:
> 
> I have the following three types:
>     type Length is new Float;
>     type Time   is new Float;
>     type Speed  is new Float;
> 
> Suppose I need to compute a speed given a length and a time.
> 
>     L: Length := 100.0;
>     T: Time   :=  10.0;
>     S: Speed;
> 
> How to do that ?
> 
> With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.
> 
> With S := Speed(L / Length(T)), I am also not satisfy as I convert a 
> time in Length ...
> 
> I am sure you have better ideas !

If you want to do unit checking, you need a new abstraction:

type Scalar_Value is digits ...;

type Dimensioned_Value (Length : Integer; Mass : Integer; Time : Integer)
is private;

function To_Scalar (Value : in Dimensioned_Value) return Scalar_Value;

function To_Dimensioned (Length : in Integer;
                          Mass   : in Integer;
                          Time   : in Integer;
                          Value  : in Scalar_Value)
return Dimensioned_Value;

Dimension_Mismatch : exception;

function "+" (Left : in Dimensioned_Value; Right : in Dimensioned_Value)
return Dimensioned_Value;

-- "-", "*", "/", ...

subtype Length_Value is Dimensioned_Value (Length => 1, Mass => 0, Time =>  0);
subtype Time_Value   is Dimensioned_Value (Length => 0, Mass => 0, Time =>  1);
subtype Speed_Value  is Dimensioned_Value (Length => 1, Mass => 0, Time => -1);
subtype Area_Value   is Dimensioned_Value (Length => 2, Mass => 0, Time =>  0);
...

L: Length_Value := To_Dimensioned (1, 0, 0, 100.0);
T: Time_Value   := To_Dimensioned (0, 0, 1,  10.0);
S: Speed_Value;

S := L / T; -- OK.
L := L * L; -- Raises Constraint_Error: dimensions of L * L differ from L.
L := S + T; -- Raises Dimension_Mismatch.

Such an abstraction can be very useful if you have to do a lot of unit checking. 
It can also be noticeably slower than just using floating-point types.

An intermediate course is to derive a bunch of floating-point types from a 
common ancestor (as you have with Float), and define the appropriate operations 
to mix them, as others have suggested. The number of operations gets large very 
quickly. You can write a program to generate a package with the types and their 
operations; I have such a program, called Make_Units, if you'd like to see one 
(others do, too). One small problem when doing this is that the operations that 
have been "eliminated" by being declared abstract are still considered for 
overload resolution.

A low-level approach that still retains some unit checking is to derive a bunch 
of types from a common ancestor, then convert to that ancestor to perform 
operations that mix the types. This is something you've already said you don't 
like [S := Speed (Float (L) / Float (T) );].

The easiest thing from the point of writing the code is to use a single type and 
trust to inspection and testing to get the units right.

Which is best for you depends on your application.

-- 
Jeff Carter
"Beyond 100,000 lines of code you
should probably be coding in Ada."
P. J. Plauger
26



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

* Re: Question on types conversions - operations
  2009-06-13 17:24   ` Martin
  2009-06-13 19:35     ` sjw
@ 2009-06-14  8:22     ` sjw
  1 sibling, 0 replies; 16+ messages in thread
From: sjw @ 2009-06-14  8:22 UTC (permalink / raw)


On Jun 13, 6:24 pm, Martin <martin.do...@btopenworld.com> wrote:

> It would be brilliant if units checking could be built into the
> standard language...

There's Dmitry's work at http://www.dmitry-kazakov.de/ada/units.htm
(and also John Woodruff's work at http://www.dmitry-kazakov.de/ada/Numeric-Name-IO.htm).



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

* Re: Question on types conversions - operations
  2009-06-13 19:56 ` Jeffrey R. Carter
@ 2009-06-14 15:55   ` Robert A Duff
  0 siblings, 0 replies; 16+ messages in thread
From: Robert A Duff @ 2009-06-14 15:55 UTC (permalink / raw)


"Jeffrey R. Carter" <spam.jrcarter.not@nospam.acm.org> writes:

>...One small
> problem when doing this is that the operations that have been
> "eliminated" by being declared abstract are still considered for
> overload resolution.

This problem has been fixed in Ada 2005.  In Ada 95, you can get
ambiguities, because (as you say), the abstract ops are considered
for overload resolution (and then the call is illegal if that's
what it resolves to).  In Ada 2005, the overload res acts as
if the abstract ops are not even there (for nondispatching ops,
of course).

- Bob



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

* Re: Question on types conversions - operations
  2009-06-13 16:59 ` sjw
  2009-06-13 17:24   ` Martin
@ 2009-06-15  8:40   ` Jean-Pierre Rosen
  2009-06-15  9:30     ` Olivier Scalbert
                       ` (2 more replies)
  1 sibling, 3 replies; 16+ messages in thread
From: Jean-Pierre Rosen @ 2009-06-15  8:40 UTC (permalink / raw)


sjw a �crit :
>> With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.
>>
Why not nice? You are performing (for good reasons) a non homogenous
operation. Therefore you go to the no-dimension world (convert to
Float), do your operation there, then return to the dimensioned world
(convert to Speed).

-- 
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr



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

* Re: Question on types conversions - operations
  2009-06-13 15:51 Question on types conversions - operations Olivier Scalbert
                   ` (4 preceding siblings ...)
  2009-06-13 19:56 ` Jeffrey R. Carter
@ 2009-06-15  8:52 ` AdaMagica
  5 siblings, 0 replies; 16+ messages in thread
From: AdaMagica @ 2009-06-15  8:52 UTC (permalink / raw)


For an overview of methods for dealing with dimensioned units see
http://www.christ-usch-grein.homepage.t-online.de/Ada/Dimension.html
(Ada Europe Conference 2003, Toulouse)



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

* Re: Question on types conversions - operations
  2009-06-15  8:40   ` Jean-Pierre Rosen
@ 2009-06-15  9:30     ` Olivier Scalbert
  2009-06-15  9:51       ` stefan-lucks
  2009-06-15 10:33     ` AdaMagica
  2009-06-15 19:37     ` sjw
  2 siblings, 1 reply; 16+ messages in thread
From: Olivier Scalbert @ 2009-06-15  9:30 UTC (permalink / raw)


Jean-Pierre Rosen wrote:
> sjw a �crit :
>>> With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.
>>>
> Why not nice? You are performing (for good reasons) a non homogenous
> operation. Therefore you go to the no-dimension world (convert to
> Float), do your operation there, then return to the dimensioned world
> (convert to Speed).
> 

Agree !

I thought it was not nice, because if I change the three types
  Length, Time and Speed from Float to My_Float, then I have to modify:
S := Speed(My_Float(L) / My_Float(T))



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

* Re: Question on types conversions - operations
  2009-06-15  9:30     ` Olivier Scalbert
@ 2009-06-15  9:51       ` stefan-lucks
  0 siblings, 0 replies; 16+ messages in thread
From: stefan-lucks @ 2009-06-15  9:51 UTC (permalink / raw)


[-- Attachment #1: Type: TEXT/PLAIN, Size: 978 bytes --]


> Jean-Pierre Rosen wrote:
> > sjw a �crit :
> > > > With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.

> > Why not nice? 
[...]

> I thought it was not nice, because if I change the three types
>  Length, Time and Speed from Float to My_Float, then I have to modify:
> S := Speed(My_Float(L) / My_Float(T))

Indeed! Better, you start with My_Float at the beginning

    type My_Float is new Float; -- change this, if you need
    type Length is new My_Float;
    type Time   is new My_Float;
    type Speed  is new My_Float;

and later write 

    S := Speed(My_Float(L) / My_Float(T));

This is logically the same as before, but you can change the definition of 
My_Float to whatever kind of floating-point operation you like ... 

So long

Stefan







-- 
------ Stefan Lucks   --  Bauhaus-University Weimar  --   Germany  ------
               Stefan dot Lucks at uni minus weimar dot de
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------

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

* Re: Question on types conversions - operations
  2009-06-15  8:40   ` Jean-Pierre Rosen
  2009-06-15  9:30     ` Olivier Scalbert
@ 2009-06-15 10:33     ` AdaMagica
  2009-06-15 19:37     ` sjw
  2 siblings, 0 replies; 16+ messages in thread
From: AdaMagica @ 2009-06-15 10:33 UTC (permalink / raw)


On Jun 15, 10:40 am, Jean-Pierre Rosen <ro...@adalog.fr> wrote:
> sjw a écrit :>> With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.
>
> Why not nice? You are performing (for good reasons) a non homogenous
> operation. Therefore you go to the no-dimension world (convert to
> Float), do your operation there, then return to the dimensioned world
> (convert to Speed).

Of course not nice because: You introduce different types for safety
against mixing different units incorrectly. But then you render
physical expressions unreadable by marring them with type conversions
- and you lose type checking. So where is the safety?

This is only OK when hidden in a body for overloaded versions of
multiplying operators.

But then:
With only three dimensions, there are only a few overloadings
necessary; *but* there are also only very simple expressions so that
it's improbable that you write wrong expressions. So what do you gain?
Do you really gain something? Wrong dimensions deliver abstruse
results which should show up immediately in unit tests (when done
properly).

For more dimensions, you get a nightmare of overloadings. So IMHO it
is complete nonesense to try to implement different dimensions with
different types like this (with compile-time checking).

IMHO, there is no good way to do this in Ada as she is now.



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

* Re: Question on types conversions - operations
  2009-06-15  8:40   ` Jean-Pierre Rosen
  2009-06-15  9:30     ` Olivier Scalbert
  2009-06-15 10:33     ` AdaMagica
@ 2009-06-15 19:37     ` sjw
  2 siblings, 0 replies; 16+ messages in thread
From: sjw @ 2009-06-15 19:37 UTC (permalink / raw)


On Jun 15, 9:40 am, Jean-Pierre Rosen <ro...@adalog.fr> wrote:
> sjw a écrit :>> With S := Speed(Float(L) / Float(T)) ? Mmmm ... not nice.
>
> Why not nice? You are performing (for good reasons) a non homogenous
> operation. Therefore you go to the no-dimension world (convert to
> Float), do your operation there, then return to the dimensioned world
> (convert to Speed).

There's nothing in the code as presented to make sure that
Distance'Base and Time'Base are both (even either!) Float.

I suppose if the code said Speed (Distance'Base (L) / Time'Base (T))
we would get a failure to compile if one was Float and the other
Long_Float.



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

end of thread, other threads:[~2009-06-15 19:37 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-13 15:51 Question on types conversions - operations Olivier Scalbert
2009-06-13 16:13 ` Robert Matthews
2009-06-13 16:55 ` anon
2009-06-13 16:58 ` Dmitry A. Kazakov
2009-06-13 16:59 ` sjw
2009-06-13 17:24   ` Martin
2009-06-13 19:35     ` sjw
2009-06-14  8:22     ` sjw
2009-06-15  8:40   ` Jean-Pierre Rosen
2009-06-15  9:30     ` Olivier Scalbert
2009-06-15  9:51       ` stefan-lucks
2009-06-15 10:33     ` AdaMagica
2009-06-15 19:37     ` sjw
2009-06-13 19:56 ` Jeffrey R. Carter
2009-06-14 15:55   ` Robert A Duff
2009-06-15  8:52 ` AdaMagica

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