[math constants] a new approach (perhaps)

Dear boosters, I discovered something that at least was new to me. It's a simple way of coding floating point constants s.t. 1. no overhead at all 2. no order dependencies occur 3. the context in which the constant appears decides the precision of the constants [important in template code] 4. whenever a narrowing or widening conversion is required, explicit action must be taken by the programmer to determine what he wants 5. all precisions of the constants co-exist, so there is no need for several headers Example: #include "math_constant.hpp" #include <iostream> #include <cmath> #include <iomanip> using namespace std; template< typename T > void test(); int main() { cout << setprecision( 10 ); test<float>(); test<double>(); test<long double>(); // cout << pi; // ambiguous cout << float( pi ) << " " << double( pi ) << " " << (long double)( pi ); // ok // int i = pi; // ambiguous int i = float( pi ); // ok cout << sqrt( float( pi ) ); } template< typename T > void test() { T two_pi = T(2) * pi; two_pi = T(pi) + pi; // note: pi operator X() pi is ambiguous T plus = T(1) + pi; T minus = pi - T(1); T divide = pi / T(2); T all = pi + T(3) - T(pi) * pi / T(3); // also ambiguous cout << T( pi ) << " "; } Any comments are more than welcome. I know there are several proposals for defining math constants, but I don't see what the big problems are (so please help me understand them :-) ) br Thorsten

Looks interesting - but what is in "math_constant.hpp" ? Thanks Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com | -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Thorsten Ottosen | Sent: 29 February 2004 11:52 | To: boost@lists.boost.org | Subject: [boost] [math constants] a new approach (perhaps) | I discovered something that at least was new to me. It's a | simple way of | coding floating point | constants s.t. | | #include "math_constant.hpp"

