www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - generic + numeric + literals = abomination

reply so <so so.do> writes:
In C++!

I have a type defined in the core library like..
typedef float scalar;
//typedef double scalar; // <-- whole framework is now double precision

Next i instantiate vectors, matrices etc... from templates.
typedef vector_t<scalar, 3> vector;
typedef matrix_t<scalar, 3, 3> matrix;

Until now everything cool, here pain comes...

const scalar a = scalar(0.2) * math::consts<scalar>::pi; // can't drop  
cast, since 0.2 is double
const scalar b = a * scalar(0.9) + scalar(5); // " "
const vector v = vector(8.0) * scalar(3.0); // can't drop cast, error
...

Since D is superb, i like to know how you do it in D.
If you got a better idea in C++, i would like to hear that too!

Thanks!

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 27 2010
next sibling parent reply Robert Clipsham <robert octarineparrot.com> writes:
On 27/03/10 10:20, so wrote:
 In C++!

 I have a type defined in the core library like..
 typedef float scalar;
 //typedef double scalar; // <-- whole framework is now double precision

alias float scalar; //alias double scalar;
 Next i instantiate vectors, matrices etc... from templates.
 typedef vector_t<scalar, 3> vector;
 typedef matrix_t<scalar, 3, 3> matrix;

alias Vector!(scalar, 3) vector; // Presuming you have defined // the Vector!() template somewhere alias Matrix!(scalar, 3, 3) matrix; // Presuming Matrix!() is defined
 Until now everything cool, here pain comes...

 const scalar a = scalar(0.2) * math::consts<scalar>::pi; // can't drop
 cast, since 0.2 is double

const scalar a = 0.2 * PI; // PI is defined in std.math
 const scalar b = a * scalar(0.9) + scalar(5); // " "

const scalar b = a * 0.9 * 5.0;
 const vector v = vector(8.0) * scalar(3.0); // can't drop cast, error

const vector v = vector(8.0) * 3.0;
 ...

 Since D is superb, i like to know how you do it in D.
 If you got a better idea in C++, i would like to hear that too!

 Thanks!

There are a few vector implementations for D out there, or you can roll your own. I'm pretty sure there's matrices out there too, I haven't checked though (I'm pretty sure D's built in arrays will do the trick, I'm not an expert though).
Mar 27 2010
parent so <so so.do> writes:
On Sat, 27 Mar 2010 13:32:24 +0200, Robert Clipsham  
<robert octarineparrot.com> wrote:

 On 27/03/10 10:20, so wrote:
 In C++!

 I have a type defined in the core library like..
 typedef float scalar;
 //typedef double scalar; // <-- whole framework is now double precision

alias float scalar; //alias double scalar;
 Next i instantiate vectors, matrices etc... from templates.
 typedef vector_t<scalar, 3> vector;
 typedef matrix_t<scalar, 3, 3> matrix;

alias Vector!(scalar, 3) vector; // Presuming you have defined // the Vector!() template somewhere alias Matrix!(scalar, 3, 3) matrix; // Presuming Matrix!() is defined
 Until now everything cool, here pain comes...

 const scalar a = scalar(0.2) * math::consts<scalar>::pi; // can't drop
 cast, since 0.2 is double

const scalar a = 0.2 * PI; // PI is defined in std.math
 const scalar b = a * scalar(0.9) + scalar(5); // " "

const scalar b = a * 0.9 * 5.0;
 const vector v = vector(8.0) * scalar(3.0); // can't drop cast, error

const vector v = vector(8.0) * 3.0;
 ...

 Since D is superb, i like to know how you do it in D.
 If you got a better idea in C++, i would like to hear that too!

 Thanks!

There are a few vector implementations for D out there, or you can roll your own. I'm pretty sure there's matrices out there too, I haven't checked though (I'm pretty sure D's built in arrays will do the trick, I'm not an expert though).

