www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - Wrote a blog post about CTFE and D

reply "Danny Arends" <Danny.Arends gmail.com> writes:
I wrote a blog post about the stuff I've been doing last weekend 
using CTFE.
All comments are welcome, you can find the blog post at:

http://www.dannyarends.nl/index.cgi?viewDetailed=00029

Danny Arends
http://www.dannyarends.nl
Aug 30 2012
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Danny Arends:

 http://www.dannyarends.nl/index.cgi?viewDetailed=00029

struct Coord(T : float){ T[] d = [1.0, 0.0]; Maybe better ==> struct Coord(T) if (isFloatingPoint!T) { T[2] d = [1.0, 0.0]; (isFloatingPoint is in std.traits) Bye, bearophile
Aug 30 2012
prev sibling next sibling parent "Danny Arends" <Danny.Arends gmail.com> writes:
Thanks for the feedback, I'll update it..

I was thinking to remove the struct all together, but when doing 
the rotation matrices its actually more clean / useful to have 
structures.

Danny Arends
http://www.dannyarends.nl

On Thursday, 30 August 2012 at 11:25:55 UTC, bearophile wrote:
 Danny Arends:

 http://www.dannyarends.nl/index.cgi?viewDetailed=00029

struct Coord(T : float){ T[] d = [1.0, 0.0]; Maybe better ==> struct Coord(T) if (isFloatingPoint!T) { T[2] d = [1.0, 0.0]; (isFloatingPoint is in std.traits) Bye, bearophile

Aug 30 2012
prev sibling next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 30-Aug-12 13:41, Danny Arends wrote:
 I wrote a blog post about the stuff I've been doing last weekend using
 CTFE.
 All comments are welcome, you can find the blog post at:

 http://www.dannyarends.nl/index.cgi?viewDetailed=00029

 Danny Arends
 http://www.dannyarends.nl

Nice read. A couple of nits: Use T[2] for fixed arrays like Cord one. It also helps tremendously for lookup speed of the final lookup table. Thus instead of array of arrays you'd have an array of pairs i.e. 2 indirections ---> 1 indirection and cache friendly layout. And an awful typo in degreeloop function I think: pure int degreeloop(int deg){ while(deg < 0 || deg >= 360){ if(deg < 0) deg += 360; if(deg >= 0) deg -= 360; //shouldn't it be >= 360 ?? } return deg; } -- Olshansky Dmitry
Aug 30 2012
prev sibling next sibling parent "Danny Arends" <Danny.Arends gmail.com> writes:
On Thursday, 30 August 2012 at 16:27:05 UTC, Dmitry Olshansky 
wrote:
 On 30-Aug-12 13:41, Danny Arends wrote:
 I wrote a blog post about the stuff I've been doing last 
 weekend using
 CTFE.
 All comments are welcome, you can find the blog post at:

 http://www.dannyarends.nl/index.cgi?viewDetailed=00029

 Danny Arends
 http://www.dannyarends.nl

Nice read. A couple of nits: Use T[2] for fixed arrays like Cord one. It also helps tremendously for lookup speed of the final lookup table. Thus instead of array of arrays you'd have an array of pairs i.e. 2 indirections ---> 1 indirection and cache friendly layout.

You're right about that, I made it initially to be variable length. because I was also planning on storing the other ones (tan, cosh, sinh) but didn't get around to that yet.
 And an awful typo in degreeloop function I think:
 pure int degreeloop(int deg){
   while(deg < 0 || deg >= 360){
     if(deg < 0) deg += 360;
     if(deg >= 0) deg -= 360; //shouldn't it be >= 360 ??
   }
   return deg;
 }

Thanks for the spot ;) it actually doesn't matter seeing as the while condition already forced it to be out of array bounds. I could just as well use an else Thanks for the feedback ! And I'll create a blog post about the rotation matrices also when I finish off that code Danny Arends http://www.dannyarends.nl
Aug 30 2012
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Thu, Aug 30, 2012 at 7:10 PM, Danny Arends <Danny.Arends gmail.com> wrote:

 I wrote a blog post about the stuff I've been doing last weekend using
 CTFE.
 All comments are welcome, you can find the blog post at:

 http://www.dannyarends.nl/index.cgi?viewDetailed=00029



Nice article, Danny! A few remarks: degToRad!(float,int) 45 First, it seems like you missed a parenthesis pair? The compiler will be able to determine V in degToRad, you can call it like this: degToRad!(float)(45) Following bearophile's use of isFloatingPoint, you can use a default value, if that's what you need most of the time: import std.traits; pure U degToRad(U = float, V)(in V deg) if (isFloatingPoint!U && isIntegral!V) { return (deg * PI) / 180.0; } Then, to call it: degToRad(45) => automatically expand to detToRad!(float,int)(45) And the same type deduction for cordic gives you cordic( degToRad(45) ); instead of cordic!(float)(degToRad!(float,int) 45); In gen_trigonometric, I think the float call should be a T: result ~= cordic!T(degToRad!(float,int)(i), iter); => result ~= cordic( degToRad!(T)(i), iter); And, since you know the result's size in advance, you might want to generate it at once: T[2][] result = new (T[2][])(iter); foreach(i; 0 .. 360) result[i] = cordic(degToRad!(T)(i), iter); return result; (no need for braces for a one-expression foreach) Or even, using map: import std.algorithm, std.array; return map!( i => cordic(degToRag!(T)(i), iter) )(result).array;
Aug 30 2012
prev sibling next sibling parent "Danny Arends" <Danny.Arends gmail.com> writes:
On Thursday, 30 August 2012 at 17:40:16 UTC, Philippe Sigaud 
wrote:
 On Thu, Aug 30, 2012 at 7:10 PM, Danny Arends 
 <Danny.Arends gmail.com> wrote:

 I wrote a blog post about the stuff I've been doing last 
 weekend using
 CTFE.
 All comments are welcome, you can find the blog post at:

 http://www.dannyarends.nl/index.cgi?viewDetailed=00029



Nice article, Danny! A few remarks: degToRad!(float,int) 45 First, it seems like you missed a parenthesis pair?

Indeed, fixed
 The compiler will be able to determine V in degToRad, you can 
 call it like this:

 degToRad!(float)(45)

 Following bearophile's use of isFloatingPoint, you can use a 
 default
 value, if that's what you need most of the time:

 import std.traits;
 pure U degToRad(U = float, V)(in V deg) if (isFloatingPoint!U 
 && isIntegral!V)
 { return (deg * PI) / 180.0; }

Interesting, I knew about defaults but I tend to forget about them, when I can use them...
 Then, to call it:

 degToRad(45) => automatically expand to detToRad!(float,int)(45)

 And the same type deduction for cordic gives you

 cordic( degToRad(45) );

 instead of

 cordic!(float)(degToRad!(float,int) 45);

 In gen_trigonometric, I think the float call should be a T:

 result ~= cordic!T(degToRad!(float,int)(i), iter);

Indeed, fixed !
 =>

 result ~= cordic( degToRad!(T)(i), iter);

 And, since you know the result's size in advance, you might 
 want to
 generate it at once:

 T[2][] result = new (T[2][])(iter);
 foreach(i; 0 .. 360)
     result[i] = cordic(degToRad!(T)(i), iter);
 return result;

 (no need for braces for a one-expression foreach)

Again valid point. Though the compile time benefits will be minor with all the memory CTFE is gobbling up anyway.
 Or even, using map:

 import std.algorithm, std.array;

 return map!( i => cordic(degToRag!(T)(i), iter) )(result).array;

I like the map syntax, that's prob. because I've got an R background where we have lapply (1D) and apply (2D) Still I don't seem to get used to the => syntax... Thanks for the feedback, Gr, Danny If I get round to it I'll also update the code to use default return types. Though I like being explicit with types, if you got them flaunt them...
Aug 30 2012
prev sibling next sibling parent "Danny Arends" <Danny.Arends gmail.com> writes:
Another post: http://www.dannyarends.nl/?viewDetailed=00030

Again all comments are welcome
Danny Arends
Aug 31 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Danny Arends:

 Another post: http://www.dannyarends.nl/?viewDetailed=00030

pure mat!(T)[3][] gen_rotationmatrices(T = float)(){ I suggest to write something like this (note the casing and other details): Mat!T[3][] genRotationMatrices(T = float)() pure { tmp += mixin('A[i][k] '~op~' B[k][j]'); This seems OK, but it looks a bit convoluted. Maybe something like this works (untested): tmp += A[i][k].opBinary!op(B[k][j]); pure auto yaw(int deg){ deg = degreeloop(deg); return cast(matrix)rmatrix[deg][YAW]; } I suggest generally to try to avoid casts, where possible. Bye, bearophile
Aug 31 2012
prev sibling next sibling parent "Rene Zwanenburg" <renezwanenburg gmail.com> writes:
On Thursday, 30 August 2012 at 09:41:43 UTC, Danny Arends wrote:
 I wrote a blog post about the stuff I've been doing last 
 weekend using CTFE.
 All comments are welcome, you can find the blog post at:

 http://www.dannyarends.nl/index.cgi?viewDetailed=00029

 Danny Arends
 http://www.dannyarends.nl

It's always good to see someone write about the unusual features of D, but I have a non-D related point of criticism regarding your post: lookup tables for trig functions are a thing from the nineties. I'm not trying to make some bad 'the nineties called' joke ;). Since at least a decade, calling the trig functions will usually be significantly faster in a real application than a lookup table. Simple benchmarks may show a performance improvement, but that's because the table still resides in the L1 cache. A real application will often have to read the table from main memory, which is orders of magnitude slower than simply doing the computation. Use caching for data which is really expensive to calculate. For relatively trivial stuff like sin(), just calculate it during runtime.
Aug 31 2012
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sat, Sep 1, 2012 at 3:46 AM, Rene Zwanenburg
<renezwanenburg gmail.com> wrote:

 Use caching for data which is really expensive to calculate. For relatively
 trivial stuff like sin(), just calculate it during runtime.

On a somewhat related note, I remember realizing a few years ago that it was faster to generate the first thousands of primes on the fly than to pre-generate them and read them from a file.
Sep 01 2012
prev sibling next sibling parent "Danny Arends" <Danny.Arends gmail.com> writes:
On Saturday, 1 September 2012 at 01:46:38 UTC, Rene Zwanenburg 
wrote:
 On Thursday, 30 August 2012 at 09:41:43 UTC, Danny Arends wrote:
 I wrote a blog post about the stuff I've been doing last 
 weekend using CTFE.
 All comments are welcome, you can find the blog post at:

 http://www.dannyarends.nl/index.cgi?viewDetailed=00029

 Danny Arends
 http://www.dannyarends.nl

It's always good to see someone write about the unusual features of D, but I have a non-D related point of criticism regarding your post: lookup tables for trig functions are a thing from the nineties.

Thanks for reply! I see you got the point from the post :) The stuff I implemented in CTFE is course many times worse then the std.math sine and cosine functions (they fall back to single operators in ASM)I could have just as well done: pure T[2][] gen_trigonometric(){ T[2][] result = new T[2][](360); foreach(i; 0 .. 360){ result[i] = [sin(x), cos(x)]; } return result; } But well then showing off D's feature to call (polymorphic) user functions in CTFE is then less clear :)
 I'm not trying to make some bad 'the nineties called' joke ;). 
 Since at least a decade, calling the trig functions will 
 usually be significantly faster in a real application than a 
 lookup table. Simple benchmarks may show a performance 
 improvement, but that's because the table still resides in the 
 L1 cache. A real application will often have to read the table 
 from main memory, which is orders of magnitude slower than 
 simply doing the computation.