"Paul A Bristow" <boost@hetp.u-net.com> wrote in message news:002c01c3ff13$be46d340$0c010101@hetp3...
Looks interesting - but what is in "math_constant.hpp" ?
David Abrahams:
So, umm, are you going to show us the definition of "pi"?
Yes, of course. BTW, I've attached the file since my messages seems to format the code like ****. br Thorsten namespace std { #define CNAME( Var ) Var##_constant_t #define OVERLOAD_CONTEXT( ConstType, FP, FPV ) \ inline FP operator+( FP l, ConstType ) \ { return l + FPV; } \ inline FP operator+( ConstType, FP r ) \ { return r + FPV; } \ inline FP operator-( FP l, ConstType ) \ { return l - FPV; } \ inline FP operator-( ConstType, FP r ) \ { return FPV - r; } \ inline FP operator*( FP l, ConstType ) \ { return l * FPV; } \ inline FP operator*( ConstType, FP r ) \ { return r * FPV; } \ inline FP operator/( FP l, ConstType ) \ { return l / FPV; } \ inline FP operator/( ConstType, FP r ) \ { return FPV / r; } \ #define DEFINE_FP_CONSTANT( Name, FV, DV, LDV ) \ struct CNAME( Name ) \ { \ CNAME( Name ) () {} \ operator float() const { return FV; } \ operator double() const { return DV; } \ operator long double() const { return LDV; } \ }; \ OVERLOAD_CONTEXT( CNAME( Name ), float, FV ) \ OVERLOAD_CONTEXT( CNAME( Name ), double, DV ) \ OVERLOAD_CONTEXT( CNAME( Name ), long double, LDV ) \ const CNAME( Name ) Name; DEFINE_FP_CONSTANT( pi, 3.14F, 3.14232, 3.1423211223L ) } // namespace std begin 666 math_constant.hpp M+RHJ#0H@*B H0RD@5&AO<G-T96X@3W1T;W-E;BP@,C P- T*("H@0V]N=&%C M=#H@;F5S;W1T;T!C<RYA=6,N9&L-"B J( T*("H@17AA;7!L92!O9B!H;W<@ M=&\@:6UP;&5M96YT(&9L97AI86)L92!M871H(&-O;G-T86YT<R!S+G0N#0H@ M*B -"B J(#$I('1H92!E>'!R97-S:6]N('=H97)E('1H92!C;VYS=&%N="!A M<'!E87)S(&1E8VED97,@=&AE#0H@*B @("!T>7!E(&]F('1H92!C;VYS=&%N M= T*("H@,BD@=&AE(&-O;G-T86YT<R!C86X@<&%S<V5D('1O(&YO<FUA;"!M M871H(&9U;F-T:6]N<PT*("H@,RD@;F\@;W)D97(@9&5P96YD96YC:65S(&]C M8W5R<PT*("H@-"D@;6EX+6UO9&4@87)I=&AM971I8R!I<R!N;W0@<&]S<VEB M;&4@=VET:&]U="!E>'!L:6-I="!A8W1I;VX@9G)O;2!T:&4-"B J(" @('!R M;V=R86UM97(-"B J(#4I('1E<W1S(')E=F5A;"!T:&%T('1H97)E(&ES(&YO M(&]V97)H96%D#0H@*B -"B J("@R*2P@*#,I(&%N9" H-2D@87)E(&$@;75S M="!W:&EL92 H,2D@86YD("@T*2!M96%N<R!T:&%T('5N=V%N=&5D(&-O;G9E M<G-I;VYS#0H@*B!C86X@8F4@97AP;&EC:71L>2!C;VYT<F]L;&5D+B!&;W)C M:6YG('1H92!P<F]G<F%M;65R('1O(&UA:V4@=&AA="!C:&]I8V4-"B J(&ES M('-E96X@87,@82!G;V]D('!R;W!E<G1Y+@T*("HO#0H@( T*#0IN86UE<W!A M8V4@<W1D#0I[#0H-"B-D969I;F4@0TY!344H(%9A<B I(%9A<B,C7V-O;G-T M86YT7W0-"@T*(V1E9FEN92!/5D523$]!1%]#3TY415A4*"!#;VYS=%1Y<&4L M($90+"!&4%8@*2 @7 T*:6YL:6YE($90(&]P97)A=&]R*R@@1E @;"P@0V]N M<W14>7!E("D@(" @(" @(" @7 T*>R!R971U<FX@;" K($905CL@?2 @(" @ M(" @(" @(" @(" @(" @(" @(" @(" @7 T*:6YL:6YE($90(&]P97)A=&]R M*R@@0V]N<W14>7!E+"!&4"!R("D@(" @(" @(" @7 T*>R!R971U<FX@<B K M($905CL@?2 @(" @(" @(" @(" @(" @(" @(" @(" @(" @7 T*:6YL:6YE M($90(&]P97)A=&]R+2@@1E @;"P@0V]N<W14>7!E("D@(" @(" @(" @7 T* M>R!R971U<FX@;" M($905CL@?2 @(" @(" @(" @(" @(" @(" @(" @(" @ M(" @7 T*:6YL:6YE($90(&]P97)A=&]R+2@@0V]N<W14>7!E+"!&4"!R("D@ M(" @(" @(" @7 T*>R!R971U<FX@1E!6("T@<CL@?2 @(" @(" @(" @(" @ M(" @(" @(" @(" @(" @7 T*:6YL:6YE($90(&]P97)A=&]R*B@@1E @;"P@ M0V]N<W14>7!E("D@(" @(" @(" @7 T*>R!R971U<FX@;" J($905CL@?2 @ M(" @(" @(" @(" @(" @(" @(" @(" @(" @7 T*:6YL:6YE($90(&]P97)A M=&]R*B@@0V]N<W14>7!E+"!&4"!R("D@(" @(" @(" @7 T*>R!R971U<FX@ M<B J($905CL@?2 @(" @(" @(" @(" @(" @(" @(" @(" @(" @7 T*:6YL M:6YE($90(&]P97)A=&]R+R@@1E @;"P@0V]N<W14>7!E("D@(" @(" @(" @ M7 T*>R!R971U<FX@;" O($905CL@?2 @(" @(" @(" @(" @(" @(" @(" @ M(" @(" @7 T*:6YL:6YE($90(&]P97)A=&]R+R@@0V]N<W14>7!E+"!&4"!R M("D@(" @(" @(" @7 T*>R!R971U<FX@1E!6("\@<CL@?2 @(" @(" @(" @ M(" @(" @(" @(" @(" @(" @7 T*#0HC9&5F:6YE($1%1DE.15]&4%]#3TY3 M5$%.5"@@3F%M92P@1E8L($16+"!,1%8@*2 @(" @7 T*<W1R=6-T($-.04U% M*"!.86UE("D@(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(%P-"GL@ M(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @ M(" @("!<#0H@($-.04U%*"!.86UE("D@*"D@(" @(" @(" @(" @>WT@(" @ M(" @(" @(" @(" @(" @7 T*("!O<&5R871O<B!F;&]A="@I(&-O;G-T(" @ M(" @('L@<F5T=7)N($96.R!](" @(" @(%P-"B @;W!E<F%T;W(@9&]U8FQE M*"D@8V]N<W0@(" @("![(')E='5R;B!$5CL@?2 @(" @("!<#0H@(&]P97)A M=&]R(&QO;F<@9&]U8FQE*"D@8V]N<W0@>R!R971U<FX@3$16.R!](" @(" @ M7 T*?3L@(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @ M(" @(" @(" @(%P-"D]615),3T%$7T-/3E1%6%0H($-.04U%*"!.86UE("DL M(&9L;V%T+"!&5B I(" @(" @("!<#0I/5D523$]!1%]#3TY415A4*"!#3D%- M12@@3F%M92 I+"!D;W5B;&4L($16("D@(" @(" @7 T*3U9%4DQ/041?0T]. M5$585"@@0TY!344H($YA;64@*2P@;&]N9R!D;W5B;&4L($Q$5B I(%P-"F-O M;G-T($-.04U%*"!.86UE("D@3F%M93L-"@T*1$5&24Y%7T907T-/3E-404Y4 M*"!P:2P@,RXQ-$8L(#,N,30R,S(L(#,N,30R,S(Q,3(R,TP@*0T*#0I]("\O 4(&YA;65S<&%C92!S=&0-"@T*#0H` ` end

Thorsten Ottosen wrote:
Yes, of course. BTW, I've attached the file since my messages seems to format the code like ****.
br
Thorsten
With no offense intended, but that's a very simple version which doesn't work in many situations. The problems of your solution are: - Doesn't work well for UDTs (try std::complex, some conversions are ambiguous then) - Doesn't scale for new types (you need to know all of them in the single header that defines the constant) - Doesn't work for more complex expressions (pi*pi*t instead of T(pi)*pi*t) - Doesn't work for function calls (srqt(pi)*t instead of sqrt(T(pi))*t) - Doesn't solve the naming dilemma (how to spell the constant "pi*pi"?) - Doesn't work well with unit libraries AFAICS (again not scaling well) I really suggest you look at my code at <http://groups.yahoo.com/group/boost/files/MathConstants/>, which solves all of the above points. Feel free to ask questions. Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

With no offense intended, but that's a very simple version which doesn't work in many situations. The problems of your solution are:
- Doesn't work well for UDTs (try std::complex, some conversions are ambiguous then)
What rule of the language prohibit this conversion? My vc71 compiler can do it, como and g++ cannot.
- Doesn't scale for new types (you need to know all of them in the single header that defines the constant)
You could add the overloads with eg a macro in your own header. What should hinder this?
- Doesn't work for more complex expressions (pi*pi*t instead of T(pi)*pi*t)
true, but what precision does pi*pi have? IMO, it's good to have that information in the code.
- Doesn't work for function calls (srqt(pi)*t instead of sqrt(T(pi))*t)
again it a matter of being explicit about which overloaded version you want to call; therefore one would always add T().
- Doesn't solve the naming dilemma (how to spell the constant "pi*pi"?)
is pi_square that bad?
- Doesn't work well with unit libraries AFAICS (again not scaling well)
how?
I really suggest you look at my code at <http://groups.yahoo.com/group/boost/files/MathConstants/>, which solves all of the above points. Feel free to ask questions.
Is there any documentation?
From your example file:
std::cout << pi.get< float >() << std::endl; which is float( pi ) spelt more elaborate. std::cout << pi + pi - pi * pi / pi + d << std::endl; how often does such an expression occur in practice? Afterall, a single pi would do. std::cout << sqrt( sqrt( two + pi ) ) + d << std::endl; will everything left of d be a constant? If so, what would the point be? Thanks Thorsten

Thorsten Ottosen wrote:
With no offense intended, but that's a very simple version which doesn't work in many situations. The problems of your solution are:
- Doesn't work well for UDTs (try std::complex, some conversions are ambiguous then)
What rule of the language prohibit this conversion? My vc71 compiler can do it, como and g++ cannot.
It depends on what exactly you tried. The basic problem is, that T(pi) tries to call a ctor for T, but std::complex has several candidates available. std::complex<double>(std::complex<double>) and std::complex<double>(double) might conflict here, except you don't provide conversion to std::complex<double> for your constants. But you cannot assume this for other UDT. What happens if a UDT has ctors taking float, double and long-double? You can't use your constants any more, even a new conversion to the type directly won't help. This is (one of the reasons) why I provide .get<T>() instead of T(pi), static_cast<T>(pi) or pi.operator T(). While the alternatives all look very promising, they have some severe problem: You can't influence what they actually do. This becomes important when you think of unit-libraries, see the examples I put into the files section.
- Doesn't scale for new types (you need to know all of them in the single header that defines the constant)
You could add the overloads with eg a macro in your own header. What should hinder this?
Macro's are ugly. OK, not a very compelling reason :-) Still I would feel somewhat limited when I have to provide all of this stuff through macros. Also, I can't add values only for selected constants, once I start using macros, I have to prove them for all constants. Maybe this can - again - be fixed by some preprocessor magic, but it's well possible without the preprocessor at all.
- Doesn't work for more complex expressions (pi*pi*t instead of T(pi)*pi*t)
true, but what precision does pi*pi have? IMO, it's good to have that information in the code.
I disagree. You already found out that a certain convenience is necessary. You don't write T(pi)*t (t being of type T), just pi*t. This automatically selects the type/precision for pi in this expression. Why shouldn't this scale to pi*pi*t? Or sqrt(pi)*t. The first non-constant should select the type, no matter how the constants are used before.
- Doesn't solve the naming dilemma (how to spell the constant "pi*pi"?)
is pi_square that bad?
Yes. It clutters my brain with more names. pi*pi is a general principle I already know. Also, 1/srqt(e) is easy to remember, but what would the name be when using you scheme? It also makes the code less readable IMHO.
- Doesn't work well with unit libraries AFAICS (again not scaling well)
how?
Because they need to return a different type than what they are asked for. And casting them is not an option, as you need to know the unit and spell it out explicitly. Look at the ideal-gas-law-examples. You want to use the constant without spelling out it's type over and over again, won't you?
Is there any documentation?
Well, that's the weak point currently. I hope that I can come up with some docs in the next weeks. Currently, all I can offer is that I answer questions. Sorry.
From your example file:
std::cout << pi.get< float >() << std::endl;
which is float( pi ) spelt more elaborate.
As mentioned, this is a very important thing to note that .get<T> is free to return something else than T!
std::cout << pi + pi - pi * pi / pi + d << std::endl;
how often does such an expression occur in practice? Afterall, a single pi would do.
Look at some physical laws. There are often combinations of several constants and if possible, I don't want to limit the programmer if there isn't a compelling reason to do so. People should be able to express their thoughts as direct as possible. They shouldn't be forced to care about the language more than neccessary.
std::cout << sqrt( sqrt( two + pi ) ) + d << std::endl;
will everything left of d be a constant? If so, what would the point be?
Basically, it's not a single constant. The constants are both casts to d's type, added and sent through sqrt two times. But you can - if you want to - make it a single, fast constant if you think it's worth the effort for your program. Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

"Daniel Frey" <daniel.frey@aixigo.de> wrote in message news:c1vlqp$90l$1@sea.gmane.org... Thorsten Ottosen wrote: [snip]
It depends on what exactly you tried. The basic problem is, that T(pi) tries to call a ctor for T, but std::complex has several candidates available. std::complex<double>(std::complex<double>) and std::complex<double>(double) might conflict here, except you don't provide conversion to std::complex<double> for your constants. But you cannot assume this for other UDT. What happens if a UDT has ctors taking float, double and long-double? You can't use your constants any more, even a new conversion to the type directly won't help.
Sorry, but I don't get this. complex<float> z = float( pi ); should work just fine.
Why shouldn't this scale to pi*pi*t? Or sqrt(pi)*t. The first non-constant should select the type, no matter how the constants are used before.
Yeah, I could let pi * pi return a two_pi object.
- Doesn't work well with unit libraries AFAICS (again not scaling well) how?
From your example file:
std::cout << pi.get< float >() << std::endl;
which is float( pi ) spelt more elaborate.
As mentioned, this is a very important thing to note that .get<T> is free to return something else than T!
maybe not the best way to spell the function then?
std::cout << sqrt( sqrt( two + pi ) ) + d << std::endl;
will everything left of d be a constant? If so, what would the point be?
Basically, it's not a single constant. The constants are both casts to d's type, added and sent through sqrt two times. But you can - if you want to - make it a single, fast constant if you think it's worth the effort for your program.
ok. I can see that my approach might not scale too well. br Thorsten

Thorsten Ottosen wrote:
"Daniel Frey" <daniel.frey@aixigo.de> wrote in message news:c1vlqp$90l$1@sea.gmane.org... Thorsten Ottosen wrote: [snip]
It depends on what exactly you tried. The basic problem is, that T(pi) tries to call a ctor for T, but std::complex has several candidates available. std::complex<double>(std::complex<double>) and std::complex<double>(double) might conflict here, except you don't provide conversion to std::complex<double> for your constants. But you cannot assume this for other UDT. What happens if a UDT has ctors taking float, double and long-double? You can't use your constants any more, even a new conversion to the type directly won't help.
Sorry, but I don't get this.
complex<float> z = float( pi );
should work just fine.
Sure, but what about complex<float> z = complex<float>(pi)? Indeed, think about a generic algorithm: template<typename T> T area(const T& r) { return pi * r * r; } (or even T(pi)*r*r). You need constants that work well for all types with no special treatment of some types.
Why shouldn't this scale to pi*pi*t? Or sqrt(pi)*t. The first non-constant should select the type, no matter how the constants are used before.
Yeah, I could let pi * pi return a two_pi object.
No. OK, "yes" for this example, but "no" in general. You cannot predict all combinations the user could write. Simply providing all possible combinations is ridiculous overhead which doesn't scale well. My constant library works for any combination, whether predefined (that is, there is a real constant pi_square (ha, you got fooled by your own names - the naming dilemma! :) ) ) or not.
From your example file:
std::cout << pi.get< float >() << std::endl;
which is float( pi ) spelt more elaborate.
As mentioned, this is a very important thing to note that .get<T> is free to return something else than T!
maybe not the best way to spell the function then?
I'm open to suggestions. I don't like .get<T>() very much myself, but I can't imagine any better solution. Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

"Daniel Frey" <daniel.frey@aixigo.de> wrote in message news:c21jp0$2i8$1@sea.gmane.org...
Sorry, but I don't get this.
complex<float> z = float( pi );
should work just fine.
Sure, but what about complex<float> z = complex<float>(pi)?
works.
Indeed, think about a generic algorithm:
template<typename T> T area(const T& r) { return pi * r * r; }
also works. At least for float, double, and long double. Do you mean that your version will work with physical quantities like meters? If so, could I achieve the same effect by adding template< typename T > inline T operator*( T l, pi_t ) { return something; } ?
(or even T(pi)*r*r). You need constants that work well for all types with no special treatment of some types.
Given the info above, I can't fully understand it.
Why shouldn't this scale to pi*pi*t? Or sqrt(pi)*t. The first non-constant should select the type, no matter how the constants are used before.
Yeah, I could let pi * pi return a two_pi object.
No. OK, "yes" for this example, but "no" in general. You cannot predict all combinations the user could write. Simply providing all possible combinations is ridiculous overhead which doesn't scale well. My constant library works for any combination, whether predefined (that is, there is a real constant pi_square (ha, you got fooled by your own names - the naming dilemma! :) ) ) or not.
:-) Ok, but I don't quite see how your approach works for all combinations without coding support for them. But I'm willing to wait till you write some docs about it to find out. br Thorsten

