comp.lang.ada
 help / color / mirror / Atom feed
From: AdaMagica <christ-usch.grein@t-online.de>
Subject: Re: GNAT and Dimension Checking
Date: Fri, 6 Jul 2012 03:47:58 -0700 (PDT)
Date: 2012-07-06T03:47:58-07:00	[thread overview]
Message-ID: <8252873c-f2b9-4afd-8373-0658836c34c1@googlegroups.com> (raw)
In-Reply-To: <2afdc8e6-def0-4a00-8535-4db40165fc92@googlegroups.com>

I would like to invite all of you interested in dimensional algebra to a lively discussion about the findings in packages provided by GNAT.

I played around a bit and here are mine.

  GNAT Dimension_System Findings
==================================

Very clever use of the new aspect facilty.
Should be considered for standardisation in next Ada generation.

Currently very poorly documented.

There are a few minor problems and some (in my honest opinion) more severe
ones in output.

The following is based on the (Gaussian) CGS system.

  type CGS_Gauss is new Long_Long_Float
    with Dimension_System => ((Centimeter, "cm"),
                              (Gram      , 'g'),
                              (Second    , 's'));

  package CGS_Gauss_IO is new System.Dim.Float_IO (CGS_Gauss);
  use CGS_Gauss_IO;

  subtype Length is CGS_Gauss
    with Dimension => ("cm",
                       Centimeter => 1,
                       others     => 0);

  subtype Mass is CGS_Gauss
    with Dimension => ("g",
                       Gram   => 1,
                       others => 0);

  subtype Time is CGS_Gauss
    with Dimension => ("s",
                       Second => 1,
                       others => 0);

  cm: constant Length := 1.0;
  g : constant Mass   := 1.0;
  s : constant Time   := 1.0;

0. The syntax of aspects Dimension_System and Dimension is not documented.
--------------------------------------------------------------------------
It might seem obvious, but documentation is needed nevertheless.

In Dimension_System, up to 7 base dimensions may be defined (more lead to
a compilation error, less are tolerated).

1. How to define objects for dimensions without name?
-----------------------------------------------------
Imagine you have some charge, but not defined a subtype Charge.

   Q: CGS_Gauss := 40.0 * cm**(3/2)*g**(1/2)/s;  -- ???

This fails with
   dimensions mismatch in object declaration
   object type is dimensionless
   object expression has dimensions (3/2, 1/2, -1)

It's no problem to define the subtype

   subtype Charge is CGS_Gauss
     with Dimension => ("esu",
                        Centimeter => 3/2,
                        Gram       => 1/2,
                        Second     => -1);

and then write

   Q: Charge := 40.0 * cm**(3/2)*g**(1/2)/s;

but it is often the case that some intermediate value has to be stored
with an unnamed dimension. Very inconvenient if you have to locally
define a subtype for this.

** Dimension should be taken from the initial expression! **

2. Obviously GNAT can handle fractional dimensions.
---------------------------------------------------
This is very comfortable.

  Q: Charge := 40.0 * cm**(3/2)*g**(1/2)/s;
  R: Length := 10.0 * cm;
  
  Put (Q**2/R**2   , Aft => 2, Exp => 0);                    New_Line;
  Put (Q**2/R**2   , Aft => 2, Exp => 0, Symbols => "dyn");  New_Line;
  Put ((Q/R)**(5/7), Aft => 2, Exp => 0);                    New_Line;

  16.00 cm.g.s**(-2)
   2.69 cm**(5/14).g**(5/14).s**(-5/7)

However, I cannot find where

   function (Left: Dim_Type; Right: Rational) return Dim_Type;

is defined, let alone the type Rational.

The definition of Rational is flawed.

Don't write

  (8.0*cm)**(1/3+2/3)

this has the value 1. This, howver, is correct:

  (8.0*cm)**((1+2)/(5-2)) = 8.0*cm

(Admittedly, who would write such nonsense? Dimension checking is only done
for static expressions.)

