2015-08-03 5 views
7
const double pi = 3.1415926535897; 

static double mysin(double x) { 
    return ((((((-0.000140298 * x - 0.00021075890) * x + 0.008703147) * x - 
     0.0003853080) * x - 0.16641544) * x - 0.00010117316) * x + 
     1.000023121) * x; 
} 

static void Main(string[] args) { 
    Stopwatch sw = new Stopwatch(); 

    double a = 0; 
    double[] arg = new double[1000000]; 
    for (int i = 0; i < 1000000; i++) { 
     arg[i] = (pi/2000000); 
    } 
    sw.Restart(); 
    for (int i = 0; i < 1000000; i++) { 
     a = a + Math.Sin(arg[i]); 
    } 
    sw.Stop(); 
    double t1 = (double)(sw.Elapsed.TotalMilliseconds); 

    a = 0; 
    sw.Restart(); 
    for (int i = 0; i < 1000000; i++) { 
     a = a + mysin(arg[i]); 
    } 
    sw.Stop(); 
    double t2 = (double)(sw.Elapsed.TotalMilliseconds); 
    Console.WriteLine("{0}\n{1}\n", t1,t2); 
    Console.Read(); 
} 

Questa serie di potenze è valida per [0, pi/2] ed è 10 volte più lenta della funzione sinusoidale incorporata in modalità di rilascio. 1 ms vs 10 ms.Perché il mio algoritmo seno è molto più lento del valore predefinito?

Tuttavia, quando copio il codice di scrittura mysin nella funzione, ottengo praticamente la stessa ora di rilascio e il mio codice è circa 4 volte più veloce in modalità di debug.

a = 0; 
sw.Restart(); 
for (int i = 0; i < 1000000; i++) { 
    double x = arg[i]; 
    a = a + ((((((-0.000140298 * x - 0.00021075890) * x + 0.008703147) * x - 
     0.0003853080) * x - 0.16641544) * x - 0.00010117316) * x + 
     1.000023121) * x; 
    //a = a + mysin(arg[i]); 
} 

Qual è l'affare qui? Come faccio a rendere questo tipo di calcoli più veloce? Sto indovinando che il codice riconosce automaticamente che l'algoritmo sin non dovrebbe essere chiamato ma copia incolla nel ciclo. Come faccio a fare in modo che il compilatore faccia lo stesso per me.

Un'altra domanda, C++ farebbe la stessa ottimizzazione per la sua funzione sin/cos predefinita? Altrimenti, come farei per assicurarmi che lo faccia. Modifica: l'ho testato e la mia funzione seno (con 4 extra se le condizioni aggiunte per espandere il dominio su tutto il reale) viene eseguita circa il 25% più veloce (anche se imprecisa) rispetto alla funzione sin predefinita. E infatti, la versione incollata della copia è più lenta di quando la scrivo come una funzione separata.

+1

Hai eseguito la build "Release" del tuo programma? In caso contrario, probabilmente la tua funzione non è in linea. – SuperOli

+0

Intendi dire che quando si copia-incolla il codice nella funzione principale si ottiene lo stesso tempo con 'mysin' come' Math.Sin'? –

+0

Sì, ottengo la stessa durata in modalità di rilascio. In modalità di debug, copia serie di potenze incollate è in realtà 4 volte più veloce. – grdgfgr

risposta

3

Suppongo che l'hai testato su x86, perché non posso riprodurre i numeri su x64. Su x64, il tuo codice sembra essere più veloce.

Ho disassemblato il codice per x86/release. Il motivo della differenza è che il tuo metodo è proprio questo, un metodo mentre Math.Sin viene compilato per utilizzare direttamente l'istruzione x86 fsin, eliminando così una chiamata di funzione per invocazione.

FWIW, il codice x64 è molto diverso. Math.Sin è tradotto in clr!COMDouble::Sin.

Vedere FSIN.

+0

Il mio computer è un computer a 64 bit e non ricordo di aver configurato Visual Studio esplicitamente per 32 o 64 bit. – grdgfgr

+0

Per impostazione predefinita, VS produce codice x86 per AnyCPU - controlla le impostazioni del progetto - "Prefer 32 bit" deve essere controllato. –

+1

Al momento del voto si prega di lasciare un commento. Grazie. –

Problemi correlati