From: si-units-list@si-units (si-units-digest)
To: si-units-digest@si-units
Subject: si-units-digest V1 #19
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 Saturday, July 12 2003 Volume 01 : Number 019
In this issue:
SI Units Project: Test message, ignore
RE: SI Units Project: Test message, ignore
SI Units Project: Celsius scale (etc)
SI Units Project: mkserror.cc
SI Units Project: mksconstraints.h
SI Units Project: mksmeasure.h (for compiler errors)
SI Units Project: compiler output
SI Units Project: Getting closer...
[Fwd: SI Units Project: Celsius scale (etc)]
----------------------------------------------------------------------
Date: Sun, 06 Jul 2003 17:25:37 -0700
From: Pete and Lana Klier
Subject: SI Units Project: Test message, ignore
test message
------------------------------
Date: Mon, 7 Jul 2003 08:38:04 +0100
From: "Watts, Simon (UK)"
Subject: RE: SI Units Project: Test message, ignore
Unit test message?
Things have been quiet here for a while. I do intend to get back and finish
off my version of the printing scheme -- but need to get a new monitor for
the pc, which is next in the queue after either a new engine or a
replacement car!
Having some thoughts on the representation of units and scales, for example
celsius. I'll post a seperate thread on that.
Si.
------------------------------
Date: Mon, 7 Jul 2003 09:36:57 +0100
From: "Watts, Simon (UK)"
Subject: SI Units Project: Celsius scale (etc)
I started doing a bit of a rework on my code a while back, including a small
terminology change (from previous discussions here):
"Quantity" to refer to the value classes, eg Temperature, Length, Mass are
all Quantity classes.
"Unit" to refer to the measurement units for quantities, eg, Kelvin, metre,
kilogram. These are constants for a particular system of units.
I am also toying with the concept of a "Scale", though this may merge with
"Unit". This has been discussed previously on this list, and I am just
trying to fit it into my model. Scales are needed to represent scales which
have a different origin to the internal SI system, for example Celsius.
The scale for Celsius would represent "273.15 + 1.0 T", where T is the
Celsius value. Its type would be something like "Scale".
Obviously, Unit and Scale can be merged when the offset is set to zero.
I did think about generalising this to an arbitary polynomial expression.
However, I cannot think of any practical systems which would require this,
and such expressions do not have a simple inverse, which I believe will be
an implicit requirement.
So the bit where this gets complicated is in the usage of scales in
expressions. This goes to the distinction between absolute values and
difference or delta values.
Consider the following expression:
Temperature t = 100.0 * celsius;
This can be interpreted as either a delta of +100.0 K, or an absolute value
of 373.15 K. OK, in this case probably the latter. But what about:
MyQuantity q = 100.0 * metre / celsius;
Here the intent is _probably_ to divide by the delta (1.0 K), and not "1.0 *
celsius = 273.15 K". So we have two uses.
And its not that simple, since we could write:
MyQuantity q = 200.0 * metre / (2.0 * celsius);
And expect the same thing as above.
The following expressions should be equivalent:
MyOtherQuantity z1 = 200.0 * metre * celsius;
MyOtherQuantity z2 = 200.0 * celsius * metre;
What is the intended use of celsius here? Delta or absolute?
I am currently leaning towards the following rule for dealing with scales,
although they do not cover every intent I havent thought of a better
approach:
Only multiplication or division _by_ a number
preserves the offset.
All other operations, the resultant offset is
set to zero.
Addition and subtraction require conversion to
a quantity.
So, if 'n' a number, and '(a,b)', '(c,d)' are scales:
n * (a,b) -> (a,nb)
(a,b) * n -> (a,nb)
(a,b) / n -> (a/n,b/n)
n / (a,b) -> (0,b/n)
(a,b)*(c,d) -> (0,bd)
(a,b)/(c,d) -> (0,b/d)
Now, there is the question of what to do when Quantities are thrown into the
mix. It may be sufficient to notionally convert the Quantity, 'q', to the
equivalent scale '(0,q)', and apply the rules above.
So, any counter examples?
Si.
------------------------------
Date: Fri, 08 Aug 2003 20:10:17 -0700
From: Pete and Lana Klier
Subject: SI Units Project: mkserror.cc
Here is some erroneous code:
- --------------------------- mkserror.cc ------------------------
// -*- compile-command: "g++ -o mkserror mkserror.cc" -*-
#include "mksmeasure.h"
#include "mksunity.h"
#include "mksuniconsts.h"
#include "mkstypes.h"
#include "mksdimensionless.h"
#include "mkspostfix.h"
#include "mksmuldiv.h"
#include
#include "mksconstants.h"
#include "mksio.h"
#warning This compilation is designed to give pretty errors
#warning not to actually run
int main(int argc, char **argv)
{
cout << "mks" << "\n";
dimensionless dim(6.0);
mksunity<1,0,0,0> a_meter;
meters mm = dim ( a_meter );
meters nn = dimensionless(6.0) ( a_meter );
#warning Mismatched initialization:
meters dist = 3.0E8 sec;
meters distx = 3.0E8 met;
#warning Mismatched assignment
distx = 3.0E8 sec;
kilograms m = 1.0 kg;
#warning Mismatched initialization after expression eval
joules mass_annihilated = m * c/*.square()*/;
seconds time2 = 42 sec;
meters dist2 = 24 met;
joules badtest = 6.5 J;
#warning Mismatched assignment after expression eval
badtest = m * dist2.square() / time2/*.square()*/;
#warning Mistmached +, no left-hand-side
(1000.0 W) + (120.0 V);
#warning Mismatched "-" with initialization
joules kilowatt_hour = (1000.0 W) - (3600.0 sec);
kilowatt_hour += (360.0 sec)
ohms hair_dryer_ohms = 7.3 Ohms; // OK
#warning Mismatched "?" with initialization
hair_dryer_ohms = (120.0 sec) / hair_dryer ;
return 0;
}
------------------------------
Date: Fri, 08 Aug 2003 20:11:28 -0700
From: Pete and Lana Klier
Subject: SI Units Project: mksconstraints.h
and the header files that implement these error messages. Note that we
are relying
on the compiler to use the more general form of each operator (copy
ctor, operator =,
operator +, operator -, etc.) in the error case, but use the
more-specialized form in the
normal case. I'm not sure if all compilers are smart enough to do this,
but for any compiler
that isn't, we can just leave out the pretty error messages.
- ------------------- mksconstraints.h -----------------
#ifndef __MKSCONSTRAINTS__
#define __MKSCONSTRAINTS__
template class power_base
{
public:
power_base & operator += (const power_base &);
power_base & operator -= (const power_base &);
};
template class meter_power
{
public:
meter_power & operator += (const meter_power &);
meter_power & operator -= (const meter_power &);
};
template class kilogram_power
{
public:
kilogram_power & operator += (const kilogram_power &);
kilogram_power & operator -= (const kilogram_power &);
};
template class seconds_power
{
public:
seconds_power & operator += (const seconds_power &);
seconds_power & operator -= (const seconds_power &);
};
template class coulombs_power
{
public:
coulombs_power & operator += (const coulombs_power &);
coulombs_power & operator -= (const coulombs_power &);
};
class invalid_mks_dimension
{
private:
invalid_mks_dimension(const invalid_mks_dimension &);
void operator = (const invalid_mks_dimension &);
public:
invalid_mks_dimension ();
};
class invalid_meter_dimension : public invalid_mks_dimension {};
class invalid_kilogram_dimension : public invalid_mks_dimension {};
class invalid_seconds_dimension : public invalid_mks_dimension {};
class invalid_coulombs_dimension : public invalid_mks_dimension {};
class mks_type_error
{
public:
typedef invalid_meter_dimension meter_dimension;
typedef invalid_kilogram_dimension kilogram_dimension;
typedef invalid_seconds_dimension seconds_dimension;
typedef invalid_coulombs_dimension coulombs_dimension;
};
#endif
------------------------------
Date: Fri, 08 Aug 2003 20:12:28 -0700
From: Pete and Lana Klier
Subject: SI Units Project: mksmeasure.h (for compiler errors)
- ----------------------- mksmeasure.h (my system, not Simon's yet)
- ----------------
#ifndef __MKSMEASURE__
#define __MKSMEASURE__
#include "mksconstraints.h"
template
class mksmeasure
{
private:
T value_;
mksmeasure (void); // No default constructor for safety
protected:
mksmeasure (const T & number) : value_(number) {};
operator const T & (void) const { return value_; };
mksmeasure operator = (const T &rhs) { value_ = number; };
public:
typedef meter_power meter_dimension;
typedef kilogram_power kilogram_dimension;
typedef seconds_power~~ seconds_dimension;
typedef coulombs_power coulombs_dimension;
static mksmeasure mksmeasure_from_number (const T &number)
{
return mksmeasure(number);
}
const T & number_from_mksmeasure (void) const { return value_; };
mksmeasure (const mksmeasure &rhs) : value_(rhs.value_) {};
template mksmeasure(const RHS &rhs)
{
typename RHS::meter_dimension right_hand_side_meter_dimension;
meter_dimension left_hand_side_meter_dimension =
right_hand_side_meter_dimension;
typename RHS::kilogram_dimension
right_hand_side_kilogram_dimension;
kilogram_dimension left_hand_side_kilogram_dimension =
right_hand_side_kilogram_dimension;
typename RHS::seconds_dimension right_hand_side_seconds_dimension;
seconds_dimension left_hand_side_seconds_dimension =
right_hand_side_seconds_dimension;
typename RHS::coulombs_dimension
right_hand_side_coulombs_dimension;
coulombs_dimension left_hand_side_coulombs_dimension =
right_hand_side_coulombs_dimension;
};
template mksmeasure(const mksmeasure~~__ &rhs)
: value_(rhs.number_from_mksmeasure()) {};
template operator mksmeasure____ (void) const
{ return mksmeasure____(*this); };
template mksmeasure &operator = (const RHS &rhs)
{
typename RHS::meter_dimension right_hand_side_meter_dimension;
meter_dimension left_hand_side_meter_dimension;
left_hand_side_meter_dimension = right_hand_side_meter_dimension;
typename RHS::kilogram_dimension
right_hand_side_kilogram_dimension;
kilogram_dimension left_hand_side_kilogram_dimension;
left_hand_side_kilogram_dimension =
right_hand_side_kilogram_dimension;
typename RHS::seconds_dimension right_hand_side_seconds_dimension;
seconds_dimension left_hand_side_seconds_dimension;
left_hand_side_seconds_dimension =
right_hand_side_seconds_dimension;
typename RHS::coulombs_dimension
right_hand_side_coulombs_dimension;
coulombs_dimension left_hand_side_coulombs_dimension;
left_hand_side_coulombs_dimension =
right_hand_side_coulombs_dimension;
return *this;
};
// No dtor, let T::operator = handle everything
mksmeasure &operator = (const mksmeasure &rhs)
{
value_ = rhs.value_;
return *this;
}
template mks_type_error operator + (const RHS &rhs)
{
typename RHS::meter_dimension right_hand_side_meter_dimension;
meter_dimension left_hand_side_meter_dimension;
left_hand_side_meter_dimension + right_hand_side_meter_dimension;
typename RHS::kilogram_dimension
right_hand_side_kilogram_dimension;
kilogram_dimension left_hand_side_kilogram_dimension;
left_hand_side_kilogram_dimension +
right_hand_side_kilogram_dimension;
typename RHS::seconds_dimension right_hand_side_seconds_dimension;
seconds_dimension left_hand_side_seconds_dimension;
left_hand_side_seconds_dimension +
right_hand_side_seconds_dimension;
typename RHS::coulombs_dimension
right_hand_side_coulombs_dimension;
coulombs_dimension left_hand_side_coulombs_dimension;
left_hand_side_coulombs_dimension +
right_hand_side_coulombs_dimension;
return mks_type_error();
};
mksmeasure operator + (const mksmeasure &rhs)
{
return mksmeasure(value_ + rhs.value_);
};
template mks_type_error operator - (const RHS &rhs)
{
typename RHS::meter_dimension right_hand_side_meter_dimension;
meter_dimension left_hand_side_meter_dimension;
left_hand_side_meter_dimension - right_hand_side_meter_dimension;
typename RHS::kilogram_dimension
right_hand_side_kilogram_dimension;
kilogram_dimension left_hand_side_kilogram_dimension;
left_hand_side_kilogram_dimension -
right_hand_side_kilogram_dimension;
typename RHS::seconds_dimension right_hand_side_seconds_dimension;
seconds_dimension left_hand_side_seconds_dimension;
left_hand_side_seconds_dimension -
right_hand_side_seconds_dimension;
typename RHS::coulombs_dimension
right_hand_side_coulombs_dimension;
coulombs_dimension left_hand_side_coulombs_dimension;
left_hand_side_coulombs_dimension -
right_hand_side_coulombs_dimension;
return mks_type_error();
};
mksmeasure operator - (const mksmeasure &rhs)
{
return mksmeasure(value_ - rhs.value_);
};
template mksmeasure &operator += (const RHS &rhs)
{
typename RHS::meter_dimension right_hand_side_meter_dimension;
meter_dimension left_hand_side_meter_dimension;
left_hand_side_meter_dimension += right_hand_side_meter_dimension;
typename RHS::kilogram_dimension
right_hand_side_kilogram_dimension;
kilogram_dimension left_hand_side_kilogram_dimension;
left_hand_side_kilogram_dimension +=
right_hand_side_kilogram_dimension;
typename RHS::seconds_dimension right_hand_side_seconds_dimension;
seconds_dimension left_hand_side_seconds_dimension;
left_hand_side_seconds_dimension +=
right_hand_side_seconds_dimension;
typename RHS::coulombs_dimension
right_hand_side_coulombs_dimension;
coulombs_dimension left_hand_side_coulombs_dimension;
left_hand_side_coulombs_dimension +=
right_hand_side_coulombs_dimension;
return *this;
};
mksmeasure &operator += (const mksmeasure &rhs)
{
value_ += rhs.value_;
return *this;
};
template mksmeasure &operator -= (const RHS &rhs)
{
typename RHS::meter_dimension right_hand_side_meter_dimension;
meter_dimension left_hand_side_meter_dimension;
left_hand_side_meter_dimension -= right_hand_side_meter_dimension;
typename RHS::kilogram_dimension
right_hand_side_kilogram_dimension;
kilogram_dimension left_hand_side_kilogram_dimension;
left_hand_side_kilogram_dimension -=
right_hand_side_kilogram_dimension;
typename RHS::seconds_dimension right_hand_side_seconds_dimension;
seconds_dimension left_hand_side_seconds_dimension;
left_hand_side_seconds_dimension -=
right_hand_side_seconds_dimension;
typename RHS::coulombs_dimension
right_hand_side_coulombs_dimension;
coulombs_dimension left_hand_side_coulombs_dimension;
left_hand_side_coulombs_dimension -=
right_hand_side_coulombs_dimension;
return *this;
};
mksmeasure &operator -= (const mksmeasure &rhs)
{
value_ += rhs.value_;
return *this;
};
// Multiplication and division by dimensionless
mksmeasure operator * (const T &rhs) const
{
return mksmeasure(value_ * rhs);
};
mksmeasure pre_multiply (const T &lhs) const
{
return mksmeasure(lhs * value_);
};
mksmeasure pre_divide (const T &lhs) const
{
return mksmeasure::mksmeasure_from_number(lhs /
value_);
};
mksmeasure operator / (const T &rhs) const
{
return mksmeasure(value_ / rhs);
};
mksmeasure & operator /= (const T &rhs)
{
value_ /= rhs;
return *this;
};
mksmeasure & operator *= (const T &rhs)
{
value_ *= rhs;
return *this;
};
mksmeasure square (void) const
{
return (*this) * (*this);
};
};
template
mksmeasure operator *
(const T &lhs, const mksmeasure &rhs)
{
return rhs.pre_multiply(lhs);
};
template
mksmeasure operator /
(const T &lhs, const mksmeasure &rhs)
{
return rhs.pre_divide(lhs);
};
#endif
------------------------------
Date: Fri, 08 Aug 2003 20:11:00 -0700
From: Pete and Lana Klier
Subject: SI Units Project: compiler output
Here is the compiler output from said erroneous code:
- ------------------------*compilation*---------------------------------------
cd /home/pklier/mks/
g++ -o mkserror mkserror.cc
mkserror.cc:13:2: warning: #warning This compilation is designed to give
pretty errors
mkserror.cc:14:2: warning: #warning not to actually run
mkserror.cc:31:2: warning: #warning Mismatched initialization:
mkserror.cc:41:2: warning: #warning Mismatched assignment
mkserror.cc:48:2: warning: #warning Mismatched initialization after
expression eval
mkserror.cc:57:2: warning: #warning Mismatched assignment after
expression eval
mkserror.cc:61:2: warning: #warning Mistmached +, no left-hand-side
mkserror.cc:65:2: warning: #warning Mismatched "-" with initialization
mkserror.cc:73:2: warning: #warning Mismatched "?" with initialization
mkserror.cc: In function `int main (int, char **)':
mkserror.cc:72: parse error before `hair_dryer_ohms'
mkserror.cc:76: `hair_dryer_ohms' undeclared (first use this function)
mkserror.cc:76: (Each undeclared identifier is reported only once for
each function it appears in.)
mkserror.cc:76: `hair_dryer' undeclared (first use this function)
mksmeasure.h: In method `mksmeasure::mksmeasure (const
RHS &) [with RHS = mksmeasure, T = double, int M =
1, int K = 0, int S = 0, int C = 0]':
mkserror.cc:33: instantiated from here
mksmeasure.h:41: conversion from `meter_power<0>' to non-scalar type
`meter_power<1>' requested
mkserror.cc:33: instantiated from here
mksmeasure.h:47: conversion from `seconds_power<1>' to non-scalar type
`seconds_power<0>' requested
mksmeasure.h: In method `mksmeasure &mksmeasure::operator= (const RHS &) [with RHS = mksmeasure, T = double, int M = 1, int K = 0, int S = 0, int C = 0]':
mkserror.cc:42: instantiated from here
mksmeasure.h:66: no match for `meter_power<1> & = meter_power<0> &'
mksconstraints.h:12: candidates are: meter_power<1>
&meter_power<1>::operator= (const meter_power<1> &)
mksmeasure.h:74: no match for `seconds_power<0> & = seconds_power<1> &'
mksconstraints.h:30: candidates are: seconds_power<0>
&seconds_power<0>::operator= (const seconds_power<0> &)
mksmeasure.h: In method `mksmeasure::mksmeasure (const
RHS &) [with RHS = mksmeasure, T = double, int M =
2, int K = 1, int S = -2, int C = 0]':
mkserror.cc:49: instantiated from here
mksmeasure.h:41: conversion from `meter_power<1>' to non-scalar type
`meter_power<2>' requested
mkserror.cc:49: instantiated from here
mksmeasure.h:47: conversion from `seconds_power<-1>' to non-scalar type
`seconds_power<-2>' requested
mksmeasure.h: In method `mksmeasure &mksmeasure::operator= (const RHS &) [with RHS = mksmeasure, T = double, int M = 2, int K = 1, int S = -2, int C = 0]':
mkserror.cc:58: instantiated from here
mksmeasure.h:74: no match for `seconds_power<-2> & = seconds_power<-1>
&'
mksconstraints.h:30: candidates are: seconds_power<-2>
&seconds_power<-2>::operator= (const seconds_power<-2> &)
mksmeasure.h: In method `mks_type_error mksmeasure::operator+ (const RHS &) [with RHS = mksmeasure, T = double, int M = 2, int K = 1, int S = -3, int C = 0]':
mkserror.cc:62: instantiated from here
mksmeasure.h:97: no match for `meter_power<2> & + meter_power<2> &'
mksmeasure.h:101: no match for `kilogram_power<1> & + kilogram_power<1>
&'
mkserror.cc:62: instantiated from here
mksmeasure.h:105: no match for `seconds_power<-3> & + seconds_power<-2>
&'
mkserror.cc:62: instantiated from here
mksmeasure.h:109: no match for `coulombs_power<0> & +
coulombs_power<-1> &'
mksmeasure.h: In method `mks_type_error mksmeasure::operator- (const RHS &) [with RHS = mksmeasure,
T = double, int M = 2, int K = 1, int S = -3, int C = 0]':
mkserror.cc:66: instantiated from here
mksmeasure.h:125: no match for `meter_power<2> & - meter_power<0> &'
mksmeasure.h:129: no match for `kilogram_power<1> & - kilogram_power<0>
&'
mksmeasure.h:133: no match for `seconds_power<-3> & - seconds_power<1>
&'
mksmeasure.h:137: no match for `coulombs_power<0> & - coulombs_power<0>
&'
mksmeasure.h: In method `mksmeasure::mksmeasure (const
RHS &) [with RHS = mks_type_error, T = double, int M = 2, int K = 1,
int S = -2, int C = 0]':
mkserror.cc:66: instantiated from here
mksmeasure.h:41: conversion from `invalid_meter_dimension' to
non-scalar type `meter_power<2>' requested
mksmeasure.h:44: conversion from `invalid_kilogram_dimension' to
non-scalar type `kilogram_power<1>' requested
mksmeasure.h:47: conversion from `invalid_seconds_dimension' to
non-scalar type `seconds_power<-2>' requested
mksmeasure.h:50: conversion from `invalid_coulombs_dimension' to
non-scalar type `coulombs_power<0>' requested
mksmeasure.h: In method `mksmeasure &mksmeasure::operator+= (const RHS &) [with RHS = mksmeasure, T = double, int M = 2, int K = 1, int S = -2, int C = 0]':
mkserror.cc:72: instantiated from here
mksmeasure.h:154: no match for `meter_power<2> & += meter_power<0> &'
mksconstraints.h:14: candidates are: meter_power
&meter_power::operator+= (const meter_power &) [with int M = 2]
mksmeasure.h:158: no match for `kilogram_power<1> & +=
kilogram_power<0> &'
mksconstraints.h:22: candidates are: kilogram_power
&kilogram_power::operator+= (const kilogram_power &) [with int K
= 1]
mksmeasure.h:162: no match for `seconds_power<-2> & += seconds_power<1>
&'
mksconstraints.h:32: candidates are: seconds_power__~~
&seconds_power~~~~::operator+= (const seconds_power~~~~ &) [with int S =
- -2]
Compilation exited abnormally with code 1 at Sun Jul 6 09:41:10
- ------------------------------------
------------------------------
Date: Fri, 08 Aug 2003 20:09:38 -0700
From: Pete and Lana Klier
Subject: SI Units Project: Getting closer...
Assuming that anybody is out there...
Loosely based on Bjarne Stroustrup's web site, I've managed to cobble
together
a prototype that prints error messages for SI units which are more
user-friendly thant
the defaults. This, or something like it, is probably the best that I
can do without
modifying the compiler.
In any case, this ( as well as history-based printing ) is the last
frontier.
What remains is to integrate these things into Simon's code and then
write it up.
Next, in my *copious* spare time, I will attempt to integrate this, and
the
heterogeneous base types (i.e. metres + metres) if it
hasn't been incorporated already, into Simon's latest and greatest.
So if anyone has any comments, let me know.
- --------------- (see next message) ----------------
------------------------------
Date: Sat, 12 Jul 2003 12:21:44 -0700
From: Pete and Lana Klier
Subject: [Fwd: SI Units Project: Celsius scale (etc)]
This is a multi-part message in MIME format.
- --Boundary_(ID_7t2AB82U/WorYI5kwf8JEg)
Content-type: text/plain; charset=us-ascii
Content-transfer-encoding: 7BIT
The short answer is, "it's not our problem -- once SI units are managed,
it's up to the user to keep the
types straight." For instance, the user can say:
const kelvin freezing_point_water = 273; /* 273.15?? */
kelvin temp_k = 283 kelvin;
kelvin temp_c = temp_k - freezing_point_water;
Under this model, with simple SI units the way it is today, the user
would be responsible
for ensuring that his "type system" is consistent. We can save her from
*some* mistakes,
but we cannot ensure that (what would be) the next layer of the type
system is correct.
The user must keep track of the semantics of each variable: temp_k is
the temperature
relative to absolute zero, temp_c is the temperature relative to the
freezing point of water,
both in units of "kelvin" and there's nothing that the SI units system,
managing multiplicative
constants, can do about it.
As for the long answer, we can get a little philosophical here. It's
possible to create another
type system which deals with such additive constants and levels. Let's
make an analogy to
vectors and points in 3-dimensional space, which I have implemented and
it turns out to work
pretty well.
The semantics of a _vector_ (which I call a *vec3* to distinguish it
from STL's) is that it represents the *difference* between 2 points in
space. The semantics of a *point* is that of a particular point in
space. In a strict abstractionist
way of thinking, there are really no numbers associated with either one
of them. In order to begin generating
points from vec3's, you need to start with a fixed constant which I call
point::the_origin.
Note that there are 2 distinct data types above, but they are related:
A point plus a vec3 results in another point.
The difference of two points is a vec3.
The sum of a vec3 and another vec3 is a vec3.
Conversely, the operations that make no sense, semantically, are not
implemented, and help
prevent the user from making mistakes. For example, I cannot add two
points in space; it
simply does not make sense to add "the location of my house" to "the
location of Fry's electronics"
but I can take the difference of the two to yield the vector between
them.
Most people who use a "vector" data type such as above use it to mean
both "vector" as in
the difference between two locations in space, and "point" as in a
single location in space, and
the type information as to which one is which is implicit in the
variables, and it is possible to get
them mixed up even if the type of each individual item is in terms of SI
units!
Back to temperatures, we can make the following analogies:
Point in space (point) <====> The temperature of an object
Difference between two points (vec3) <=====> A difference in
temperatures.
Thus "the temperature of an object" and " a difference in temperatures"
are really two different
data types. Strictly speaking, the data type that implements "the
temperature of an object" would
be so abstract that we wouldn't care whether it's Kelvin or Celsius,
until we tried to print it.
So the following operations would apply:
"Temperature of an object" + "a difference in temperatures" ==>
"Temperature of an object"
"Temperature of an object" - "Temperature of an object" ==> "a
difference in temperatures"
"a difference in temperatures" + "a difference in temperatures" ==> "a
difference in temperatures"
and, in particular, adding together two "Temperature of an object"
instances would be an operation
that simply does not exist.
What further complicates matters is the fact that there are two
"natural" zero points for the temperature
scale, namely absolute zero and the freezing point of water. I might
write something like this (I didn't
check this out on the computer, just getting the general flavor ) :
template class Delta_Temperature
{
private:
REP delta_degrees_;
public:
// Here is a little bit of 'weaker' typing, but I want to get
the point across.
explicit Delta_Temperature (const REP &rhs) :
delta_degrees_(rhs) {};
Delta_Temperature operator + (const Delta_Temperature &)
const;
Delta_Temperature operator - (const Delta_Temperature &)
const;
Delta_Temperature operator - () const;
template Delta_Temperature< ProdType >
operator * (const U &);
}
template class Absolute_Temperature
{
private:
REP degrees_above_zero_point_;
Absolute_Temperature (const REP &rhs) :
degrees_above_zero_point_(rhs) {};
public:
Absolute_Temperature operator + (const Delta_Temperature
&) const;
Absolute_Temperature operator - (const Delta_Temperature
&) const;
Delta_Temperature operator - (const Absolute_Temperature
&) const;
// unary - does NOT exist
// operator * for scaling does NOT exist
template
Delta_Temperature operator - (const
Absolute_Temperature &rhs)
{
return
Absolute_Temperature(degrees_above_zero_point_ +
ZERO_POINT::zero_point()) -
(rhs.degrees_above_zero_point +
RHS_ZERO_POINT::zero_point());
}
tempalte
Absolute_Temperature (const
Absolute_Temperature &rhs)
{
return (zero_opint() +
(rhs.zero_point_ -
Absolute_Temperature::zero_point() );
}
static Absolute_Temperature zero_point() {
Absolute_Temperature temp;
temp.degrees_above_zero_point = ZERO_POINT::zero_point();
return temp; }
}
class water_freezing_double { public: static double zero_point() {
return 273.15; }};
class absolute_zero_double { public: static double zero_point() {
return 0; }};
class water_freezing_SI { public: static kelvin zero_point() { return
273.15 * Kelvin; }};
class absolute_zero_SI { public: static kelvin zero_point() { return 0 *
Kelvin; } };
- ----- let's keep in mind that there are a LOT of permutations of this
stuff, this is just one example.
I'm attempting to get the point across that we don't NEED SI units to
keep track of Celsius and Kelvin!!!!!
Then usage:
static const Absolute_Temperature
Absolute_Zero =
Absolute_Temperature::zero_point();
static const Absolute_Temperature
Water_Freezing =
Absolute_Temperature::zero_point();
static const Absolute_Temperature DryIce =
Water_Freezing + Delta_Temperature(- 70.0);
Delta_Temperature foo = Water_Freezing - Absolute_Zero;
cout << foo << endl; // Should say something like "273.15 degrees
Kelvin differential"
cout << Water_Freezing << endl; // Might say something like "0 degrees
Celsius temperature"
cout << Absolute_Zero << endl; '// Might say something like "0 degrees
above absolute zero"
cout <<
Absolute_Temperature(Absolute_Zero) <<
endl;
// Might say something like "-273.15 degrees
Celsius temperature"
cout <<
Absolute_Temperature(Water_Freezing) <<
endl;
// Might say something like "273.15 degrees
above absolute zero"
const Absolute_Temperature balmy =
Water_Freezing +
Delta_Temperature(10.0);
const Absolute_Temperature boiling =
Water_Freezing +
Delta_Temperature(100.0);
cout << (boiling - balmy) << endl ; // "90 degrees Kelvin differential"
cout << Absolute_Zero + (boiling - balmy) << endl; // "90 degrees above
absolute zero"
cout << DryIce << endl; // "-70.0 degrees Celsius temperature"
cout << Absolute_Temperature(DryIce) <<
endl; // "203.15 degrees above absolute zero"
cout << (boiling - DryIce) << endl; // "170.0 degrees Kelvin
differential"
- ------
Now, if I want to, I can throw in SI units:
static const Absolute_Temperature
Absolute_Zero =
Absolute_Temperature::zero_point();
static const Absolute_Temperature
Water_Freezing =
Absolute_Temperature::zero_point();
static const Absolute_Temperature
DryIce =
Water_Freezing + Delta_Temperature(- 70.0);
- --- and do all the same computations, except that I wouldn't be allowed
to do:
Delta_Temperature foo = Delta_Temperature(63.0 *
Metres);
or whatever our syntax is.
Food for thought: If I generalize "Delta_Temperature" to "Delta_Units"
and "Absolute_Temperature" to
"Absolute_Units" then I might be able to do the same thing with "metres
above sea level" and what not.
The upshot is ..... This kind of thing can be made *INDEPENDENT* of SI
units and, with suitable
generality, interoperate smoothly with it.
Then, of course, we can generalize to dimensionless *MULTIPLICATIVE*
constants and think about....
horror of horrors.... FAHRENHEIT. Similarly, we can start to talk
about things like converting
"feet below sea level" to "metres above the center of the Earth"....
shudder..... but I think that's just
a generalization of the above. Then there's kilo-, mega-, etc. but
again, we need to make things
as independent as possible, which is why I was thinking of
kilo
along with
kilo
I'm not trying to get people to do things *that way* (as above) but it's
the independence of the various
concepts that is important.
In any case, Simon, if you have some new code I would be happy to get
it. Send a ".tar" or a ".tar.gz"
or whatever... uplink it to the web page, but you can also send it with
an attachment to my mail system....
whatever you have is acceptable as I would like to spiff it up with the
multiple-type models and
compile-time error messages that I've already done "off line"....
I want to write this up so that we'll be rich and famous!
- --Boundary_(ID_7t2AB82U/WorYI5kwf8JEg)
Content-type: message/rfc822; name=nsmailKG.TMP
Received: from vmj-ext.prodigy.net by vmj with SMTP; Mon,
07 Jul 2003 05:15:54 -0400
Received: from easterbrook.org.uk
(public2-lock1-4-cust244.cosh.broadband.ntl.com [80.3.182.244])
by vmj-ext.prodigy.net (8.12.9/8.12.9) with ESMTP id h679FoWS205474 for
; Mon, 07 Jul 2003 05:15:53 -0400
Received: (from mdom@si-units)
by easterbrook.org.uk (8.11.6/8.11.6/SuSE Linux 0.5)
id h679F4x25717 for si-units-list-outgoing; Mon, 07 Jul 2003 10:15:04 +0100
Date: Mon, 07 Jul 2003 09:36:57 +0100
From: "Watts, Simon (UK)"
Subject: SI Units Project: Celsius scale (etc)
X-Originating-IP: [80.3.182.244]
Sender: si-units-list@si-units
To: "'si-units-list@si-units'"
Reply-to: si-units-list@si-units
Message-id: <4F055774D458D51195BC000347246B39E804BD@si-units>
X-Envelope-to: si-units-list@si-units
MIME-version: 1.0
X-Mailer: Internet Mail Service (5.5.2656.59)
Content-type: text/plain; charset=iso-8859-1
Content-transfer-encoding: 7BIT
Precedence: bulk
X-Header-Overseas: Mail.from.Overseas.source.80.3.182.244
X-Sieve: cmu-sieve 2.0
I started doing a bit of a rework on my code a while back, including a small
terminology change (from previous discussions here):
"Quantity" to refer to the value classes, eg Temperature, Length, Mass are
all Quantity classes.
"Unit" to refer to the measurement units for quantities, eg, Kelvin, metre,
kilogram. These are constants for a particular system of units.
I am also toying with the concept of a "Scale", though this may merge with
"Unit". This has been discussed previously on this list, and I am just
trying to fit it into my model. Scales are needed to represent scales which
have a different origin to the internal SI system, for example Celsius.
The scale for Celsius would represent "273.15 + 1.0 T", where T is the
Celsius value. Its type would be something like "Scale".
Obviously, Unit and Scale can be merged when the offset is set to zero.
I did think about generalising this to an arbitary polynomial expression.
However, I cannot think of any practical systems which would require this,
and such expressions do not have a simple inverse, which I believe will be
an implicit requirement.
So the bit where this gets complicated is in the usage of scales in
expressions. This goes to the distinction between absolute values and
difference or delta values.
Consider the following expression:
Temperature t = 100.0 * celsius;
This can be interpreted as either a delta of +100.0 K, or an absolute value
of 373.15 K. OK, in this case probably the latter. But what about:
MyQuantity q = 100.0 * metre / celsius;
Here the intent is _probably_ to divide by the delta (1.0 K), and not "1.0 *
celsius = 273.15 K". So we have two uses.
And its not that simple, since we could write:
MyQuantity q = 200.0 * metre / (2.0 * celsius);
And expect the same thing as above.
The following expressions should be equivalent:
MyOtherQuantity z1 = 200.0 * metre * celsius;
MyOtherQuantity z2 = 200.0 * celsius * metre;
What is the intended use of celsius here? Delta or absolute?
I am currently leaning towards the following rule for dealing with scales,
although they do not cover every intent I havent thought of a better
approach:
Only multiplication or division _by_ a number
preserves the offset.
All other operations, the resultant offset is
set to zero.
Addition and subtraction require conversion to
a quantity.
So, if 'n' a number, and '(a,b)', '(c,d)' are scales:
n * (a,b) -> (a,nb)
(a,b) * n -> (a,nb)
(a,b) / n -> (a/n,b/n)
n / (a,b) -> (0,b/n)
(a,b)*(c,d) -> (0,bd)
(a,b)/(c,d) -> (0,b/d)
Now, there is the question of what to do when Quantities are thrown into the
mix. It may be sufficient to notionally convert the Quantity, 'q', to the
equivalent scale '(0,q)', and apply the rules above.
So, any counter examples?
Si.
- --Boundary_(ID_7t2AB82U/WorYI5kwf8JEg)--
------------------------------
End of si-units-digest V1 #19
*****************************
~~