Ahem - be careful:

  8.0**(1/3)     = 1
  8.0**(1/3)*cm  = 2.0*cm
 (8.0*cm)**(1/3) = 2.0*cm**(1/3)

You need a dimensioned value to give the correct result:

  One: constant CGS_Gauss := 1.0;  -- dimension 1, i.e. "dimensionless"
  8.0**(1/3)*One = 2.0

(In SI, results never have fractional dimensions, but intermediate values
may. So this is important also for SI.)

3. System.Dim.Float_IO is only output.
--------------------------------------
Values are correctly output with their dimension, very nice.

However, the name Float_IO is a lie, there is no dimensional input.

Input would be hard to achieve with the output syntax as produced now because
how to determine whether a dimension to read follows a number or not since
there is a separating space. We would need a multiplication sign instead.

  Put (Q**2/R**2, Aft => 2, Exp => 0);

results in

  16.00 cm.g.s**(-2)                     <=== How to read this back in?

Also the exponent in an output like 1.0 m**2.s could be taken as the
floating point number 2.0 when trying to read it in again (in input, missing
fore or aft is allowed).

Compare with

  16.00*cm.g.s**(-2)                     <=== This is dimensioned.

So checking the input for syntactic and semantic correctness is not easy.

Adding a symbol for the output is not checked! You can write any nonsense.

  Put (Q**2/R**2, Aft => 2, Exp => 0, Symbols => "dyn");  New_Line;
  Put (Q**2/R**2, Aft => 2, Exp => 0, Symbols => "m/s");  New_Line;
  16.00dyn                               <=== space missing (dyn undefined)!
  16.00m/s                               <=== nonsense!

  R: Length := 10.0 * cm;
  Put (R, Aft => 2, Exp => 0);                   New_Line;
  Put (R, Aft => 2, Exp => 0, Symbols => "km");  New_Line;
  10.00 cm                               <=== OK
  10.00km                                <=== Surprise, surprise!

This behaviour is apt to lead to confusion and program bugs!

4. Mathematics is included!
===========================

   package Math is new Ada.Numerics.Generic_Elementary_Functions (CGS_Gauss);
   use Math;

Any function requires dimensionless parameters and returns a dimensionless
result, except Sqrt, which correcly calculates the root of the dimension.

However:

  function Sin (X, Cycle : Float_Type'Base) return Float_Type'Base;

(Cos, Tan, Cot) should allow dimensioned parameters when both have the same
dimension.

  function Arcsin (X, Cycle : Float_Type'Base) return Float_Type'Base;

(Arccos) should request X dimensionless and the return value should be
dimensioned like Cycle.

   function Arctan (Y: Float_Type'Base;
                    X: Float_Type'Base := 1.0[;
                    Cycle : Float_Type'Base]) return Float_Type'Base;

(Arccot) should allow X and Y with the same dimension [and be dimensioned
like Cycle].

------------------------------------------

Any thoughts, other nice features or awkward shortcomings?



  parent reply	other threads:[~2012-07-06 10:47 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-01  5:53 GNAT and Dimension Checking AdaMagica
2012-07-01  6:25 ` Nasser M. Abbasi
2012-07-01 10:44   ` yogeshwarsing
2012-07-02 20:42     ` Anh Vo
2012-07-02 20:58       ` Adam Beneschan
2012-07-02 21:51         ` Anh Vo
2012-07-01 15:18 ` AdaMagica
2012-07-01 15:47   ` yogeshwarsing
2012-07-06 10:47 ` AdaMagica [this message]
2012-07-08  1:50   ` Robert A Duff
2012-07-08 10:33 ` AdaMagica
2012-07-08 11:37   ` Dmitry A. Kazakov
2012-07-08 14:13     ` AdaMagica
2012-07-08 18:47   ` Jacob Sparre Andersen
2012-07-09 11:06     ` AdaMagica
2012-07-09  8:20   ` Martin
2012-07-09 11:19     ` AdaMagica
replies disabled

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