C # vs C - Perbedaan performa yang besar

94

Saya menemukan perbedaan kinerja yang sangat besar antara kode serupa di C anc C #.

Kode C adalah:

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

main()
{
    int i;
    double root;

    clock_t start = clock();
    for (i = 0 ; i <= 100000000; i++){
        root = sqrt(i);
    }
    printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);   

}

Dan C # (aplikasi konsol) adalah:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime startTime = DateTime.Now;
            double root;
            for (int i = 0; i <= 100000000; i++)
            {
                root = Math.Sqrt(i);
            }
            TimeSpan runTime = DateTime.Now - startTime;
            Console.WriteLine("Time elapsed: " + Convert.ToString(runTime.TotalMilliseconds/1000));
        }
    }
}

Dengan kode di atas, C # selesai dalam 0,328125 detik (versi rilis) dan C membutuhkan waktu 11,14 detik untuk berjalan.

C sedang dikompilasi ke windows yang dapat dieksekusi menggunakan mingw.

Saya selalu beranggapan bahwa C / C ++ lebih cepat atau setidaknya sebanding dengan C # .net. Apa sebenarnya yang menyebabkan C bekerja lebih dari 30 kali lebih lambat?

EDIT: Tampaknya pengoptimal C # menghapus root karena tidak digunakan. Saya mengubah tugas root menjadi root + = dan mencetak totalnya di akhir. Saya juga telah mengkompilasi C menggunakan cl.exe dengan flag / O2 yang disetel untuk kecepatan maksimal.

Hasilnya sekarang: 3,75 detik untuk C 2,61 detik untuk C #

C masih membutuhkan waktu lebih lama, tetapi ini bisa diterima

John
sumber
18
Saya menyarankan Anda menggunakan StopWatch, bukan hanya DateTime.
Alex Fort
2
Bendera kompilator yang mana? Apakah keduanya dikompilasi dengan pengoptimalan diaktifkan?
jalf
2
Bagaimana jika Anda menggunakan -ffast-math dengan compiler C ++?
Dan McClain
10
Sungguh pertanyaan yang menarik!
Robert S.
4
Mungkin fungsi C sqrt tidak sebaik ini di C #. Maka itu tidak akan menjadi masalah dengan C, tapi dengan perpustakaan yang menyertainya. Cobalah beberapa kalkulasi tanpa fungsi matematika.
klew

Jawaban:

61

Karena Anda tidak pernah menggunakan 'root', kompilator mungkin telah menghapus panggilan untuk mengoptimalkan metode Anda.

Anda dapat mencoba mengakumulasi nilai akar kuadrat menjadi akumulator, mencetaknya di akhir metode, dan melihat apa yang terjadi.

Edit: simak jawaban Jalf di bawah ini

Brann
sumber
1
Eksperimen kecil menunjukkan bahwa ini bukanlah masalahnya. Kode untuk loop dibuat, meskipun mungkin runtime cukup pintar untuk melewatinya. Bahkan terakumulasi, C # masih mengalahkan celananya C.
Dana
3
Sepertinya masalahnya ada di sisi lain. C # berperilaku wajar dalam semua kasus. Kode C-nya tampaknya dikompilasi tanpa pengoptimalan
jalf
2
Banyak dari Anda yang melewatkan intinya di sini. Saya telah membaca banyak kasus serupa di mana c # mengungguli c / c ++ dan selalu bantahannya adalah menggunakan beberapa pengoptimalan tingkat ahli. 99% programmer tidak memiliki pengetahuan untuk menggunakan teknik pengoptimalan seperti itu hanya untuk membuat kode mereka berjalan sedikit lebih cepat daripada kode c #. Kasus penggunaan untuk c / c ++ semakin menyempit.
167

Anda harus membandingkan build debug. Saya baru saja menyusun kode C Anda, dan mendapatkannya

Time elapsed: 0.000000