Even the example looks/sounds simple, i am not that new in C++/D programming :) If one comes to D from C++, he is most likely pushing limits of the C++ templates/numerics. PI was just an example, i could find another constant, but then you would point me to a SI unit implementation. :) For : const scalar a = 0.2 * PI; // both double implicit cast to scalar, when it is float, this must produce a warning? const scalar b = a * 0.9 * 5.0; // same const vector v = vector(8.0) * 3.0; // 3.0 is a double, when scalar is float, this line must not compile I think you should try it first, DMD should also give warnings/errors here. Thanks! -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 27 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
so:
 Since D is superb, i like to know how you do it in D.
 If you got a better idea in C++, i would like to hear that too!

You know there are float literal too, in C++/D, like: 5.5f I don't think D can help you more than C++ here. Can you explain better what the problem is and what kind of solution you would like? Bye, bearophile
Mar 27 2010
next sibling parent so <so so.do> writes:
On Sat, 27 Mar 2010 13:52:28 +0200, bearophile <bearophileHUGS lycos.com>  
wrote:

 so:
 Since D is superb, i like to know how you do it in D.
 If you got a better idea in C++, i would like to hear that too!

You know there are float literal too, in C++/D, like: 5.5f I don't think D can help you more than C++ here. Can you explain better what the problem is and what kind of solution you would like? Bye, bearophile

You are right, i guess i wasn't clear enough. In 5.5f, f is the float literal, i am trying to write generic code. Say i changed the type to f64(double), or f128 by just changing a line. typedef f128 scalar; // or in D alias f128 scalar; So each cast above will be like f128(5.5f)... What have i gained by increasing precision to 64 or 128 bit here? Clear enough? :) Thanks! -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 27 2010
prev sibling next sibling parent reply so <so so.do> writes:
On Sat, 27 Mar 2010 13:52:28 +0200, bearophile <bearophileHUGS lycos.com>  
wrote:

 Can you explain better what the problem is and what kind of solution you  
 would like?

 Bye,
 bearophile

One thing i can think of now is adding another float literal, maybe 'r', for "real"!, Which means you are free to cast this to any floating point suitable. Some kind of template, i don't know! So when i have something like this : scalar m = 0.99999999999999999999999999r; when scalar is f32 : scalar m = 0.99999999999999999999999999f; when scalar is f64 : scalar m = 0.99999999999999999999999999; ... And it is easy to detect for the compiler i guess. scalar m = 0.2r; // just cast it to scalar, user wants to assign to a scalar scalar n = m * 4.5r; // again just cast it to scalar, user wants to multiply by a scalar. ... Thanks :) -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 27 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
so:
 One thing i can think of now is adding another float literal, maybe 'r',  
 for "real"!,

See here, Unfortunately it's called "L" not "r": http://www.digitalmars.com/d/2.0/lex.html FloatSuffix: f F RealSuffix: L bearophile
Mar 27 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
so:
 When i have the code :
 scalar m = 0.5fp;
 
 I want compiler to implicitly cast it to typeof(scalar).
 so when the scalar is float, m will be 0.5f.

