March 27, 2010
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/
March 27, 2010
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
March 27, 2010
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!
>
March 27, 2010
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/
March 27, 2010
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.
March 27, 2010
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
March 27, 2010
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/
March 28, 2010
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
March 28, 2010
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/
March 28, 2010
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/