Jika Anda tidak mengaktifkan pengoptimalan, tolok ukur apa pun yang Anda lakukan sama sekali tidak berguna. (Dan jika Anda mengaktifkan pengoptimalan, loop akan dioptimalkan. Jadi kode pembandingan Anda juga cacat. Anda perlu memaksanya untuk menjalankan loop, biasanya dengan menjumlahkan hasil atau yang serupa, dan mencetaknya di akhir)

Tampaknya apa yang Anda ukur pada dasarnya adalah "kompiler mana yang menyisipkan overhead debugging paling banyak". Dan ternyata jawabannya adalah C. Tapi itu tidak memberi tahu kita program mana yang paling cepat. Karena bila Anda menginginkan kecepatan, Anda mengaktifkan pengoptimalan.

Ngomong-ngomong, Anda akan terhindar dari banyak sakit kepala dalam jangka panjang jika Anda mengabaikan gagasan tentang bahasa yang "lebih cepat" daripada satu sama lain. C # tidak lebih memiliki kecepatan daripada bahasa Inggris.

Ada beberapa hal dalam bahasa C yang akan efisien bahkan dalam kompiler non-pengoptimalan yang naif, dan ada hal lain yang sangat bergantung pada kompiler untuk mengoptimalkan semuanya. Dan tentu saja, hal yang sama berlaku untuk C # atau bahasa lainnya.

Kecepatan eksekusi ditentukan oleh:

  • platform tempat Anda menjalankan (OS, perangkat keras, perangkat lunak lain yang berjalan di sistem)
  • kompiler
  • kode sumber Anda

Kompiler C # yang baik akan menghasilkan kode yang efisien. Kompiler C yang buruk akan menghasilkan kode yang lambat. Bagaimana dengan kompilator C yang menghasilkan kode C #, yang kemudian dapat dijalankan melalui kompilator C #? Seberapa cepat lari itu? Bahasa tidak memiliki kecepatan. Kode Anda melakukannya.

jalf
sumber
Banyak lagi bacaan menarik di sini: blogs.msdn.com/ricom/archive/2005/05/10/416151.aspx
Daniel Earwicker
18
Jawaban yang bagus, tetapi saya tidak setuju tentang kecepatan bahasa, setidaknya dalam analogi: Telah ditemukan bahwa Welsch adalah bahasa yang lebih lambat daripada kebanyakan bahasa karena frekuensi vokal panjang yang tinggi. Selain itu, orang-orang mengingat kata (dan daftar kata) lebih baik jika mereka lebih cepat diucapkan. web.missouri.edu/~cowann/docs/articles/before%201993/… en.wikipedia.org/wiki/Vowel_length en.wikipedia.org/wiki/Welsh_language
exceptionerror
1
Bukankah itu tergantung pada apa yang Anda katakan di Welsch? Saya merasa tidak mungkin semuanya lebih lambat.
jalf
5
++ Hai teman-teman, jangan tersimpangkan di sini. Jika program yang sama berjalan lebih cepat dalam satu bahasa daripada bahasa lainnya, itu karena kode assembly yang berbeda dihasilkan. Dalam contoh khusus ini, 99% atau lebih waktu akan mengambang i, dan sqrtitulah yang diukur.
Mike Dunlavey
116

Biar singkat saja, sudah ditandai jawab. C # memiliki keuntungan besar karena memiliki model floating point yang terdefinisi dengan baik. Itu kebetulan cocok dengan mode operasi asli dari set instruksi FPU dan SSE pada prosesor x86 dan x64. Tidak ada kebetulan di sana. JITter mengkompilasi Math.Sqrt () menjadi beberapa instruksi sebaris.

C / C ++ asli dibebani dengan kompatibilitas mundur bertahun-tahun. Opsi / fp: tepat, / fp: cepat dan / fp: kompilasi ketat adalah yang paling terlihat. Karenanya, ia harus memanggil fungsi CRT yang mengimplementasikan sqrt () dan memeriksa opsi floating point yang dipilih untuk menyesuaikan hasilnya. Itu lambat.

