digitalmars.D.learn - generic + numeric + literals = abomination
- so (18/18) Mar 27 2010 In C++!
- Robert Clipsham (13/29) Mar 27 2010 alias float scalar;
- so (18/53) Mar 27 2010 Even the example looks/sounds simple, i am not that new in C++/D
- bearophile (6/8) Mar 27 2010 You know there are float literal too, in C++/D, like: 5.5f
- so (14/23) Mar 27 2010 You are right, i guess i wasn't clear enough.
- so (22/26) Mar 27 2010 One thing i can think of now is adding another float literal, maybe 'r',...
- bearophile (9/11) Mar 27 2010 See here, Unfortunately it's called "L" not "r":
- so (11/22) Mar 27 2010 Yes, it says :
- Bill Baxter (8/35) Mar 27 2010 Note that 'real' is a built in type in D. It's an 80-bit float on x86
- so (17/21) Mar 27 2010 That "r for real!" was joke.
- bearophile (6/11) Mar 27 2010 I am starting to understand, sorry if I am a dumb bear :-) Programming i...
- so (41/57) Mar 27 2010 Oh... wait a second.
- biozic (7/32) Mar 27 2010 In this case, when is(T==real), you could have a precision problem more
- bearophile (22/53) Mar 27 2010 Are you trying to do this?
- so (8/29) Mar 27 2010 With one exception yes, i want all 3 test pass with your fix to implicit...
- bearophile (4/7) Mar 28 2010 I don't understand your problem/needs, sorry.
- so (41/44) Mar 28 2010 Well, i am having hard time explaining, it is not a surprise that you
- bearophile (25/27) Mar 28 2010 I think I have understood you this time. Writing skills are important fo...
- so (8/36) Mar 28 2010 You didn't change anything there, just back to original code, now just
- biozic (3/15) Mar 28 2010 Have you checked std.traits, where isIntegral!T, isFloatingPoint!T, etc....
- so (13/32) Mar 28 2010 I can't think of any solution they might provide sorry.
- so (6/13) Mar 28 2010 Basically what i am asking is hmmm, ability to write generic constants? ...
- so (12/19) Mar 28 2010 Everything comes to this...
-
so
(9/9)
Mar 27 2010
On Sat, 27 Mar 2010 12:20:38 +0200, so
wrote: - Jesse Phillips (4/20) Mar 27 2010 I think you would end up creating a scalar class/struct with operator
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
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 precisionalias 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 definedUntil now everything cool, here pain comes... const scalar a = scalar(0.2) * math::consts<scalar>::pi; // can't drop cast, since 0.2 is doubleconst scalar a = 0.2 * PI; // PI is defined in std.mathconst 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, errorconst 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
On Sat, 27 Mar 2010 13:32:24 +0200, Robert Clipsham <robert octarineparrot.com> wrote:On 27/03/10 10:20, so wrote: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/In C++! I have a type defined in the core library like.. typedef float scalar; //typedef double scalar; // <-- whole framework is now double precisionalias 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 definedUntil now everything cool, here pain comes... const scalar a = scalar(0.2) * math::consts<scalar>::pi; // can't drop cast, since 0.2 is doubleconst scalar a = 0.2 * PI; // PI is defined in std.mathconst 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, errorconst 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
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
On Sat, 27 Mar 2010 13:52:28 +0200, bearophile <bearophileHUGS lycos.com> wrote:so: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/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
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, bearophileOne 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
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
On Sat, 27 Mar 2010 15:28:22 +0200, bearophile <bearophileHUGS lycos.com> wrote:so: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/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
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'=wedYes, it says : "Floating literals with no suffix are of type double. Floats can be follo=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 bearophileby one f, F, or L suffix. The f or F suffix means it is a float, and L me=ansit 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
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. --bbThat "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
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
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:-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/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
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
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
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
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
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
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
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:-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/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
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
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=ourdon't understand. To make things clearer, lets forget floats for a seconds and change y=c. =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
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:-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/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
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
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:-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/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
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:-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/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
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
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