I am starting to understand, sorry if I am a dumb bear :-) Programming in C++/D is usually much less hard than understanding humans. I think you mean an universal FP literal that's automatically cast-able to any other floating point type, in template arguments too. Are you able to write a 10 lines long D program that shows a compile-time error that you don't want to happen? I am willing to fix your code until it shows what you want to show me (assuming it's a real problem in D). Bye, bearophile
Mar 27 2010
next sibling parent biozic <dransic free.fr> writes:
Le 27/03/10 18:18, so a écrit :
 With this in mind, just one thing bugs me.

 ----
 import std.stdio;

 struct vector(T) {
 this(T m) { mm = m; }
 vector!T opBinary(string s)(T m) if(s=="*") {
 return vector!T(mm * m);
 }
 T mm;
 }

 void test(T)() {
 vector!T v = vector!T(0.5);
 vector!T u = v * 0.3;
 writeln("u: ", u.mm);
 }

 void main() {
 test!float();
 test!double();
 test!real();
 }
 -----

 This program compiles and runs just fine, but i feel dirty, you see I
 explicitly stated that opBinary takes a variable of type T,
 but it accepted 0.3 on all 3 tests, implicitly casted double to T. In
 C++ world this brings tons of trouble, especially performance problems,

In this case, when is(T==real), you could have a precision problem more than a performance problem. You lose less precision if you always use literals of the most precise type (eg 0.3L). Performance problems could occur in C++ when your template type is 'long double' (?). But then if 'double' is the most efficient type and if you want performance, use it explictly everywhere.
Mar 27 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
so:
 With this in mind, just one thing bugs me.
 
 ----
 import std.stdio;
 
 struct vector(T) {
 	this(T m) { mm = m; }
 	vector!T opBinary(string s)(T m) if(s=="*") {
 		return vector!T(mm * m);
 	}
 	T mm;
 }
 
 void test(T)() {
 	vector!T v = vector!T(0.5);
 	vector!T u = v * 0.3;
 	writeln("u: ", u.mm);
 }
 
 void main() {
 	test!float();
 	test!double();
 	test!real();
 }
 -----
 
 This program compiles and runs just fine, but i feel dirty, you see I  
 explicitly stated that opBinary takes a variable of type T,
 but it accepted 0.3 on all 3 tests, implicitly casted double to T. In C++  
 world this brings tons of trouble, especially performance problems,
 but here i am not sure what DMD does that there :)

Are you trying to do this? import std.stdio: writeln; struct Vector(T) { this(T m) { mm = m; } Vector opBinary(string op:"*", T2)(T2 m) if(is(T2 == T)) { return Vector(mm * m); } T mm; } void test(T)() { Vector!T v = Vector!T(0.5); Vector!T u = v * 0.3; writeln("u: ", u.mm); } void main() { //test!float(); test!double(); //test!real(); } Bye, bearophile
Mar 27 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
so:

 With one exception yes, i want all 3 test pass with your fix to implicit  
 cast.
 You know, we are trying to write generic code.

I don't understand your problem/needs, sorry. Bye, bearophile
Mar 28 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
so:

 Well, i am having hard time explaining, it is not a surprise that you  
 don't understand.

I think I have understood you this time. Writing skills are important for a programmer :-) Is this what you are asking for? But it's not very good code: import std.stdio: writeln; struct Vector(T) { this(T m) { mm = m; } this(int m) { mm = cast(T)m; } Vector opBinary(string op:"*", T2)(T2 m) { return Vector(mm * m); } T mm; } void test(T)() { auto v = Vector!T(5); auto u = v * 3; writeln("u: ", u.mm); } void main() { test!ubyte(); test!ushort(); test!uint(); test!ulong(); } Bye, bearophile
Mar 28 2010
prev sibling next sibling parent biozic <dransic free.fr> writes:
Le 28/03/10 10:57, so a écrit :
 Well, i am having hard time explaining, it is not a surprise that you
 don't understand.
 To make things clearer, lets forget floats for a seconds and change your
 code to standard unsigned types.


 import std.stdio: writeln;

 struct Vector(T) {
 this(T m) { mm = m; }
 Vector opBinary(string op:"*", T2)(T2 m) if(is(T2 == T)) {
 return Vector(mm * m);
 }
 T mm;
 }

Have you checked std.traits, where isIntegral!T, isFloatingPoint!T, etc. are defined? Could these, used as template constraints, solve your problem?
Mar 28 2010
prev sibling parent #ponce <nospam nospam.com> writes:
so Wrote:

 Basically what i am asking is hmmm, ability to write generic constants? :)
 
 Thanks!

Hi, When writing generic FP code i always use real literals and cast to T, or int. I suggest doing this. Like: T exp3(T)(T x) { if (x < cast(T)(-1.15365L)) { return 0; } else { return cast(T)1.L + x * (cast(T)1.0L + x * (cast(T)0.5L + x * cast(T)0.3333333333333L)); } } I assume the compiler will be able to optimize the cast in release mode. If you really wan't to prevent this cast in debug mode, you can simply go with: const T myConst = 0.3L; then the cast will be compile-time.
Mar 28 2010
prev sibling next sibling parent so <so so.do> writes:
On Sat, 27 Mar 2010 15:28:22 +0200, bearophile <bearophileHUGS lycos.com>  
wrote:

 so:
 One thing i can think of now is adding another float literal, maybe 'r',
 for "real"!,