Hans Passant
sumber
66
Ini adalah keyakinan aneh di antara programmer C ++, mereka tampaknya berpikir bahwa kode mesin yang dihasilkan oleh C # berbeda dari kode mesin yang dihasilkan oleh kompiler asli. Hanya ada satu jenis. Apa pun sakelar kompilator gcc yang Anda gunakan atau rakitan inline yang Anda tulis, hanya ada satu instruksi FSQRT. Itu tidak selalu lebih cepat karena bahasa asli yang membuatnya, cpu tidak peduli.
Hans Passant
16
Itulah yang dipecahkan dengan ngen.exe. Kita berbicara tentang C #, bukan Java.
Hans Passant
20
@ user877329 - benarkah? Wow.
Andras Zoltan
7
Tidak, jitter x64 menggunakan SSE. Math.Sqrt () diterjemahkan ke instruksi kode mesin sqrtsd.
Hans Passant
6
Meskipun secara teknis bukan perbedaan antarbahasa, .net JITter melakukan pengoptimalan yang agak terbatas dibandingkan dengan compiler C / C ++ biasa. Salah satu batasan terbesar adalah kurangnya dukungan SIMD yang membuat kode seringkali sekitar 4x lebih lambat. Tidak mengekspos banyak intrinsik bisa menjadi malus besar juga, tapi itu sangat tergantung pada apa yang Anda lakukan.
CodesInChaos
57

Saya seorang pengembang C ++ dan C #. Saya telah mengembangkan aplikasi C # sejak beta pertama kerangka .NET dan saya memiliki lebih dari 20 tahun pengalaman dalam mengembangkan aplikasi C ++. Pertama, kode C # TIDAK AKAN PERNAH lebih cepat daripada aplikasi C ++, tetapi saya tidak akan membahas panjang lebar tentang kode yang dikelola, cara kerjanya, lapisan inter-op, internal manajemen memori, sistem tipe dinamis, dan pengumpul sampah. Namun demikian, izinkan saya melanjutkan dengan mengatakan bahwa tolok ukur yang tercantum di sini semuanya menghasilkan hasil yang TIDAK BENAR.

Izinkan saya menjelaskan: Hal pertama yang perlu kita pertimbangkan adalah compiler JIT untuk C # (.NET Framework 4). Sekarang JIT menghasilkan kode native untuk CPU menggunakan berbagai algoritme pengoptimalan (yang cenderung lebih agresif daripada pengoptimal C ++ default yang disertakan dengan Visual Studio) dan set instruksi yang digunakan oleh compiler .NET JIT adalah cerminan yang lebih dekat dari CPU yang sebenarnya. pada mesin sehingga substitusi tertentu dalam kode mesin dapat dilakukan untuk mengurangi siklus jam dan meningkatkan laju klik di cache pipeline CPU dan menghasilkan pengoptimalan hyper-threading lebih lanjut seperti pengurutan ulang instruksi dan peningkatan yang berkaitan dengan prediksi cabang.

Artinya, kecuali Anda mengompilasi aplikasi C ++ menggunakan parameter yang benar untuk build RELEASE (bukan build DEBUG), aplikasi C ++ Anda mungkin bekerja lebih lambat daripada aplikasi berbasis C # atau .NET yang sesuai. Saat menentukan properti proyek pada aplikasi C ++ Anda, pastikan Anda mengaktifkan "pengoptimalan penuh" dan "memilih kode cepat". Jika Anda memiliki mesin 64 bit, Anda HARUS menentukan untuk menghasilkan x64 sebagai platform target, jika tidak kode Anda akan dieksekusi melalui sub-lapisan konversi (WOW64) yang secara substansial akan mengurangi kinerja.

Setelah Anda melakukan pengoptimalan yang benar dalam kompiler, saya mendapatkan 0,72 detik untuk aplikasi C ++ dan 1,16 detik untuk aplikasi C # (keduanya dalam rilis build). Karena aplikasi C # sangat mendasar dan mengalokasikan memori yang digunakan dalam loop pada stack dan bukan pada heap, sebenarnya ia bekerja jauh lebih baik daripada aplikasi nyata yang terlibat dalam objek, komputasi berat, dan dengan kumpulan data yang lebih besar. Jadi angka yang diberikan adalah angka optimis yang bias terhadap C # dan kerangka .NET. Bahkan dengan bias ini, aplikasi C ++ selesai lebih dari separuh waktu dibandingkan aplikasi C # yang setara. Perlu diingat bahwa kompiler Microsoft C ++ yang saya gunakan tidak memiliki pengoptimalan pipeline dan hyperthreading yang benar (menggunakan WinDBG untuk melihat petunjuk perakitan).

