From: si-units-list@si-units (si-units-digest)
To: si-units-digest@si-units
Subject: si-units-digest V1 #15
Reply-To: si-units-list@si-units
Sender: si-units-list@si-units
Errors-To: si-units-list@si-units
Precedence: bulk
si-units-digest Friday, April 4 2003 Volume 01 : Number 015
In this issue:
RE: SI Units Project: [Fwd: ACCU SI -- printing]
Re: SI Units Project: [Fwd: ACCU SI -- printing]
Re: SI Units Project: [Fwd: ACCU SI -- printing]
RE: SI Units Project: [Fwd: ACCU SI -- printing]
Re: SI Units Project: [Fwd: ACCU SI -- printing]
RE: SI Units Project: [Fwd: ACCU SI -- printing]
----------------------------------------------------------------------
Date: Mon, 10 Mar 2003 10:50:50 -0000
From: "Watts, Simon (UK)"
Subject: RE: SI Units Project: [Fwd: ACCU SI -- printing]
> From: Pete and Lana Klier [mailto:klierz@si-units]
> From what I am gathering about possible designs for printing the units, we
are
> essentially considering 2 algorithms, and possibly a blend of them. I
would
> call these "history" based and "state" based. But I'm not certain where
exactly
> we are drawing the line between them, so we should probably have some kind
of
> pseudocode algorithm to see where we are going. (apologies for American
spelling)
I think that the system I have been considering is somewhere in between
these two. I do keep the composition history as a binary tree in the
template dimension trait of a unit, such that (abreviating heavily):
U * U => U>
U / U => U> // '1/D' provided by a typedef in D
With a few leaf dimensions (for dimensionless, and the SI basis dimensions).
Although I suspect that any implementation would have to end up being a
hybred method in practice, apart from explicit display types:
cout << (newton_metres) (4.0 * kilogram * metre * metre / (second *
second ))
<< endl;
> ---------- history-based system ----------
>
> cout << 4.0 * kilogram * meter * meter / (second * second) << endl;
> cout << 4.0 * newton * meter << endl;
> would print
> 4.0 kilogram meters^2 per second^2
> 4.0 newton meters
> exactly the way the units had been input.
This could only be done based on the type of the argument. In the first
case, this is (M=mass, L=lebgth, T=time):
U * U * U / ( U * U )
=> U> * U / U>
=> U>,L>> / U>
=> U< D>,L>,D> >
And the second case (F=force):
U * U
=> U>
Clearly, the two unit types here are distinct and unrelated. However, the
force dimesion will have been defined in terms of the basis dimensions, for
example, mass times acceleration, where accel is velocity / time, and
velocity is length/time:
F => D,1/T>>
If the first example was reordered such that the resultant type was:
U< D< D,1/T>>, L>>
then it is indistinguishable from the second, and will produce the same
results.
OK, in this case the expression would have to be:
cout << 4.0 * kilogram * metre / second / second * metre << endl;
However, whatever ordering is used, given the large number of possible
derived types in play, there is a chance that some sub-tree of the history
will match an existing named dimension/unit and produce an 'unexpected'
representation.
Furthermore, the unexpected representation may also be misleading, as some
unit types do not have distinct dimensions, but can be distinguished by
unique composition histories. My usual examples are
DIMENSIONLESS DIMENSIONS:
dimensionless_d (fundamental) == 0
angle_d => D (radians)
solid_angle_d => D (A==D) (steradians)
INVERSE TIME DIMENSIONS
frequency_d => D<1/T,0> (hertz)
activity_d => D<0,1/T> (becquerels)
(I will have to change the definitions of frequency_d and activity_d, since
I thing that we should be able to say D == D**).
The history system would require that, given a dimension D, we can
either locate a corresponding Symbol (matching either D _or_ D****),
and add it to the list to be displayed, or recurse into A and B if no match
is found.
> ----------------- state-based system ----------------
>
> In this system, all we care about are the units, *not* what the user
> has typed in. Thus,
> 1/sec would always print as "hertz" and kg-m^2 / sec^2 might always
> print as Newton-meters.
But what about 1/sec also being "becquerel"?... Same dimension, different
meaning:
Activity a = 10.0 * becquerel; // Discrete events, Dim: 1/T
Frequency f = 100.0 * hertz; // Periodicity, Dim: 1/T
cout << a << "\n" << f << "\n" << a/f << endl;
Want this to give:
10.0 Bq
100.0 Hz
0.1 Bq / Hz
Similarly with planar angles and solid angles, both dimensionless
quantities.
> Thus, one might postulate an algorithm such as the following (focusing
> on those units with integer powers for the time being):
>
>
> let U = the units of the input variable.
>
> let OUTPUT = {};
>
> while (! done (U))
> {
> Let U' = the closest match to U from a prioritized list of named
> types (i.e. Newtons, volts, ...)
> OUTPUT = OUTPUT + U';
> U = U - U';
> }
>
> print OUTPUT
This is a route I was considering before I shifted to a more history based
approach. If you like, the meta-prog constructs for doing the maths on the
dimension vectors are still in the 'units::meta' namespace of my code: See
DSPLIT, DSUB, DDOT [1].
References
[1] http://homepage.ntlworld.com/sawatts/projects/
Right, back to work...
Si.
------------------------------
Date: Sun, 16 Mar 2003 10:44:49 -0800
From: Pete and Lana Klier
Subject: Re: SI Units Project: [Fwd: ACCU SI -- printing]
I'll chew on this while traveling on business again... sorry I got flooded with
e-mails last week.
Watts, Simon (UK) wrote:
> > From: Pete and Lana Klier [mailto:klierz@si-units]
>
> > From what I am gathering about possible designs for printing the units, we
> are
> > essentially considering 2 algorithms, and possibly a blend of them. I
> would
> > call these "history" based and "state" based. But I'm not certain where
> exactly
> > we are drawing the line between them, so we should probably have some kind
> of
> > pseudocode algorithm to see where we are going. (apologies for American
> spelling)
>
> I think that the system I have been considering is somewhere in between
> these two. I do keep the composition history as a binary tree in the
> template dimension trait of a unit, such that (abreviating heavily):
>
> U * U => U>
> U / U => U> // '1/D' provided by a typedef in D
>
> With a few leaf dimensions (for dimensionless, and the SI basis dimensions).
>
> Although I suspect that any implementation would have to end up being a
> hybred method in practice, apart from explicit display types:
> cout << (newton_metres) (4.0 * kilogram * metre * metre / (second *
> second ))
> << endl;
>
> > ---------- history-based system ----------
> >
> > cout << 4.0 * kilogram * meter * meter / (second * second) << endl;
> > cout << 4.0 * newton * meter << endl;
> > would print
> > 4.0 kilogram meters^2 per second^2
> > 4.0 newton meters
> > exactly the way the units had been input.
>
> This could only be done based on the type of the argument. In the first
> case, this is (M=mass, L=lebgth, T=time):
> U * U * U / ( U * U )
> => U> * U / U>
> => U>,L>> / U>
> => U< D>,L>,D> >
>
> And the second case (F=force):
> U * U
> => U>
>
> Clearly, the two unit types here are distinct and unrelated. However, the
> force dimesion will have been defined in terms of the basis dimensions, for
> example, mass times acceleration, where accel is velocity / time, and
> velocity is length/time:
>
> F => D,1/T>>
>
> If the first example was reordered such that the resultant type was:
> U< D< D,1/T>>, L>>
> then it is indistinguishable from the second, and will produce the same
> results.
>
> OK, in this case the expression would have to be:
>
> cout << 4.0 * kilogram * metre / second / second * metre << endl;
>
> However, whatever ordering is used, given the large number of possible
> derived types in play, there is a chance that some sub-tree of the history
> will match an existing named dimension/unit and produce an 'unexpected'
> representation.
>
> Furthermore, the unexpected representation may also be misleading, as some
> unit types do not have distinct dimensions, but can be distinguished by
> unique composition histories. My usual examples are
>
> DIMENSIONLESS DIMENSIONS:
> dimensionless_d (fundamental) == 0
> angle_d => D (radians)
> solid_angle_d => D (A==D) (steradians)
>
> INVERSE TIME DIMENSIONS
> frequency_d => D<1/T,0> (hertz)
> activity_d => D<0,1/T> (becquerels)
>
> (I will have to change the definitions of frequency_d and activity_d, since
> I thing that we should be able to say D == D****).
>
> The history system would require that, given a dimension D, we can
> either locate a corresponding Symbol (matching either D _or_ D****),
> and add it to the list to be displayed, or recurse into A and B if no match
> is found.
>
>
> > ----------------- state-based system ----------------
> >
> > In this system, all we care about are the units, *not* what the user
> > has typed in. Thus,
> > 1/sec would always print as "hertz" and kg-m^2 / sec^2 might always
> > print as Newton-meters.
>
> But what about 1/sec also being "becquerel"?... Same dimension, different
> meaning:
>
> Activity a = 10.0 * becquerel; // Discrete events, Dim: 1/T
> Frequency f = 100.0 * hertz; // Periodicity, Dim: 1/T
> cout << a << "\n" << f << "\n" << a/f << endl;
>
> Want this to give:
> 10.0 Bq
> 100.0 Hz
> 0.1 Bq / Hz
>
> Similarly with planar angles and solid angles, both dimensionless
> quantities.
>
>
> > Thus, one might postulate an algorithm such as the following (focusing
> > on those units with integer powers for the time being):
> >
> >
> > let U = the units of the input variable.
> >
> > let OUTPUT = {};
> >
> > while (! done (U))
> > {
> > Let U' = the closest match to U from a prioritized list of named
> > types (i.e. Newtons, volts, ...)
> > OUTPUT = OUTPUT + U';
> > U = U - U';
> > }
> >
> > print OUTPUT
>
> This is a route I was considering before I shifted to a more history based
> approach. If you like, the meta-prog constructs for doing the maths on the
> dimension vectors are still in the 'units::meta' namespace of my code: See
> DSPLIT, DSUB, DDOT [1].
>
> References
> [1] http://homepage.ntlworld.com/sawatts/projects/
>
> Right, back to work...
>
> Si.
------------------------------
Date: Sun, 23 Mar 2003 19:55:44 -0800
From: Pete and Lana Klier
Subject: Re: SI Units Project: [Fwd: ACCU SI -- printing]
Well, my business travel happened to be to Denver -- in case you didn't hear, there
was
a lot of shoveling involved, which my day job has prepared me for quite adequately.
I finally got to talk to my local domain expert; we pretty much agreed that a
state-based
approach is preferable. I think it's a little simpler and easier to implement (at
least as a
run-time algorithm, but I'm sure that Simon's has tricks up his sleeve to make it
into a compile-time one,
I have some vague idea of how to do it).
A couple of simple examples, but as things get more and more complicated we thought
that the
same kind of reasoning would apply (c = speed of light, g = acceleration due to
gravity;
m in units of kg, t in units of sec, a in units of acceleration, yatta yatta)
cout << m * c * c << endl;
my domain expert tells me that the preferable print units for the above are
"joules."
cout << 0.5 * a * t * t << endl;
preferred units are "meters"
cout << n * m << endl;
(n in newtons)
preferred units are "joules"
cout << n * t << endl;
preferred units might be "newton-seconds" if no such 'base' unit actually exists.
An algorithm that does this (at run-time, compile-time might require more magic, so
there might
be some prototyping involved) would probably be fairly simple; just find the best
match in the
prioritized list of units with official names, divide out the remainder, and
recurse (or do a smarter
search, it may require some playing).
For the Hertz vs. Becquerel thing, this is probably just a matter of localization:
Naturally a parameter
to the algorithm would be the list of units with names, along with their localized
names. This is more
or less a given. A localized UK package versus a US package (versus German, Czech,
whatever...) would
take care of that.
In any case, it would be nice to take a stab at state-based first. Run-time first,
perhaps.
If we have any disagreements, would anyone care to vote?
Pete and Lana Klier wrote:
> I'll chew on this while traveling on business again... sorry I got flooded with
> e-mails last week.
>
> Watts, Simon (UK) wrote:
>
> > > From: Pete and Lana Klier [mailto:klierz@si-units]
> >
> > > From what I am gathering about possible designs for printing the units, we
> > are
> > > essentially considering 2 algorithms, and possibly a blend of them. I
> > would
> > > call these "history" based and "state" based. But I'm not certain where
> > exactly
> > > we are drawing the line between them, so we should probably have some kind
> > of
> > > pseudocode algorithm to see where we are going. (apologies for American
> > spelling)
> >
> > I think that the system I have been considering is somewhere in between
> > these two. I do keep the composition history as a binary tree in the
> > template dimension trait of a unit, such that (abreviating heavily):
> >
> > U * U => U>
> > U / U => U> // '1/D' provided by a typedef in D
> >
> > With a few leaf dimensions (for dimensionless, and the SI basis dimensions).
> >
> > Although I suspect that any implementation would have to end up being a
> > hybred method in practice, apart from explicit display types:
> > cout << (newton_metres) (4.0 * kilogram * metre * metre / (second *
> > second ))
> > << endl;
> >
> > > ---------- history-based system ----------
> > >
> > > cout << 4.0 * kilogram * meter * meter / (second * second) << endl;
> > > cout << 4.0 * newton * meter << endl;
> > > would print
> > > 4.0 kilogram meters^2 per second^2
> > > 4.0 newton meters
> > > exactly the way the units had been input.
> >
> > This could only be done based on the type of the argument. In the first
> > case, this is (M=mass, L=lebgth, T=time):
> > U * U * U / ( U * U )
> > => U> * U / U>
> > => U>,L>> / U>
> > => U< D>,L>,D> >
> >
> > And the second case (F=force):
> > U * U
> > => U>
> >
> > Clearly, the two unit types here are distinct and unrelated. However, the
> > force dimesion will have been defined in terms of the basis dimensions, for
> > example, mass times acceleration, where accel is velocity / time, and
> > velocity is length/time:
> >
> > F => D,1/T>>
> >
> > If the first example was reordered such that the resultant type was:
> > U< D< D,1/T>>, L>>
> > then it is indistinguishable from the second, and will produce the same
> > results.
> >
> > OK, in this case the expression would have to be:
> >
> > cout << 4.0 * kilogram * metre / second / second * metre << endl;
> >
> > However, whatever ordering is used, given the large number of possible
> > derived types in play, there is a chance that some sub-tree of the history
> > will match an existing named dimension/unit and produce an 'unexpected'
> > representation.
> >
> > Furthermore, the unexpected representation may also be misleading, as some
> > unit types do not have distinct dimensions, but can be distinguished by
> > unique composition histories. My usual examples are
> >
> > DIMENSIONLESS DIMENSIONS:
> > dimensionless_d (fundamental) == 0
> > angle_d => D (radians)
> > solid_angle_d => D (A==D) (steradians)
> >
> > INVERSE TIME DIMENSIONS
> > frequency_d => D<1/T,0> (hertz)
> > activity_d => D<0,1/T> (becquerels)
> >
> > (I will have to change the definitions of frequency_d and activity_d, since
> > I thing that we should be able to say D == D****).
> >
> > The history system would require that, given a dimension D, we can
> > either locate a corresponding Symbol (matching either D _or_ D****),
> > and add it to the list to be displayed, or recurse into A and B if no match
> > is found.
> >
> >
> > > ----------------- state-based system ----------------
> > >
> > > In this system, all we care about are the units, *not* what the user
> > > has typed in. Thus,
> > > 1/sec would always print as "hertz" and kg-m^2 / sec^2 might always
> > > print as Newton-meters.
> >
> > But what about 1/sec also being "becquerel"?... Same dimension, different
> > meaning:
> >
> > Activity a = 10.0 * becquerel; // Discrete events, Dim: 1/T
> > Frequency f = 100.0 * hertz; // Periodicity, Dim: 1/T
> > cout << a << "\n" << f << "\n" << a/f << endl;
> >
> > Want this to give:
> > 10.0 Bq
> > 100.0 Hz
> > 0.1 Bq / Hz
> >
> > Similarly with planar angles and solid angles, both dimensionless
> > quantities.
> >
> >
> > > Thus, one might postulate an algorithm such as the following (focusing
> > > on those units with integer powers for the time being):
> > >
> > >
> > > let U = the units of the input variable.
> > >
> > > let OUTPUT = {};
> > >
> > > while (! done (U))
> > > {
> > > Let U' = the closest match to U from a prioritized list of named
> > > types (i.e. Newtons, volts, ...)
> > > OUTPUT = OUTPUT + U';
> > > U = U - U';
> > > }
> > >
> > > print OUTPUT
> >
> > This is a route I was considering before I shifted to a more history based
> > approach. If you like, the meta-prog constructs for doing the maths on the
> > dimension vectors are still in the 'units::meta' namespace of my code: See
> > DSPLIT, DSUB, DDOT [1].
> >
> > References
> > [1] http://homepage.ntlworld.com/sawatts/projects/
> >
> > Right, back to work...
> >
> > Si.
------------------------------
Date: Tue, 25 Mar 2003 12:33:14 -0000
From: "Watts, Simon (UK)"
Subject: RE: SI Units Project: [Fwd: ACCU SI -- printing]
> From: Pete and Lana Klier [mailto:klierz@si-units]
Time for a lunchtime muse and commentary on P&L's last posting...
> cout << m * c * c << endl;
> "joules."
Tricky. In my current system, there are two meta descriptors attached to a
unit -- the dimension_trait being the binary tree describing how the units
dimension was derived, and the dimension_vector, which is the set of basis
coefficients (and is contained in the dimension_trait).
Using the trait allows us to distinguish between units with the same basic
coefficients, but from different problem domains (this is most significant
when dealing with angles, which are otherwise dimensionless). While the
vector is used for dimensional analysis in determining whether an operation
exists (cannot do metre+second for instance).
In the example, 'm*c*c' gives the same dimension coefficients as power
(joules), but the trait is governed by how the operations took place. In
this case:
< < M , c >, c >, where c is presumable < L, 1/T >
This is unlikely to be the chosen dimension_trait for power.
In chosing how to compose the symbols for a unit, an algorithm has available
both the trait and the vector, as well being able to recurse down the trait
tree.
A simple algorithm would be:
1. try to match the trait, or
2. try to match the vector, or
3. recurse into the components of the trait and repeat and
accumulate.
However, this would fail on some units:
cout << radian / second << endl;
The resultant here has trait:
< ANGLE, 1/T > == < , 1/T >
And vector:
[ T=-1 ]
What we would like to see is 'rad / s'. What the simple algorithm gives is
probably 'Hz'.
Skipping step (2) would give 'rad / s', since frequency, 'Hz', will have
been defined as < 1/T, 0 > or similar, and not match the basis of inverse-T.
But then again, skipping (2) would fail to produce the desired output for
the example!
Remember though, that there is always typecasing:
cout << Power (m * c * c) << endl;
is guarenteed to match the dimension_trait for power.
> cout << 0.5 * a * t * t << endl;
> preferred units are "meters"
Easy one - since the dimensions cancel down to the basis dimension of
length.
> cout << n * m << endl;
> (n in newtons)
> preferred units are "joules"
As the first example.
> cout << n * t << endl;
> preferred units might be "newton-seconds" if no such 'base'
> unit actually exists.
Should be able to do this one unambiguously, since the composite parts of
the resultants dimension should exist in the list-of-symbols.
The only issue is to decide on the display order: N s or s N ? What
criterial to use? The most derived first? SI implies positive powers
before negative, but doesnt help other than that. There are reasons to sort
lower-magnitude powers first (SI prefix binding), but that doesnt help here
(in fact, while there should only be one SI prefix used in a compound
symbol, it doesnt have to be on the first one).
Gets me thinking that there should be some sorting-order including in the
definition of the dimension traits, so that at least we will always get a
consistent ordering: 'n*t' and 't*n' both giving the same symbol 'N s' for
instance, rather than 'N s' and 's N'.
> An algorithm that does this (at run-time, compile-time might require more
magic, so
> there might be some prototyping involved) would probably be fairly
> simple; just find the best match in the
> prioritized list of units with official names, divide out the remainder,
and
> recurse (or do a smarter search, it may require some playing).
I think that a purely-compile time method is not possible, though we can
squeeze as much information as possible out during compilation. The problem
is that there are runtime decisions as to how to display units -- such as
what symbol set to use, through stream manipulators:
cout << units::si::sym << 1.0 * metre * c * c << endl;
cout << units::cgi::sym << 1.0 * metre * c * c << endl;
Where 'sym' is a stream manipulator to set the symbols used, so in the first
case it would display the result in joules, in the second case in, maybe,
ergs.
> For the Hertz vs. Becquerel thing, this is probably just a
> matter of localization:
I would disagree here. There is no localization issue with Hz vs Bq, they
are both distinct derived units in the SI system, and therefore need to be
distinct in our system. A similar argument can be placed for dimensionless
units ('1') and angles (radians and steradians). And when you include the
"Non-SI units accepted for use with [SI]", there is neper ('Np',
dimensionless), and bel, ('B'), defined as (1/2)ln10 (Np)! ...those will be
fun to sort out (actually, just a case of overloading log() -- I dont think
that I have overloaded the std maths functions for units yet).
> Naturally a parameter to the algorithm would be the list of units with
names, along
> with their localized names. This is more
> or less a given. A localized UK package versus a US package (versus
German, Czech,
> whatever...) would take care of that.
There are localisation issues, which I have been considering. There are two
catagories here:
1. Localised unit sets, such as US or British traditional, Japanese
etc. For a big list of interesting and obsure traditional units see:
http://www.unc.edu/~rowlett/units/index.html
Personally, I would see these as being defined in their own
namespaces; for example:
units -- top level units namespace
units::si -- SI units namespace; kilogram, metre, etc.
units::cgi -- cgi units; ergs, centimetre, etc.
units::[locale] -- trad. units for locale
As to what to use for 'locale' depends on whether we view this as a
language or geographic division (or combination). Could use the locale
codes, eg 'en_GB', or the ISO country codes. However, they must always be
distinct from any international standard units sets (si, cgi,...). Mayby a
prefix or sub namespace?
While we are not going to provide any localise units, it would be
useful to specify the minimum requirements for the contents of any such
namespace.
2. On top of this is localisation of names. SI defines unit symbols
explicitly, so 'm' is always the symbol for metres, wherever you are. The
unit names are subject to localisation: metre, meter, metr, metras, metri,
metro...
It would be nice to delegate this to the message catalogue support
in the STL; this is documented, a bit, in Langer's book, but seems to be a
less-well thought out part of the STL. The GNU C++ library supports this by
wrapping gettext library (as far as I can tell).
There is a third issue which may be grouped with general localisation, which
is that of the problem domain. I am thinking mainly here about definitions
of fundamental constants, but there may also be specialised unit types and
treatments. It is probably sufficient to have these in seperate headers,
defined within the existing namespaces, for use as-and-when.
Si.
------------------------------
Date: Wed, 26 Mar 2003 21:30:03 -0800
From: Pete and Lana Klier
Subject: Re: SI Units Project: [Fwd: ACCU SI -- printing]
I propose that we do the different approaches in parallel, and then
take them for a test drive. I'd like to get some hacking in myself,
so I'll try the state-based approach and test the more tree-based
methodology described below.
I really want to get something out the door, so no point in endless
debates!
Let me know if anyone has any objections -- also comments
from the field welcome.
Watts, Simon (UK) wrote:
> > From: Pete and Lana Klier [mailto:klierz@si-units]
>
> Time for a lunchtime muse and commentary on P&L's last posting...
>
>
> > cout << m * c * c << endl;
> > "joules."
>
> Tricky. In my current system, there are two meta descriptors attached to a
> unit -- the dimension_trait being the binary tree describing how the units
> dimension was derived, and the dimension_vector, which is the set of basis
> coefficients (and is contained in the dimension_trait).
>
> Using the trait allows us to distinguish between units with the same basic
> coefficients, but from different problem domains (this is most significant
> when dealing with angles, which are otherwise dimensionless). While the
> vector is used for dimensional analysis in determining whether an operation
> exists (cannot do metre+second for instance).
>
> In the example, 'm*c*c' gives the same dimension coefficients as power
> (joules), but the trait is governed by how the operations took place. In
> this case:
>
> < < M , c >, c >, where c is presumable < L, 1/T >
>
> This is unlikely to be the chosen dimension_trait for power.
>
> In chosing how to compose the symbols for a unit, an algorithm has available
> both the trait and the vector, as well being able to recurse down the trait
> tree.
>
> A simple algorithm would be:
> 1. try to match the trait, or
> 2. try to match the vector, or
> 3. recurse into the components of the trait and repeat and
> accumulate.
>
> However, this would fail on some units:
>
> cout << radian / second << endl;
>
> The resultant here has trait:
> < ANGLE, 1/T > == < , 1/T >
> And vector:
> [ T=-1 ]
>
> What we would like to see is 'rad / s'. What the simple algorithm gives is
> probably 'Hz'.
>
> Skipping step (2) would give 'rad / s', since frequency, 'Hz', will have
> been defined as < 1/T, 0 > or similar, and not match the basis of inverse-T.
>
> But then again, skipping (2) would fail to produce the desired output for
> the example!
>
> Remember though, that there is always typecasing:
>
> cout << Power (m * c * c) << endl;
>
> is guarenteed to match the dimension_trait for power.
>
>
> > cout << 0.5 * a * t * t << endl;
> > preferred units are "meters"
>
> Easy one - since the dimensions cancel down to the basis dimension of
> length.
>
>
>
> > cout << n * m << endl;
> > (n in newtons)
> > preferred units are "joules"
>
> As the first example.
>
> > cout << n * t << endl;
> > preferred units might be "newton-seconds" if no such 'base'
> > unit actually exists.
>
> Should be able to do this one unambiguously, since the composite parts of
> the resultants dimension should exist in the list-of-symbols.
>
> The only issue is to decide on the display order: N s or s N ? What
> criterial to use? The most derived first? SI implies positive powers
> before negative, but doesnt help other than that. There are reasons to sort
> lower-magnitude powers first (SI prefix binding), but that doesnt help here
> (in fact, while there should only be one SI prefix used in a compound
> symbol, it doesnt have to be on the first one).
>
> Gets me thinking that there should be some sorting-order including in the
> definition of the dimension traits, so that at least we will always get a
> consistent ordering: 'n*t' and 't*n' both giving the same symbol 'N s' for
> instance, rather than 'N s' and 's N'.
>
> > An algorithm that does this (at run-time, compile-time might require more
> magic, so
> > there might be some prototyping involved) would probably be fairly
> > simple; just find the best match in the
> > prioritized list of units with official names, divide out the remainder,
> and
> > recurse (or do a smarter search, it may require some playing).
>
> I think that a purely-compile time method is not possible, though we can
> squeeze as much information as possible out during compilation. The problem
> is that there are runtime decisions as to how to display units -- such as
> what symbol set to use, through stream manipulators:
>
> cout << units::si::sym << 1.0 * metre * c * c << endl;
> cout << units::cgi::sym << 1.0 * metre * c * c << endl;
>
> Where 'sym' is a stream manipulator to set the symbols used, so in the first
> case it would display the result in joules, in the second case in, maybe,
> ergs.
>
> > For the Hertz vs. Becquerel thing, this is probably just a
> > matter of localization:
>
> I would disagree here. There is no localization issue with Hz vs Bq, they
> are both distinct derived units in the SI system, and therefore need to be
> distinct in our system. A similar argument can be placed for dimensionless
> units ('1') and angles (radians and steradians). And when you include the
> "Non-SI units accepted for use with [SI]", there is neper ('Np',
> dimensionless), and bel, ('B'), defined as (1/2)ln10 (Np)! ...those will be
> fun to sort out (actually, just a case of overloading log() -- I dont think
> that I have overloaded the std maths functions for units yet).
>
> > Naturally a parameter to the algorithm would be the list of units with
> names, along
> > with their localized names. This is more
> > or less a given. A localized UK package versus a US package (versus
> German, Czech,
> > whatever...) would take care of that.
>
> There are localisation issues, which I have been considering. There are two
> catagories here:
>
> 1. Localised unit sets, such as US or British traditional, Japanese
> etc. For a big list of interesting and obsure traditional units see:
> http://www.unc.edu/~rowlett/units/index.html
> Personally, I would see these as being defined in their own
> namespaces; for example:
> units -- top level units namespace
> units::si -- SI units namespace; kilogram, metre, etc.
> units::cgi -- cgi units; ergs, centimetre, etc.
> units::[locale] -- trad. units for locale
> As to what to use for 'locale' depends on whether we view this as a
> language or geographic division (or combination). Could use the locale
> codes, eg 'en_GB', or the ISO country codes. However, they must always be
> distinct from any international standard units sets (si, cgi,...). Mayby a
> prefix or sub namespace?
> While we are not going to provide any localise units, it would be
> useful to specify the minimum requirements for the contents of any such
> namespace.
>
> 2. On top of this is localisation of names. SI defines unit symbols
> explicitly, so 'm' is always the symbol for metres, wherever you are. The
> unit names are subject to localisation: metre, meter, metr, metras, metri,
> metro...
> It would be nice to delegate this to the message catalogue support
> in the STL; this is documented, a bit, in Langer's book, but seems to be a
> less-well thought out part of the STL. The GNU C++ library supports this by
> wrapping gettext library (as far as I can tell).
>
> There is a third issue which may be grouped with general localisation, which
> is that of the problem domain. I am thinking mainly here about definitions
> of fundamental constants, but there may also be specialised unit types and
> treatments. It is probably sufficient to have these in seperate headers,
> defined within the existing namespaces, for use as-and-when.
>
> Si.
------------------------------
Date: Fri, 4 Apr 2003 13:48:16 +0100
From: "Watts, Simon (UK)"
Subject: RE: SI Units Project: [Fwd: ACCU SI -- printing]
> From: Pete and Lana Klier [mailto:klierz@si-units]
> I propose that we do the different approaches in parallel, and then
> take them for a test drive. I'd like to get some hacking in myself,
> so I'll try the state-based approach and test the more tree-based
> methodology described below.
> I really want to get something out the door, so no point in endless
> debates!
Ditto, when I finally get some free time!...
One thought though -- I don't think we should get too distracted by trying
to make the printing system get things -just-right-. The user will always
be free to apply an explicit casting to the desired type if the
symbol-to-dimensions mapping is not to their statisfaction:
cout << (Power) (1.2 * newton * metre) << endl;
And I don't think that printing out answers with undetermined units is going
to be a common requirement (after all, part of the purpose of this class
system is to enforce proper dimensional analysis on calculations).
What may be useful is to allow a user to define a symbol to be used to
display their own dimension. This is distinct from symbols for unit-sets
(SI, localised etc), which can be selected with a stream manipulator. Say,
have the user symbol used for the lifetime of its object:
using namespace std;
using namespace units;
// define problem-specific unit, the Flubble:
typedef Dimension flubble_d;
typedef Unit Flubble;
// define the unit vector for the flubble (expressed in SI)
const Flubble flubble (1.234);
void foo (const Flubble& val)
{
/* define a generic symbol for the flubble, active within its
* lifetime only -- user list searched first, before applied
* package list. Parameterized by the unit vector (template
* ctor), symbol string and name string.
Symbol flubble_sym (flubble, "ff", "flubble");
cout << "foo: " << val << endl;
}
int main ()
{
Flubble ff = 2 * flubble;
// apply SI units to the stream
cout << si::sym;
foo (ff);
cout << "main: " << ff << endl;
}
The output should (may) be:
foo: 2 ff
main: 2.468 m kg
Si.
------------------------------
End of si-units-digest V1 #15
*****************************
**