See here, Unfortunately it's called "L" not "r": http://www.digitalmars.com/d/2.0/lex.html FloatSuffix: f F RealSuffix: L bearophile

Yes, it says : "Floating literals with no suffix are of type double. Floats can be followed by one f, F, or L suffix. The f or F suffix means it is a float, and L means it is a real." Problem remains, i think you either lost me or just didn't read what i wrote, or well.. most probably i am still not clear enough. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 27 2010
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
Note that 'real' is a built in type in D.  It's an 80-bit float on x86
procs and 64-bit elsewhere.
So .5L is like cast(real).5.  Not the solution you were looking for.

--bb

2010/3/27 so <so so.do>:
 On Sat, 27 Mar 2010 15:28:22 +0200, bearophile <bearophileHUGS lycos.com>
 wrote:

 so:
 One thing i can think of now is adding another float literal, maybe 'r'=



 for "real"!,

See here, Unfortunately it's called "L" not "r": http://www.digitalmars.com/d/2.0/lex.html FloatSuffix: =A0 =A0 =A0 =A0f =A0 =A0 =A0 =A0F RealSuffix: =A0 =A0 =A0 =A0L bearophile

Yes, it says : "Floating literals with no suffix are of type double. Floats can be follo=

 by one f, F, or L suffix. The f or F suffix means it is a float, and L me=

 it is a real."

 Problem remains, i think you either lost me or just didn't read what i
 wrote,
 or well.. most probably i am still not clear enough.

 --
 Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

Mar 27 2010
prev sibling next sibling parent so <so so.do> writes:
On Sat, 27 Mar 2010 15:54:19 +0200, Bill Baxter <wbaxter gmail.com> wrote:

 Note that 'real' is a built in type in D.  It's an 80-bit float on x86
 procs and 64-bit elsewhere.
 So .5L is like cast(real).5.  Not the solution you were looking for.

 --bb

That "r for real!" was joke. What i mean is a literal/template/placeholder/younameit, explicitly states that number is a floating point. Lets name it "fp". When i have the code : scalar m = 0.5fp; I want compiler to implicitly cast it to typeof(scalar). so when the scalar is float, m will be 0.5f. Another example : Again, lets try pi. const scalar pi = 3.14{longest you can find}fp Now whenever i switch precision, by changing the type of scalar, i got the pi in that precision. Thanks! :) -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 27 2010
prev sibling next sibling parent so <so so.do> writes:
Oh... wait a second.
In http://www.digitalmars.com/d/2.0/float.html :

"Regardless of the type of the operands, floating point constant folding  
is done in real or greater precision. It is always done following IEEE 754  
rules and round-to-nearest is used.

Floating point constants are internally represented in the implementation  
in at least real precision, regardless of the constant's type. The extra  
precision is available for constant folding. Committing to the precision  
of the result is done as late as possible in the compilation process"

Wow! DMD already doing it, with or without literal!

With this in mind, just one thing bugs me.

----
import std.stdio;

struct vector(T) {
	this(T m) { mm = m; }
	vector!T opBinary(string s)(T m) if(s=="*") {
		return vector!T(mm * m);
	}
	T mm;
}

void test(T)() {
	vector!T v = vector!T(0.5);
	vector!T u = v * 0.3;
	writeln("u: ", u.mm);
}

void main() {
	test!float();
	test!double();
	test!real();
}
-----

This program compiles and runs just fine, but i feel dirty, you see I  
explicitly stated that opBinary takes a variable of type T,
but it accepted 0.3 on all 3 tests, implicitly casted double to T. In C++  
world this brings tons of trouble, especially performance problems,
but here i am not sure what DMD does that there :)

Thanks.

On Sat, 27 Mar 2010 16:44:32 +0200, bearophile <bearophileHUGS lycos.com>  
wrote:

 so:
 When i have the code :
 scalar m = 0.5fp;

 I want compiler to implicitly cast it to typeof(scalar).
 so when the scalar is float, m will be 0.5f.