Sekarang jika kita menggunakan kompiler Intel (yang merupakan rahasia industri untuk menghasilkan aplikasi berkinerja tinggi pada prosesor AMD / Intel), kode yang sama dijalankan dalam .54 detik untuk eksekusi C ++ vs .72 detik menggunakan Microsoft Visual Studio 2010 Jadi pada akhirnya, hasil akhirnya adalah 0,54 detik untuk C ++ dan 1,16 detik untuk C #. Jadi kode yang dihasilkan oleh compiler JIT .NET membutuhkan waktu 214% lebih lama daripada C ++ yang dapat dieksekusi. Sebagian besar waktu yang dihabiskan dalam .54 detik adalah untuk mendapatkan waktu dari sistem dan bukan dalam loop itu sendiri!

Hal yang juga hilang dalam statistik adalah waktu mulai dan pembersihan yang tidak termasuk dalam pengaturan waktu. Aplikasi C # cenderung menghabiskan lebih banyak waktu untuk start-up dan penghentian daripada aplikasi C ++. Alasan di balik ini rumit dan berkaitan dengan rutinitas validasi kode runtime .NET dan subsistem manajemen memori yang melakukan banyak pekerjaan di awal (dan akibatnya, akhir) program untuk mengoptimalkan alokasi memori dan sampah pengumpul.

Saat mengukur kinerja C ++ dan .NET IL, penting untuk melihat kode rakitan untuk memastikan bahwa SEMUA perhitungan ada. Apa yang saya temukan adalah bahwa tanpa meletakkan beberapa kode tambahan di C #, sebagian besar kode dalam contoh di atas sebenarnya telah dihapus dari biner. Ini juga terjadi pada C ++ ketika Anda menggunakan pengoptimal yang lebih agresif seperti yang disertakan dengan kompiler Intel C ++. Hasil yang saya berikan di atas 100% benar dan divalidasi di tingkat perakitan.

Masalah utama dengan banyaknya forum di internet yaitu banyak newbie yang mendengarkan propaganda marketing Microsoft tanpa memahami teknologinya dan membuat klaim palsu bahwa C # lebih cepat dari C ++. Klaimnya adalah bahwa secara teori, C # lebih cepat daripada C ++ karena kompiler JIT dapat mengoptimalkan kode untuk CPU. Masalah dengan teori ini adalah bahwa ada banyak pipa ledeng yang ada di kerangka .NET yang memperlambat kinerja; pipa ledeng yang tidak ada di aplikasi C ++. Selain itu, pengembang berpengalaman akan mengetahui kompiler yang tepat untuk digunakan pada platform tertentu dan menggunakan tanda yang sesuai saat menyusun aplikasi. Di Linux atau platform open source, ini tidak menjadi masalah karena Anda dapat mendistribusikan sumber Anda dan membuat skrip instalasi yang mengkompilasi kode menggunakan pengoptimalan yang sesuai. Di windows atau platform sumber tertutup, Anda harus mendistribusikan beberapa file yang dapat dieksekusi, masing-masing dengan pengoptimalan khusus. Biner windows yang akan disebarkan didasarkan pada CPU yang terdeteksi oleh penginstal msi (menggunakan tindakan kustom).

