sqrt c # vs sqrt c ++

6

Qualche idea sul perché la versione C # di sqrt ( System.Math.Sqrt ) sia ~ 10 volte più lenta della versione c ++? Inoltre, la versione C # sembra avere una cifra in più di precisione. Ho eseguito il test in MSVC2012.

Ho usato il double e ho chiamato System.Math.Sqrt una volta prima di fare il bench per forzare Jit

    
posta Guillaume07 24.12.2012 - 19:38
fonte

1 risposta

21

Sto parlando solo dal lato C (e quindi applicabile a C ++). Non ho un sistema in grado di eseguire C # da cui lavorare.

Il primo programma che ho scritto è stato banale:

#include <math.h>
#include <stdio.h>

int main(void) {
    printf("%f\n",sqrt(2.0));
}

Uso di gcc -S -O3 sqrt.c Ho ottenuto il sorgente compilato in sqrt.s e l'ho esaminato.

    .file   "sqrt.c"
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC1:
    .string "%f\n"
    .text
    .p2align 4,,15
.globl main
    .type   main, @function
main:
.LFB14:
    .cfi_startproc
    movsd   .LC0(%rip), %xmm0
    movl    $.LC1, %edi
    movl    $1, %eax
    jmp printf
    .cfi_endproc
.LFE14:
    .size   main, .-main
    .section    .rodata.cst8,"aM",@progbits,8
    .align 8
.LC0:
    .long   1719614413
    .long   1073127582
    .ident  "GCC: (SUSE Linux) 4.5.1 20101208 [gcc-4_5-branch revision 167585]"
    .section    .comment.SUSE.OPTs,"MS",@progbits,1
    .string "Ospwg" 
    .section    .note.GNU-stack,"",@progbits

Si noterà che non vi è alcuna chiamata a sqrt nel codice - sembra che stia semplicemente caricando una costante (che è).

Questo è diventato più evidente durante la scrittura di uno che utilizzava una variabile e faceva la compilazione per dimostrare come sarebbe una chiamata a sqrt .

Non ho alcun tipo di eleganza con questo codice.

#include <math.h>
#include <stdio.h>

void main(int argc, char **argv) {
    double num = atoi(argv[0]);
    printf("%f\n",sqrt(num));
}

Mentre gcc -O3 -S sqrt.c ha funzionato, questo secondo programma come gcc -O3 -S sqrt2.c ha restituito

/tmp/cckmgfMS.o: In function 'main':
sqrt2.c:(.text+0x46): undefined reference to 'sqrt'
collect2: ld returned 1 exit status

chiamava sqrt e ho dimenticato di collegare la libreria matematica.

Quando aggiungi il link al codice, puoi vedere la chiamata a sqrt al suo interno:

        .file   "sqrt2.c"
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "%f\n"
        .text
        .p2align 4,,15
.globl main
        .type   main, @function
main:
.LFB14:
        .cfi_startproc
        subq    $8, %rsp
        .cfi_def_cfa_offset 16
        movq    (%rsi), %rdi
        xorl    %eax, %eax
        call    atoi
        cvtsi2sd        %eax, %xmm1
        sqrtsd  %xmm1, %xmm0
        ucomisd %xmm0, %xmm0
        jp      .L5
.L2:
        movl    $.LC0, %edi
        movl    $1, %eax
        addq    $8, %rsp
        .cfi_remember_state
        .cfi_def_cfa_offset 8
        jmp     printf
.L5:
        .cfi_restore_state
        movapd  %xmm1, %xmm0
        call    sqrt
        jmp     .L2
        .cfi_endproc
.LFE14:
        .size   main, .-main
        .ident  "GCC: (SUSE Linux) 4.5.1 20101208 [gcc-4_5-branch revision 167585]"
        .section        .comment.SUSE.OPTs,"MS",@progbits,1
        .string "Ospwg"
        .section        .note.GNU-stack,"",@progbits

Si può vedere in questo codice la chiamata a sqrt e la mancanza delle costanti introdotte dall'ottimizzatore.

Dal commento precedente:

I have of course store the 10^6 sqrt(2.0) calls by doing a sum in a variable ( i.e: var += sqrt(2.0) ) and print it on screen at the end to be sure that compilator will not skip some codes. – Guillaume07 Dec 24 '12 at 19:19

Quindi, considera - se hai a che fare con costanti, questo è qualcosa che gli ottimizzatori C e C ++ identificheranno e ottimizzeranno.

Non avendo accesso a C #, ho visto come Java si occupa della linea:

System.out.println(Math.sqrt(2.0));

Questa istruzione è compilata nel codice byte Java di:

0  getstatic java.lang.System.out : java.io.PrintStream [16]
3  ldc2_w <Double 2.0> [22]
6  invokestatic java.lang.Math.sqrt(double) : double [24]
9  invokevirtual java.io.PrintStream.println(double) : void [30]

Si può vedere che il compilatore Java non ha accesso alle informazioni dell'output di sqrt() per essere in grado di ottimizzare in una costante. È possibile che l'ottimizzatore JIT abbia accesso alle informazioni sulla purezza delle chiamate attraverso Math a StrictMath e sostituisca più chiamate di Math.sqrt(2.0) allo stesso valore (e non lo richiami di nuovo), tuttavia ha ancora chiamarlo una volta a quel punto per ottenere il valore. Detto questo, non ho idea di ciò che accade a runtime nel JIT e di come le chiamate a funzioni pure che finiscono in nativo potrebbero essere ottimizzate.

Tuttavia, l'ottimizzatore C è ancora in testa al gioco con un grosso ciclo (supponendo che l'ottimizzatore JIT debba solo effettuare una chiamata a sqrt () per ottenere quel primo valore).

Osservando l'ottimizzazione del ciclo in C, l'ottimizzatore calcola anche il ciclo.

#include <math.h>
#include <stdio.h>

int main(void) {
    double sum = 0;
    int i = 0;
    for(i; i < 10; i++) {
        sum += sqrt(2.0);
    }
    printf("%f\n",sum);
}

attraverso gcc -O3 -S sqrt3.c (ancora non necessario -lm) diventa:

    .file   "sqrt3.c"
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC1:
    .string "%f\n"
    .text
    .p2align 4,,15
.globl main
    .type   main, @function
main:
.LFB14:
    .cfi_startproc
    movsd   .LC0(%rip), %xmm0
    movl    $.LC1, %edi
    movl    $1, %eax
    jmp printf
    .cfi_endproc
.LFE14:
    .size   main, .-main
    .section    .rodata.cst8,"aM",@progbits,8
    .align 8
.LC0:
    .long   2034370
    .long   1076644038
    .ident  "GCC: (SUSE Linux) 4.5.1 20101208 [gcc-4_5-branch revision 167585]"
    .section    .comment.SUSE.OPTs,"MS",@progbits,1
    .string "Ospwg"
    .section    .note.GNU-stack,"",@progbits

E si può vedere che questo codice è identico al primo, con costanti diverse nella sezione .LC0 . Il ciclo è stato calcolato solo per "il valore finale è questo, non preoccuparti di farlo in fase di esecuzione".

    
risposta data 31.01.2013 - 18:02
fonte

Leggi altre domande sui tag