I am starting to understand, sorry if I am a dumb bear :-) Programming in C++/D is usually much less hard than understanding humans. I think you mean an universal FP literal that's automatically cast-able to any other floating point type, in template arguments too. Are you able to write a 10 lines long D program that shows a compile-time error that you don't want to happen? I am willing to fix your code until it shows what you want to show me (assuming it's a real problem in D). Bye, bearophile

-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 27 2010
prev sibling next sibling parent so <so so.do> writes:
With one exception yes, i want all 3 test pass with your fix to implicit  
cast.
You know, we are trying to write generic code.

Thanks!

On Sat, 27 Mar 2010 22:21:46 +0200, bearophile <bearophileHUGS lycos.com>  
wrote:

 Are you trying to do this?

 import std.stdio: writeln;

 struct Vector(T) {
     this(T m) { mm = m; }
     Vector opBinary(string op:"*", T2)(T2 m) if(is(T2 == T)) {
         return Vector(mm * m);
     }
     T mm;
 }

 void test(T)() {
     Vector!T v = Vector!T(0.5);
     Vector!T u = v * 0.3;
     writeln("u: ", u.mm);
 }

 void main() {
     //test!float();
     test!double();
     //test!real();
 }

 Bye,
 bearophile

-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 27 2010
prev sibling next sibling parent so <so so.do> writes:
Well, i am having hard time explaining, it is not a surprise that you  
don't understand.
To make things clearer, lets forget floats for a seconds and change your  
code to standard unsigned types.


import std.stdio: writeln;

struct Vector(T) {
     this(T m) { mm = m; }
     Vector opBinary(string op:"*", T2)(T2 m) if(is(T2 == T)) {
         return Vector(mm * m);
     }
     T mm;
}

void test(T)() {
     Vector!T v = Vector!T(5);
     Vector!T u = v * 3;
     writeln("u: ", u.mm);
}

void main() {
     test!ubyte();
     test!ushort();
     test!uint();
     test!ulong();
}

All the tests fail as they should, but check it out, what is wrong with  
the templates above?
You can represent 3, and 5 with all these 4 types, but since 3, and 5  
actually is an "int" it fails.
Now think about it again with my proposal in mind. Where we add a generic  
literal, for this situation,
which covers entire unsigned types, lets pick a generic literal for them,  
say... "gu"

void test(T)() {
     Vector!T v = Vector!T(5gu);
     Vector!T u = v * 3gu;
     writeln("u: ", u.mm);
}

Thanks!

On Sun, 28 Mar 2010 12:29:17 +0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 I don't understand your problem/needs, sorry.

 Bye,
 bearophile

-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
prev sibling next sibling parent so <so so.do> writes:
Basically what i am asking is hmmm, ability to write generic constants? :)

Thanks!

On Sun, 28 Mar 2010 12:29:17 +0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 so:

 With one exception yes, i want all 3 test pass with your fix to implicit
 cast.
 You know, we are trying to write generic code.

I don't understand your problem/needs, sorry. Bye, bearophile

-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
prev sibling next sibling parent so <so so.do> writes:
Everything comes to this...
Why "3" is an int?
Why "0.3 is a double?

I guess these constraints was there before generic coding comes out, and  
we are just stuck with it!
If these sound so naive, sorry about it, I don't know compiler/language  
history.

Thanks!

On Sun, 28 Mar 2010 12:29:17 +0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 so:

 With one exception yes, i want all 3 test pass with your fix to implicit
 cast.
 You know, we are trying to write generic code.

I don't understand your problem/needs, sorry. Bye, bearophile

-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
prev sibling next sibling parent so <so so.do> writes:
You didn't change anything there, just back to original code, now just  
enabled implicit cast again!
Please read my next replies, everything should be clear now. :)

Thanks!

On Sun, 28 Mar 2010 14:32:21 +0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 so:

 Well, i am having hard time explaining, it is not a surprise that you
 don't understand.