Richard
sumber
22
1. Microsoft tidak pernah membuat klaim tentang C # menjadi lebih cepat. Klaim mereka adalah sekitar 90% dari kecepatan, lebih cepat untuk dikembangkan (dan karenanya lebih banyak waktu untuk menyesuaikan) dan lebih banyak bebas bug karena memori dan keamanan tipe. Semuanya benar (saya punya 20 tahun di C ++ dan 10 di C #) 2. Performa startup tidak berarti dalam banyak kasus. 3. Ada juga kompiler C # yang lebih cepat seperti LLVM (jadi mengeluarkan Intel bukanlah Apel untuk Apel)
ben
13
Performa startup bukannya tidak berarti. Ini sangat penting di sebagian besar aplikasi berbasis web perusahaan, itulah sebabnya Microsoft memperkenalkan halaman web yang akan dimuat sebelumnya (mulai otomatis) di .NET 4.0. Saat pool aplikasi sesekali didaur ulang, pertama kali setiap pemuatan halaman akan menambah penundaan yang signifikan untuk halaman yang kompleks dan menyebabkan time-out pada browser.
Richard
8
Microsoft membuat klaim tentang kinerja .NET menjadi lebih cepat dalam materi pemasaran sebelumnya. Mereka juga membuat berbagai klaim tentang pengumpul sampah sedikit atau tidak berdampak pada kinerja. Beberapa dari klaim ini berhasil masuk ke berbagai buku (di ASP.NET dan .NET) di edisi sebelumnya. Meskipun Microsoft tidak secara spesifik mengatakan bahwa aplikasi C # Anda akan lebih cepat daripada aplikasi C ++ Anda, mereka mungkin menghapus komentar umum dan slogan pemasaran seperti "Just-In-Time Means Run-It-Fast" ( msdn.microsoft.com/ en-us / library / ms973894.aspx ).
Richard
71
-1, kata-kata kasar ini penuh dengan pernyataan yang salah dan menyesatkan seperti bohong yang jelas "kode C # TIDAK AKAN PERNAH lebih cepat dari aplikasi C ++"
BCoates
32
-1. Anda harus membaca pertarungan kinerja C # vs C Rico Mariani vs Raymond Chen: blogs.msdn.com/b/ricom/archive/2005/05/16/418051.aspx . Singkatnya: salah satu orang terpintar di Microsoft perlu banyak mengoptimalkan untuk membuat versi C lebih cepat daripada versi C # sederhana.
Rolf Bjarne Kvinge
10

tebakan pertama saya adalah optimasi kompiler karena Anda tidak pernah menggunakan root. Anda cukup menetapkannya, lalu menimpanya lagi dan lagi.

Sunting: sial, kalahkan 9 detik!

Neil N
sumber
2
Saya katakan Anda benar. Variabel aktual ditimpa dan tidak pernah digunakan lebih dari itu. Csc kemungkinan besar akan mengabaikan keseluruhan loop sementara kompiler c ++ mungkin membiarkannya masuk. Tes yang lebih akurat adalah mengumpulkan hasil dan kemudian mencetak hasilnya di akhir. Juga seseorang tidak boleh membuat kode keras nilai seed, tetapi membiarkannya ditentukan oleh pengguna. Ini tidak akan memberi kompiler c # ruang apapun untuk meninggalkan barang-barang.
7

Untuk melihat apakah loop sedang dioptimalkan, coba ubah kode Anda menjadi

root += Math.Sqrt(i);

ans serupa dalam kode C, dan kemudian mencetak nilai root di luar loop.


sumber
6

Mungkin kompilator c # memperhatikan Anda tidak menggunakan root di mana pun, jadi ia melewatkan keseluruhan for loop. :)

Itu mungkin bukan masalahnya, tapi saya curiga apapun penyebabnya, itu bergantung pada implementasi compiler. Coba kompilasi program C Anda dengan kompiler Microsoft (cl.exe, tersedia sebagai bagian dari win32 sdk) dengan pengoptimalan dan mode Rilis. Saya yakin Anda akan melihat peningkatan kinerja dibandingkan kompiler lainnya.

EDIT: Saya tidak berpikir kompiler dapat mengoptimalkan pengulangan for, karena harus tahu bahwa Math.Sqrt () tidak memiliki efek samping.