Thorsten Ottosen wrote:
"Daniel Frey" <daniel.frey@aixigo.de> wrote in message news:c21jp0$2i8$1@sea.gmane.org...
Sorry, but I don't get this.
complex<float> z = float( pi );
should work just fine.
Sure, but what about complex<float> z = complex<float>(pi)?
works.
OK, bad example. Your version of pi works, because it doesn't offer a conversion to complex<float> directly. But what about boost::rational<T>, RWDecimal<RWMP3Int>, qdouble, etc.? Note that it's intended that you don't know all of them by heart :) You rely on special properties of std::complex, which are not given in general. Effectively, I'd say that you don't support complex, you ignore it. But complex supports conversions from/to float, double and long double as required, which makes it compatible with your constants. To put it another way: You require a specific design of compatible types for your constants. This is an unnecessary restriction which limits the use of your constants, as there are several types out there that won't match these requirements.
Indeed, think about a generic algorithm:
template<typename T> T area(const T& r) { return pi * r * r; }
also works. At least for float, double, and long double. Do you mean that your version will work with physical quantities like meters?
No, I was talking about the types listed above (rational, RWDecimal, ...). Currently, unit libraries require their own version. Although the decltype/auto-proposal would allow us to write a really cool generic version: template<typename T> auto area(const T& r) { return pi*r*r; } :))
If so, could I achieve the same effect by adding
template< typename T > inline T operator*( T l, pi_t ) { return something; }
?
Depends on the ctors of T.
Why shouldn't this scale to pi*pi*t? Or sqrt(pi)*t. The first non-constant should select the type, no matter how the constants are used before.
Yeah, I could let pi * pi return a two_pi object.
No. OK, "yes" for this example, but "no" in general. You cannot predict all combinations the user could write. Simply providing all possible combinations is ridiculous overhead which doesn't scale well. My constant library works for any combination, whether predefined (that is, there is a real constant pi_square (ha, you got fooled by your own names - the naming dilemma! :) ) ) or not.
:-) Ok, but I don't quite see how your approach works for all combinations without coding support for them. But I'm willing to wait till you write some docs about it to find out.
Well, all I can say is: It works. The type selection is defered and intermediate constants (and expressions with constants) are automatically generated by the compiler. As they are themself constants, they finally convert to the right type. But I'll try to explain it better in the docs. :) Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Daniel Frey | Sent: 01 March 2004 10:18 | To: boost@lists.boost.org | Subject: [boost] Re: [math constants] a new approach (perhaps) The problems of your solution are: | | - Doesn't work well for UDTs (try std::complex, some conversions are | ambiguous then) | - Doesn't scale for new types (you need to know all of them in the | single header that defines the constant) | - Doesn't work for more complex expressions (pi*pi*t instead | of T(pi)*pi*t) | - Doesn't work for function calls (srqt(pi)*t instead of | sqrt(T(pi))*t) | - Doesn't solve the naming dilemma (how to spell the constant | "pi*pi"?) | - Doesn't work well with unit libraries AFAICS (again not | scaling well) | | I really suggest you look at my code at | <http://groups.yahoo.com/group/boost/files/MathConstants/>, | which solves | all of the above points. Except that VC 7.1 doesn't think it is legal C++ :-(( I think we need to establish if it is correct (as gcc and Intel think it is) and then try to persuade Microsoft to change (perhaps by accepting Daniel's math constants solution as Boost library). Or to find some workaround that VC 7.1 will accept. It would be helpful to know what do other highly conformant compilers, like CodeWarrior and Comeau, say about Daniel Frey's proposal? Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com

On Mon, 01 Mar 2004 18:09:20 +0000, Paul A Bristow wrote: [Daniel Frey said:]
| I really suggest you look at my code at | <http://groups.yahoo.com/group/boost/files/MathConstants/>, which solves | all of the above points. Except that VC 7.1 doesn't think it is legal C++ :-(( I think we need to establish if it is correct (as gcc and Intel think it is)
Nope, as has been said a number of times, it is not valid C++. typeof is not in the existing C++ standard. It is a very useful extension implemented by a number of vendors, but that doesn't make it standard.
Or to find some workaround that VC 7.1 will accept.
Indeed.
It would be helpful to know what do other highly conformant compilers, like CodeWarrior and Comeau, say about Daniel Frey's proposal?
Well, you still have to get over the boost Guidelines saying: Aim for ISO Standard C++. Than means making effective use of the standard features of the language, and avoiding non-standard compiler extensions. It also means using the C++ Standard Library where applicable. It doesn't forbid using extensions, but I seem to remember David Abrahams being a little more assertive about not using non-standard extensions :-) phil -- change name before "@" to "phil" for email

Phil Richards wrote:
On Mon, 01 Mar 2004 18:09:20 +0000, Paul A Bristow wrote: [Daniel Frey said:]
| I really suggest you look at my code at | <http://groups.yahoo.com/group/boost/files/MathConstants/>, which solves | all of the above points. Except that VC 7.1 doesn't think it is legal C++ :-(( I think we need to establish if it is correct (as gcc and Intel think it is)
Nope, as has been said a number of times, it is not valid C++. typeof is not in the existing C++ standard. It is a very useful extension implemented by a number of vendors, but that doesn't make it standard.
That's not fair. VC7.1 is *not* failing because of my use of typeof. We could provide a fallback for retrieving the return type of the expressions. The point is, that the VC7.1 already failed with an "Internal compiler failure" on previous version that were 100% ISO-C++. Please try to understand the problem first before accusing me of writing offending non-standard code which hurts the poor, innocent VC7.1 :-) Regards, Daniel

Sorry to bang on about this, but we still haven't sorted it out. To re-cap, it seems that the solution proposed a long time ago by Michael Kenniston and recently by Thorsten Ottosen don't give as much 'extendibility' to user defined floating point types (quaddoubles, RWsuper doubles, rational, interval, etc) as some would like. Daniel Frey has produced two solutions which seem to provide this extendibility, BUT 1 His version 2 works on Intel (EDG?) and GCC compilers, but trips VC7.1 (see below). Is this because VC7.1 is 'broken', or is it because it isn't really legal code (or is the language ill-defined in this area). Opinions on this would be most welcome. What the other compilers make of his code may be revelevant? If there is a consensus that VC is wrong, then we can perhaps get it fixed? 2 Daniel's Version 3 uses typeof which is not yet part of the language - but is very likely to become so eventually. Our other option is to wait until it is added before we try to provide the ultimate 'constants' solution. Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com | -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Daniel Frey | Sent: 01 March 2004 21:40 | To: boost@lists.boost.org | Subject: [boost] Re: [math constants] C++ Language gurus | views needed and Codewarrior & Comeau testers | | | Phil Richards wrote: | > On Mon, 01 Mar 2004 18:09:20 +0000, Paul A Bristow wrote: | > [Daniel Frey said:] | > | >>| I really suggest you look at my code at | >>| | <http://groups.yahoo.com/group/boost/files| /MathConstants/>, | which solves | >>| all of the above points. | | >>Except that VC 7.1 doesn't think it is legal C++ :-(( | >>I think we need to establish if it is correct (as gcc and | Intel think it | >>is) | > | > Nope, as has been said a number of times, it is not valid | C++. typeof is | > not in the existing C++ standard. It is a very useful extension | > implemented by a number of vendors, but that doesn't make | it standard. | | That's not fair. VC7.1 is *not* failing because of my use of | typeof. We | could provide a fallback for retrieving the return type of the | expressions. The point is, that the VC7.1 already failed with an | "Internal compiler failure" on previous version that were | 100% ISO-C++. | Please try to understand the problem first before accusing me | of writing | offending non-standard code which hurts the poor, innocent VC7.1 :-) |

On Mon, 01 Mar 2004 22:40:06 +0100, Daniel Frey wrote:
That's not fair. VC7.1 is *not* failing because of my use of typeof. We could provide a fallback for retrieving the return type of the expressions. The point is, that the VC7.1 already failed with an "Internal compiler failure" on previous version that were 100% ISO-C++.
I'd like to test it and report to vendor (assuming VC71 is to blame here). Where is the code (the one without "typeof") I could test? Thanks B.

I believe it is in the files section math constants - second try by Daniel Frey. Daniel Frey's constant library milestone 2 /MathConstants/constant_library_m2_v1.tgz 21 Aug 2003 (The typeof using version is _v2 dated 24 Jan 2004 A test (and views on the sighnificance of the result) would most helpful. (Or even better if you can say if any workaround is possible). Thanks Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com | -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Bronek Kozicki | Sent: 07 March 2004 16:56 | To: boost@lists.boost.org | Subject: [boost] Re: [math constants] C++ Language gurus | views needed andCodewarrior & Comeau testers | | | On Mon, 01 Mar 2004 22:40:06 +0100, Daniel Frey wrote: | > That's not fair. VC7.1 is *not* failing because of my use | of typeof. We | > could provide a fallback for retrieving the return type of the | > expressions. The point is, that the VC7.1 already failed with an | > "Internal compiler failure" on previous version that were | 100% ISO-C++. | | I'd like to test it and report to vendor (assuming VC71 is to blame | here). Where is the code (the one without "typeof") I could test? | | Thanks | | | B. | | _______________________________________________ | Unsubscribe & other changes: | http://lists.boost.org/mailman/listinfo.cg| i/boost | |

I believe it is in the files section math constants - second try by Daniel Frey. Daniel Frey's constant library milestone 2 /MathConstants/constant_library_m2_v1.tgz 21 Aug 2003 (The typeof using version is _v2 dated 24 Jan 2004 A test (and views on the sighnificance of the result) would most helpful. (Or even better if you can say if any workaround is possible). Thanks Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com | -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Bronek Kozicki | Sent: 07 March 2004 16:56 | To: boost@lists.boost.org | Subject: [boost] Re: [math constants] C++ Language gurus | views needed andCodewarrior & Comeau testers | | | On Mon, 01 Mar 2004 22:40:06 +0100, Daniel Frey wrote: | > That's not fair. VC7.1 is *not* failing because of my use | of typeof. We | > could provide a fallback for retrieving the return type of the | > expressions. The point is, that the VC7.1 already failed with an | > "Internal compiler failure" on previous version that were | 100% ISO-C++. | | I'd like to test it and report to vendor (assuming VC71 is to blame | here). Where is the code (the one without "typeof") I could test? | | Thanks | | | B. | | _______________________________________________ | Unsubscribe & other changes: | http://lists.boost.org/mailman/listinfo.cg| i/boost | |

On Sun, 7 Mar 2004 17:54:37 -0000, Paul A Bristow wrote:
Daniel Frey's constant library milestone 2
/MathConstants/constant_library_m2_v1.tgz 21 Aug 2003
Ok, thanks. I have it. After some fixing (change file extension from .cc to .cpp, change line endings from LF to CRLF, append one more directory to INCLUDE) I received following error: example.cpp(18) : error C3200: 'boost::math::pi_value<T>' : invalid template argument for template parameter 'F', expected a class template example.cpp(18) : see reference to class template instantiation 'boost::math::pi_value<T>' being compiled example.cpp(81) : fatal error C1903: unable to recover from previous error(s); stopping compilation I have stripped down problematic code to very simple: #include <iostream> template <template <typename> class F, typename T> struct constant_value { T operator()() const { return T(); } }; template <typename T> struct pi_value : constant_value <pi_value, T> {}; int main() { pi_value<double> t; std::cout << t(); } and tried it under Comeau (online), with no problems. It also compiles fine under GCC 3.3.1 (mingw). From my (limited) understanding of templates this code is fine, thus apparently there's problem with VC71. Looks like using template being just defined as template template parameter makes VC71 confused. I reported it to Microsoft (on its private newsgroup). B.

Many thanks - that is most helpful and may eventually solve the problem. Paul | -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Bronek Kozicki | Sent: 07 March 2004 19:45 | To: boost@lists.boost.org | Subject: [boost] Re: Re: [math constants] C++ Language gurus | views neededandCodewarrior & Comeau testers | | | On Sun, 7 Mar 2004 17:54:37 -0000, Paul A Bristow wrote: | > Daniel Frey's constant library milestone 2 | > | > /MathConstants/constant_library_m2_v1.tgz 21 Aug 2003 | | Ok, thanks. I have it. After some fixing (change file | extension from .cc | to .cpp, change line endings from LF to CRLF, append one more | directory | to INCLUDE) I received following error: | | example.cpp(18) : error C3200: 'boost::math::pi_value<T>' : invalid | template argument for template parameter 'F', expected a | class template | example.cpp(18) : see reference to class template | instantiation | 'boost::math::pi_value<T>' being compiled | example.cpp(81) : fatal error C1903: unable to recover from previous | error(s); stopping compilation | | I have stripped down problematic code to very simple: | | #include <iostream> | | template <template <typename> class F, typename T> struct | constant_value | { | T operator()() const | { | return T(); | } | }; | | template <typename T> struct pi_value : constant_value | <pi_value, T> {}; | | int main() | { | pi_value<double> t; | std::cout << t(); | } | | and tried it under Comeau (online), with no problems. It also compiles | fine under GCC 3.3.1 (mingw). From my (limited) understanding of | templates this code is fine, thus apparently there's problem | with VC71. | Looks like using template being just defined as template template | parameter makes VC71 confused. I reported it to Microsoft (on its | private newsgroup). | | | B. | | _______________________________________________ | Unsubscribe & other changes: | http://lists.boost.org/mailman/listinfo.cg| i/boost | |

On Sun, 7 Mar 2004 22:53:43 -0000, Paul A Bristow wrote:
Many thanks - that is most helpful and may eventually solve the problem.
It's just a beginning :) anyway, Jim Apple pointed out that using namespace qualifier can fix *this* problem, indeed it did. After changing line 18 of example.cc (example.cpp on my computer) to: template< typename T > struct pi_value : constant_value< boost::math::pi_value, T > {}; I received nice INTERNAL COMPILER ERROR. Now I need to reproduce this error in some smaller sample code, and then post it to MS newsgroups. This task have to wait (it's midnight here in Poland, and I have plenty of work starting tommorow morning - deadlines are killing me :( ). Kind regards B.

Bronek Kozicki wrote:
On Sun, 7 Mar 2004 22:53:43 -0000, Paul A Bristow wrote:
Many thanks - that is most helpful and may eventually solve the problem.
It's just a beginning :) anyway, Jim Apple pointed out that using namespace qualifier can fix *this* problem, indeed it did. After
Well, we knew that already. Look at the last 4 messages from this thread: <http://thread.gmane.org/gmane.comp.lib.boost.devel/29507>
I received nice INTERNAL COMPILER ERROR. Now I need to reproduce this error in some smaller sample code, and then post it to MS newsgroups.
That is the real problem. And I think that the code in question is standard conformant C++, if someone thinks it isn't please provide some reason. I am not using Windows (thus no VC), so I can only speculate: The problem might be connected to the use of template<typename T> operator T() but that's just a wild guess. I just seem to remember that I read about the VC having a small problem there. If this is in fact the problem, we might be lucky as my newest version no longer uses this conversion, instead I use a get<T>-function. As the documentation is making only slow progress (that's not: "no progress" :), I think I'll try to hack together a non-typeof-version to give you some more stuff to test. Maybe this evening, otherwise it will be by the end of the week. Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

Daniel Frey wrote:
As the documentation is making only slow progress (that's not: "no progress" :), I think I'll try to hack together a non-typeof-version to give you some more stuff to test. Maybe this evening, otherwise it will be by the end of the week.
OK, I uploaded a new version (m3) to the files section. It fixes the bug with the template template parameter mentioned and it doesn't use typeof. You can reenable typeof (and thus added functionality) by defining BOOST_HAS_TYPEOF in the new header file constant/config.hpp. The example-program included (which is still the same as in m2) works without the typeof, but the unit-library examples won't work. This is IMHO not a big problem as we can add better workaround for missing typeof later (other Boost-libs show what's possible, see bind/lambda). The m3-version should thus be a standard conformant version which can be tested on any compiler. Please give it a try and report results (and probably analysis and workarounds when it fails) here, thanks. Regards, Daniel

On Mon, 08 Mar 2004 20:11:19 +0100, Daniel Frey wrote:
tested on any compiler. Please give it a try and report results (and probably analysis and workarounds when it fails) here, thanks.
Good news is that there is no ICE, bad news is that it does not compile. I have a lot of compilation errors, please find attached file. Regards B.

Bronek Kozicki wrote:
On Mon, 08 Mar 2004 20:11:19 +0100, Daniel Frey wrote: Good news is that there is no ICE, bad news is that it does not compile. I have a lot of compilation errors, please find attached file.
There is no attachment. Can you repost it, please? (Or is it a problem on my side and anyone else sees it?) Regards, Daniel

OK, thanks for the tests so far. What we can see is that operator T() caused the ICE (as I suspected), but now we need to find out what exactly the problems with the current version is. It seems to me that the VC7.1 has problems deducing template template parameters. Could the interested folks please test whether is_constant works as expected? It's AFAICS the basic requirement for anything else to work. The next step is to test whether it's a problem for the VC to deduce parameters from base classes. Here's some code to illustrate the idea: template< typename T > class V {}; template< template<typename> class T > struct B {}; struct D : B<V> {}; template< typename T > void f( const B<V>& ) {} int main() { D d; f( d ); } Regards, Daniel

Daniel Frey <d.frey@gmx.de> wrote: [...] I tried following code: #include <iostream> template <typename T> class V {}; template <template <typename> class T> struct B {}; struct D : B<V> {}; template <typename T> void f (const B<T>&) { std::cout << typeid(T).name() << std::endl; } int main() { D d; f (d); } According to Comeau compiler and GCC this program is invalid. I have following error messages (from GCC 3.3.1): T246.cpp:6: error: type/value mismatch at argument 1 in template parameter list for `template<template<class> class T> struct B' T246.cpp:6: error: expected a class template, got `T' T246.cpp:7: error: ISO C++ forbids declaration of `parameter' with no type T246.cpp: In function `int main()': T246.cpp:13: error: no matching function for call to `f(D&)' (from Comeau online 4.3.3 beta) "ComeauTest.c", line 6: error: template parameter "T" is not a class template void f (const B<T>&) ^ "ComeauTest.c", line 13: error: no instance of function template "f" matches the argument list The argument types that you used are: (D) f (d); ^ ... however it compiles under VC71, and the output of this program is: class V I think that's a surprise? B.

Bronek Kozicki wrote:
Daniel Frey <d.frey@gmx.de> wrote: [...]
I tried following code:
#include <iostream> template <typename T> class V {}; template <template <typename> class T> struct B {}; struct D : B<V> {}; template <typename T> void f (const B<T>&) { std::cout << typeid(T).name() << std::endl; } int main() { D d; f (d); }
According to Comeau compiler and GCC this program is invalid. I have
Yes, the code is invalid. The correct code (used in the constant library) looks like this: template<template <typename> class T> void f( const B<T>& ) {} T is than deduced to V. V is not a valid class on itself, it's just a valid template for a template template parameter. However:
.... however it compiles under VC71, and the output of this program is: class V
I think that's a surprise?
Nope. My skills in guessing VC-bugs just seem to get better every day :) Could you ask on some MS-support-groups about this, please? I think it's wrong to compile the code and deduce T to V, as V is not a class. The MS-folks should please either confirm the bug or kindly point me to the standard text that allows this behaviour. Regards, Daniel

Out of curiousity: What does the VC say abou this: #include <iostream> template <typename T> struct V { void g() const { std::cout << typeid(T).name() << std::endl; } }; template <template <typename> class T> struct B {}; struct D : B<V> {}; template <typename U> void f (const B<U>&) { U<double> v; v.g(); } int main() { D d; f(d); } Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

Daniel Frey <daniel.frey@aixigo.de> wrote:
template <typename U> void f (const B<U>&) { U<double> v; v.g(); }
There's an error: C:\DATA\USERS\bronislaw\My Documents\msys\T248.cpp(15) : error C2143: syntax error : missing ';' before '<' C:\DATA\USERS\bronislaw\My Documents\msys\T248.cpp(22) : see reference to function template instantiation 'void f<V>(const B<T> &)' being compiled with [ T=V ] C:\DATA\USERS\bronislaw\My Documents\msys\T248.cpp(15) : error C2143: syntax error : missing ';' before '<' C:\DATA\USERS\bronislaw\My Documents\msys\T248.cpp(16) : error C2065: 'v' : undeclared identifier C:\DATA\USERS\bronislaw\My Documents\msys\T248.cpp(16) : error C2228: left of '.g' must have class/struct/union type type is ''unknown-type'' I think that instead should be: template <template <typename> class U> void f (const B<U>&) { U<double> v; v.g(); } after this small change it compiles fine, and result is: double Regards B.

Bronek Kozicki wrote:
Daniel Frey <daniel.frey@aixigo.de> wrote:
template <typename U> void f (const B<U>&) { U<double> v; v.g(); }
There's an error:
Obviously, as that was on purpose.
I think that instead should be:
template <template <typename> class U> void f (const B<U>&) { U<double> v; v.g(); }
after this small change it compiles fine, and result is: double
Hm. Well, this means that the VC seems to accept the correct code in *some* cases, but not always? I'm puzzled and I don't know how to help you to find the problem. Can you try to reduce the _m3 to a small example which still shows some of the problems you reported? TIA. Regards, Daniel

On Mon, 08 Mar 2004 10:47:49 +0100, Daniel Frey wrote:
but that's just a wild guess. I just seem to remember that I read about the VC having a small problem there. If this is in fact the problem, we might be lucky as my newest version no longer uses this conversion, instead I use a get<T>-function.
I can reproduce this ICE on following code: template<template <typename> class F> struct constant { template <typename T> operator T() const { return F <T>()(); } }; template <typename T> struct map_type; template <template<typename> class F, typename T> struct constant_value { T operator()() const { return F<typename ::map_type<T> ::type>()(); } }; template <typename T> struct pi_value : constant_value< ::pi_value, T > {}; template <> struct pi_value <float> {float operator()() const {return 3.14;}}; struct pi_t : constant <pi_value> {} const pi = pi_t(); int main() { const float f2 = pi; // ICE here } possibly it can be made smaller, I just finished cutting it at this moment and sent to private MS newsgroup asking for support. Comeau and GCC both happily accept this code, and it just looks OK. However it's bit too complicated and I'm too tired to look into it deeper. I hope someone from VC71 developers will now take a look. VC71 quite often bulks on invalid code, but if this one is valid (I certainly think so) then we have issue that have to be fixed . In the meantime if you can come up with some variations of the above, just send an email and I will test it. BTW: problem with operator() and VC71 is that it does not always recognize operator() as function, in context of pointer to member function. However it does not ICE on that problem. Regards B.

Phil Richards <news@derived-software.ltd.uk> writes:
On Mon, 01 Mar 2004 18:09:20 +0000, Paul A Bristow wrote: [Daniel Frey said:]
| I really suggest you look at my code at | <http://groups.yahoo.com/group/boost/files/MathConstants/>, which solves | all of the above points. Except that VC 7.1 doesn't think it is legal C++ :-(( I think we need to establish if it is correct (as gcc and Intel think it is)
Nope, as has been said a number of times, it is not valid C++. typeof is not in the existing C++ standard. It is a very useful extension implemented by a number of vendors, but that doesn't make it standard.
Or to find some workaround that VC 7.1 will accept.
Indeed.
It would be helpful to know what do other highly conformant compilers, like CodeWarrior and Comeau, say about Daniel Frey's proposal?
Well, you still have to get over the boost Guidelines saying: Aim for ISO Standard C++. Than means making effective use of the standard features of the language, and avoiding non-standard compiler extensions. It also means using the C++ Standard Library where applicable.
It doesn't forbid using extensions, but I seem to remember David Abrahams being a little more assertive about not using non-standard extensions :-)
To be precise, code should usually not *rely* on non-standard extensions. It's fine to use non-standard extensions if they can make the library perform better, use less code, etc., but there should be a fallback position for compilers that don't support the extension. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Le lun 01/03/2004 à 01:06, Thorsten Ottosen a écrit :
namespace std {
#define CNAME( Var ) Var##_constant_t
#define OVERLOAD_CONTEXT( ConstType, FP, FPV ) \ inline FP operator+( FP l, ConstType ) \ { return l + FPV; } \ inline FP operator+( ConstType, FP r ) \ { return r + FPV; } \ inline FP operator-( FP l, ConstType ) \ { return l - FPV; } \ inline FP operator-( ConstType, FP r ) \ { return FPV - r; } \ inline FP operator*( FP l, ConstType ) \ { return l * FPV; } \ inline FP operator*( ConstType, FP r ) \ { return r * FPV; } \ inline FP operator/( FP l, ConstType ) \ { return l / FPV; } \ inline FP operator/( ConstType, FP r ) \ { return FPV / r; } \
#define DEFINE_FP_CONSTANT( Name, FV, DV, LDV ) \ struct CNAME( Name ) \ { \ CNAME( Name ) () {} \ operator float() const { return FV; } \ operator double() const { return DV; } \ operator long double() const { return LDV; } \ }; \ OVERLOAD_CONTEXT( CNAME( Name ), float, FV ) \ OVERLOAD_CONTEXT( CNAME( Name ), double, DV ) \ OVERLOAD_CONTEXT( CNAME( Name ), long double, LDV ) \ const CNAME( Name ) Name;
DEFINE_FP_CONSTANT( pi, 3.14F, 3.14232, 3.1423211223L )
} // namespace std
Unless I'm missing something, it seems to me that the constants can only be defined for built-in floating-point numbers. Indeed, once the structure for a pi constant has been defined by DEFINE_FP_CONSTANT (in the math_constant.hpp header), the user or others libraries cannot add new values for their own numerical types. With respect to that, I think the proposal of Daniel Frey is a lot more interesting since it allows user-defined types and provides automatic type deduction so that complex constants do not have to have their own names. Being able to write "interval<double> a = 2 * pi;" and being sure it is mathematically correct and accurate is great. Regards, Guillaume
participants (8)
-
Bronek Kozicki
-
Daniel Frey
-
Daniel Frey
-
David Abrahams
-
Guillaume Melquiond
-
Paul A Bristow
-
Phil Richards
-
Thorsten Ottosen