I think I have understood you this time. Writing skills are important for a programmer :-) Is this what you are asking for? But it's not very good code: import std.stdio: writeln; struct Vector(T) { this(T m) { mm = m; } this(int m) { mm = cast(T)m; } Vector opBinary(string op:"*", T2)(T2 m) { return Vector(mm * m); } T mm; } void test(T)() { auto v = Vector!T(5); auto u = v * 3; writeln("u: ", u.mm); } void main() { test!ubyte(); test!ushort(); test!uint(); test!ulong(); } Bye, bearophile

-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
prev sibling next sibling parent so <so so.do> writes:
I can't think of any solution they might provide sorry.
You know there are C++ equivalents, for years and they didn't solve any =
 =

problems above.
Maybe i can use them to disable implicit casting, but then again program=
  =

won't compile. :P

Thanks!

On Sun, 28 Mar 2010 18:09:21 +0400, biozic <dransic free.fr> wrote:

 Le 28/03/10 10:57, so a =E9crit :
 Well, i am having hard time explaining, it is not a surprise that you=


 don't understand.
 To make things clearer, lets forget floats for a seconds and change y=


 code to standard unsigned types.


 import std.stdio: writeln;

 struct Vector(T) {
 this(T m) { mm =3D m; }
 Vector opBinary(string op:"*", T2)(T2 m) if(is(T2 =3D=3D T)) {
 return Vector(mm * m);
 }
 T mm;
 }

Have you checked std.traits, where isIntegral!T, isFloatingPoint!T, et=

 are defined? Could these, used as template constraints, solve your  =

 problem?

-- = Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
prev sibling parent so <so so.do> writes:
Why a generic code have to be ugly?
At this age of compilers and languages, and the capabilities of DMD?
Why that many casts? or implicit casts?
DMD already doing it behind the scenes with constant folding,
not sure but i think literals stay that way mostly because of C  
compatibility!

Thanks.

On Sun, 28 Mar 2010 19:09:18 +0400, #ponce <nospam nospam.com> wrote:

 so Wrote:

 Basically what i am asking is hmmm, ability to write generic constants?  
 :)

 Thanks!

Hi, When writing generic FP code i always use real literals and cast to T, or int. I suggest doing this. Like: T exp3(T)(T x) { if (x < cast(T)(-1.15365L)) { return 0; } else { return cast(T)1.L + x * (cast(T)1.0L + x * (cast(T)0.5L + x * cast(T)0.3333333333333L)); } } I assume the compiler will be able to optimize the cast in release mode. If you really wan't to prevent this cast in debug mode, you can simply go with: const T myConst = 0.3L; then the cast will be compile-time.

-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
prev sibling next sibling parent so <so so.do> writes:
On Sat, 27 Mar 2010 12:20:38 +0200, so <so so.do> wrote:

I haven't seen a single C++ library able to do this properly. (I would  
just copy it!)
This is one of the reasons why something like  
std::numeric_limits<type>::function() exists.
Which makes a generic and *clean* numeric code in C++ nonexistent.

Don! Please enlighten us! (especially me...) *begs*

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 27 2010
prev sibling parent Jesse Phillips <jessekphillips+D gmail.com> writes:
I think you would end up creating a scalar class/struct with operator
overloading to get the behavior you are looking for. I realize that is
more overhead than what you would want but I don't see another way.

so wrote:

 In C++!

 I have a type defined in the core library like..
 typedef float scalar;
 //typedef double scalar; // <-- whole framework is now double precision

 Next i instantiate vectors, matrices etc... from templates.
 typedef vector_t<scalar, 3> vector;
 typedef matrix_t<scalar, 3, 3> matrix;

 Until now everything cool, here pain comes...

 const scalar a = scalar(0.2) * math::consts<scalar>::pi; // can't drop  
 cast, since 0.2 is double
 const scalar b = a * scalar(0.9) + scalar(5); // " "
 const vector v = vector(8.0) * scalar(3.0); // can't drop cast, error
 ...

 Since D is superb, i like to know how you do it in D.
 If you got a better idea in C++, i would like to hear that too!

 Thanks!

Mar 27 2010