i_am_jorf
sumber
2
Mungkin dia tahu itu.
2
@Neil, @jeff: Setuju, dia bisa tahu itu dengan mudah. Bergantung pada implementasinya, analisis statis pada Math.Sqrt () mungkin tidak terlalu sulit, meskipun saya tidak yakin pengoptimalan apa yang dilakukan secara khusus.
John Feminella
5

Apapun waktunya berbeda. Mungkin, "waktu yang berlalu" itu tidak valid. Ini hanya akan menjadi valid jika Anda dapat menjamin bahwa kedua program berjalan di bawah kondisi yang sama persis.

Mungkin Anda harus mencoba menang. setara dengan $ / usr / bin / time my_cprog; / usr / bin / time my_csprog

Tom
sumber
1
Mengapa ini tidak disukai? Adakah yang berasumsi bahwa interupsi dan sakelar konteks tidak memengaruhi kinerja? Adakah yang bisa membuat asumsi tentang TLB meleset, bertukar halaman, dll?
Tom
5

Saya mengumpulkan (berdasarkan kode Anda) dua tes yang lebih sebanding di C dan C #. Keduanya menulis array yang lebih kecil menggunakan operator modulus untuk pengindeksan (ini menambahkan sedikit overhead, tapi hei, kami mencoba membandingkan kinerja [pada tingkat kasar]).

Kode C:

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

void main()
{
    int count = (int)1e8;
    int subcount = 1000;
    double* roots = (double*)malloc(sizeof(double) * subcount);
    clock_t start = clock();
    for (int i = 0 ; i < count; i++)
    {
        roots[i % subcount] = sqrt((double)i);
    }
    clock_t end = clock();
    double length = ((double)end - start) / CLOCKS_PER_SEC;
    printf("Time elapsed: %f\n", length);
}

Di C #:

using System;

namespace CsPerfTest
{
    class Program
    {
        static void Main(string[] args)
        {
            int count = (int)1e8;
            int subcount = 1000;
            double[] roots = new double[subcount];
            DateTime startTime = DateTime.Now;
            for (int i = 0; i < count; i++)
            {
                roots[i % subcount] = Math.Sqrt(i);
            }
            TimeSpan runTime = DateTime.Now - startTime;
            Console.WriteLine("Time elapsed: " + Convert.ToString(runTime.TotalMilliseconds / 1000));
        }
    }
}

Tes ini menulis data ke sebuah array (sehingga runtime .NET tidak boleh diizinkan untuk memilih operasi sqrt) meskipun array secara signifikan lebih kecil (tidak ingin menggunakan memori yang berlebihan). Saya menyusun ini dalam konfigurasi rilis dan menjalankannya dari dalam jendela konsol (alih-alih memulai melalui VS).

Di komputer saya, program C # bervariasi antara 6,2 dan 6,9 detik, sedangkan versi C bervariasi antara 6,9 dan 7.1.

Cecil Memiliki Nama
sumber
5

Jika Anda hanya satu langkah kode di tingkat perakitan, termasuk melalui rutin akar kuadrat, Anda mungkin akan mendapatkan jawaban atas pertanyaan Anda.

Tidak perlu menebak-nebak.

Mike Dunlavey
sumber
Saya ingin tahu bagaimana melakukan ini
Josh Stodola
Tergantung pada IDE atau debugger Anda. Istirahat di awal pgm. Tampilkan jendela pembongkaran, dan mulai satu langkah. Jika menggunakan GDB, ada perintah untuk melangkah satu instruksi dalam satu waktu.
Mike Dunlavey
Nah, itu tip yang bagus, ini membantu seseorang lebih memahami apa yang sebenarnya terjadi di sana. Apakah itu juga menunjukkan pengoptimalan JIT seperti panggilan sebaris dan ekor?
gjvdkamp
FYI: bagi saya ini menunjukkan VC ++ menggunakan fadd dan fsqrt sedangkan C # menggunakan cvtsi2sd dan sqrtsd yang seperti yang saya mengerti adalah instruksi SSE2 dan jauh lebih cepat jika didukung.
danio
2

