in D

2012-04-12 18 views
5

L'obiettivo è ottenere lo stesso effetto di this C++ example: evitare di creare provvisori. Ho provato a tradurre l'esempio C++ in D senza successo. Ho anche provato approcci diversi.in D

import std.datetime : benchmark; 
import std.stdio : writefln, writeln; 

void bench(alias fun, string time = "msecs")(string msg, uint n = 1_000_000) { 
    auto b = benchmark!fun(n); 
    writefln(" %s: %s ms", msg, b[0].to!(time, int)); 
} 

alias double Real; 

struct Expression(string op, E1, E2) { 
    E1 _v1; 
    E2 _v2; 
    alias _v1 v1; 
    alias _v2 v2; 

    auto opIndex(size_t i) { 
    return mixin("v1[i]" ~ op ~ "v2[i]"); 
    } 

    auto opBinary(string op, E)(auto ref E e) { 
    return Expression!(op, typeof(this), E)(this, e); 
    } 
} 

struct ExpVector { 

    Real[40] _data = void; 
    alias _data this; 

    this(Real datum) pure nothrow { _data = datum; } 

    auto opBinary(string op, T)(auto ref T other) { 
    return Expression!(op, typeof(this), T)(this, other); 
    } 

    void opAssign(E)(auto ref E exp) { 
    foreach(i, ref datum; _data) 
     datum = exp[i]; 
    } 
} 

struct Vector { 

    Real[40] _data = void; 
    alias _data this; 

    this(Real datum) pure nothrow { _data = datum; } 

    auto opBinary(string op)(auto ref Vector other) { 
    Vector ret; 
    foreach(i, datum; _data) 
     ret[i] = mixin("datum" ~ op ~ "other[i]"); 
    return ret; 
    } 
} 

void main() { 

    ExpVector e1 = ExpVector(1.5); 
    ExpVector e2 = ExpVector(7.3); 
    ExpVector ef; 
    void T1() { 
    ef = (e1 + e2) * (e1 + e2); 
    } 
    bench!T1(" vector operations using template expression"); 

    Vector v1 = Vector(1.5); 
    Vector v2 = Vector(7.3); 
    Vector vf; 
    void T2() { 
    vf = (v1 + v2) * (v1 + v2); 
    } 
    bench!T2(" regular vector operations"); 

    void T3() { 
    for(int i = 0; i < vf.length; ++i) 
     vf[i] = (v1[i] + v2[i]) * (v1[i] + v2[i]); 
    } 
    bench!T3(" what is expected if template expressions worked and temporaries were not created."); 
} 

La versione del modello di espressione è più lenta della versione del modello di non-espressione. Mi aspettavo che la versione del modello di espressione fosse molto più veloce e vicina a quanto previsto. Allora, cosa c'è di sbagliato con i miei modelli di espressione? Qual è il modo corretto di fare modello di espressione in D?

+1

Beh, senza nemmeno considerare che cosa fa il codice, vorrei sottolineare che si avrebbe bisogno di compilare il codice su un compilatore che condivide un back-end con il compilatore C++ per poter realmente confrontare il linguaggio piuttosto che l'implementazione del compilatore. Se usi gdc per la roba D e gcc per la roba C++, otterrai un confronto molto migliore della lingua stessa. Il codice D potrebbe essere più lento semplicemente perché il backend di dmd non si ottimizza così come fa gcc. Potrebbe esserci molto di più, ma confrontare dmd vs gcc potrebbe facilmente essere comparativo con gli ottimizzatori dei due compilatori. –

+0

Penso che tu abbia frainteso quello che ho detto. Il codice che ho postato è più del doppio della versione senza template di espressioni, cioè una normale struct 'Vector' che implementa la funzione membro' opBinary', con entrambe le versioni compilate con DMD. Non sto confrontandolo con il codice C++ in Wikipedia. – Arlen

+0

Quindi dovresti postare entrambe le versioni. È difficile confrontare qualcosa con qualcos'altro quando hai solo uno dei due. –

risposta

2

in C esempio classi di espressione di Wikipedia ++ detiene riferimenti a provvisori, e in caso di espressione ...

 
Vec a, b; 
double c; 
Vec result = (a - b) * c 
... a destra prima assegnazione ai risultati vettore abbiamo una sorta di albero in memoria:
a   b 
\  /
    \ /
    \ /
VecDifference 
     \ 
     \ 
     \ 
     VecScaled(has copy of 'c' embedded directly in object) 
VecDifference hold just references to a and b, and VecScaled holds reference to temporary VecDifference (which, according to the c++ rules, will be alive until expression end). At the end we have no duplication of initial data and no unnecessary computations(if we will use just some components of vector, but not all of them as in simple assignment to Vec)
In your struct Expression(string op, E1, E2) initial and intermediate data simply copied to data members and at the end of previous expression you will have
 
Expression!("*", Expression!("-", Vec, Vec), double) 
cui espressione esteriore avrà copia di Espressione interna ("-", Vec, Vec) e doppi parametri e Espressione interna avrà copie di vettori aeb. Così alla fine di un giorno hai evitato Vec temporaneo ma hai fatto 4 copie di aeb (senza contare l'assegnazione finale al vettore risultato). Tuttavia, non so come si possa evitare di copiare in questa situazione in D. Forse i riferimenti a structres?
(BTW, C++ 11 di tipo automatico di inferenza e di espressione modelli con riferimenti ad provvisori ha sfortunata interazione, che può portare a bug: http://lanzkron.wordpress.com/2011/02/21/inferring-too-much/)

+0

Ero al corrente della copia, ma D non me lo permette di avere come riferimento. Ho provato il puntatore (avevo l'impressione che avrebbe reso il mio codice non sicuro) e fa una grande differenza, ma ancora non abbastanza. ad esempio, la versione del modello di espressione richiede '250ms' mentre è previsto' 150ms'. – Arlen

+0

Sì, i puntatori rendono le cose non sicure. La pagina collegata alla fine della mia risposta mostra uno di questi pericoli (si tratta di C++, ma penso che possiamo ottenere gli stessi risultati usando i modelli di espressione in D con i puntatori) – cybevnm