 Use caching for data which is really expensive to calculate. 
 For relatively trivial stuff like sin(), just calculate it 
 during runtime.

I don't try to advocating people start using look-up tables for sine and cosine. It's an example to show how cool I think CTFE is for stuff like this. I could have also taken the much more used example of CTFE calculating primes. However in that case (primes) it is not useful to have a user function doing it for floats, doubles and reals. :-P Gr, Danny Arends
Sep 01 2012
prev sibling next sibling parent "Danny Arends" <Danny.Arends gmail.com> writes:
On Saturday, 1 September 2012 at 00:47:20 UTC, bearophile wrote:
 Danny Arends:

 Another post: http://www.dannyarends.nl/?viewDetailed=00030

pure mat!(T)[3][] gen_rotationmatrices(T = float)(){ I suggest to write something like this (note the casing and other details): Mat!T[3][] genRotationMatrices(T = float)() pure {

Again many thanks for the feedback. I'll fix this indeed :)
 tmp += mixin('A[i][k] '~op~' B[k][j]');

 This seems OK, but it looks a bit convoluted. Maybe something 
 like this works (untested):

 tmp += A[i][k].opBinary!op(B[k][j]);

I'll test it, though I wanted to show off the mixin concept, I put a hyper link to the Dlang information page about mixins. So that people can read up on what they are.
 pure auto yaw(int deg){
    deg = degreeloop(deg);
    return cast(matrix)rmatrix[deg][YAW];
 }

 I suggest generally to try to avoid casts, where possible.

Do you have a suggestion to get around this cast ?
 Bye,
 bearophile

Gr, Danny Arends
Sep 01 2012
prev sibling next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/30/2012 02:41 AM, Danny Arends wrote:
 I wrote a blog post about the stuff I've been doing last weekend using
 CTFE.
 All comments are welcome, you can find the blog post at:

 http://www.dannyarends.nl/index.cgi?viewDetailed=00029

 Danny Arends
 http://www.dannyarends.nl

Thanks for the blog posts. I wanted to mention that the community has been moving away from the D 1 and D 2 namings. D1 is being discontinued by the end of the year and D2 wants to be called simply D, like in the subject of this thread. ;) Ali
Sep 03 2012
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/30/12 11:41 AM, Danny Arends wrote:
 I wrote a blog post about the stuff I've been doing last weekend using
 CTFE.
 All comments are welcome, you can find the blog post at:

 http://www.dannyarends.nl/index.cgi?viewDetailed=00029

On reddit: http://www.reddit.com/r/programming/comments/zcd19/using_ds_compiletime_evaluation_to_speed_up_sine/ Andrei
Sep 04 2012
prev sibling parent "Danny Arends" <Danny.Arends gmail.com> writes:
Thanks for redditting, also put the second blog post on there

http://redd.it/zcj4p

I'll update both blogs (due to previous comments )as soon as I 
get round 2 it.

On Tuesday, 4 September 2012 at 16:55:14 UTC, Andrei Alexandrescu 
wrote:
 On 8/30/12 11:41 AM, Danny Arends wrote:
 I wrote a blog post about the stuff I've been doing last 
 weekend using
 CTFE.
 All comments are welcome, you can find the blog post at:

 http://www.dannyarends.nl/index.cgi?viewDetailed=00029

On reddit: http://www.reddit.com/r/programming/comments/zcd19/using_ds_compiletime_evaluation_to_speed_up_sine/ Andrei

Sep 04 2012