Faktor lain yang mungkin menjadi masalah di sini adalah bahwa kompilator C mengkompilasi ke kode asli generik untuk keluarga prosesor yang Anda targetkan, sedangkan MSIL yang dihasilkan ketika Anda mengkompilasi kode C # kemudian JIT dikompilasi untuk menargetkan prosesor yang sama persis dengan yang Anda miliki. optimisasi yang dimungkinkan. Jadi kode asli yang dihasilkan dari C # mungkin jauh lebih cepat daripada C.

David M
sumber
Secara teori, ya. Dalam praktiknya, hal itu hampir tidak pernah membuat perbedaan yang dapat diukur. Satu atau dua persen, mungkin, jika Anda beruntung.
jalf
atau - jika Anda memiliki jenis kode tertentu yang menggunakan ekstensi yang tidak ada dalam daftar yang diizinkan untuk prosesor 'generik'. Hal-hal seperti rasa SSE. Coba dengan target prosesor yang ditetapkan lebih tinggi, untuk melihat perbedaan apa yang Anda dapatkan.
gbjbaanb
1

Tampaknya bagi saya ini tidak ada hubungannya dengan bahasa itu sendiri, melainkan berkaitan dengan implementasi yang berbeda dari fungsi akar kuadrat.

Jack Ryan
sumber
Saya sangat meragukan penerapan sqrt yang berbeda akan menyebabkan banyak perbedaan.
Alex Fort
Terutama karena, bahkan di C #, sebagian besar fungsi matematika masih dianggap penting untuk kinerja dan diterapkan seperti itu.
Matthew Olenik
fsqrt adalah instruksi prosesor IA-32, jadi implementasi bahasa tidak relevan saat ini.
Tidak Yakin
Masuk ke fungsi sqrt MSVC dengan debugger. Ini melakukan lebih dari sekedar menjalankan instruksi fsqrt.
bk1e
1

Sebenarnya teman-teman, loop TIDAK dioptimalkan. Saya mengumpulkan kode John dan memeriksa .exe yang dihasilkan. Isi loop adalah sebagai berikut:

 IL_0005:  stloc.0
 IL_0006:  ldc.i4.0
 IL_0007:  stloc.1
 IL_0008:  br.s       IL_0016
 IL_000a:  ldloc.1
 IL_000b:  conv.r8
 IL_000c:  call       float64 [mscorlib]System.Math::Sqrt(float64)
 IL_0011:  pop
 IL_0012:  ldloc.1
 IL_0013:  ldc.i4.1
 IL_0014:  add
 IL_0015:  stloc.1
 IL_0016:  ldloc.1
 IL_0017:  ldc.i4     0x5f5e100
 IL_001c:  ble.s      IL_000a

Kecuali jika runtime cukup pintar untuk menyadari loop tidak melakukan apa-apa dan melewatinya?

Edit: Mengubah C # menjadi:

 static void Main(string[] args)
 {
      DateTime startTime = DateTime.Now;
      double root = 0.0;
      for (int i = 0; i <= 100000000; i++)
      {
           root += Math.Sqrt(i);
      }
      System.Console.WriteLine(root);
      TimeSpan runTime = DateTime.Now - startTime;
      Console.WriteLine("Time elapsed: " +
          Convert.ToString(runTime.TotalMilliseconds / 1000));
 }

Hasil dalam waktu yang telah berlalu (di mesin saya) berubah dari 0,047 menjadi 2,17. Tetapi apakah itu hanya biaya tambahan untuk menambah 100 juta operator tambahan?

Dana
sumber
3
Melihat IL tidak memberi tahu Anda banyak tentang pengoptimalan karena meskipun kompilator C # melakukan beberapa hal seperti melipat terus-menerus dan menghapus kode mati, IL kemudian mengambil alih dan melakukan sisanya pada waktu pemuatan.
Daniel Earwicker
Itulah yang saya pikir mungkin terjadi. Meskipun memaksanya untuk bekerja, ini masih 9 detik lebih cepat dari versi C. (Saya tidak akan mengharapkan itu sama sekali)
Dana