Dalam wawancara baru-baru ini, saya ditanyai pertanyaan yang sangat aneh. Pewawancara bertanya kepada saya bagaimana saya dapat menghitung 1 + 2 + 3 + ... + 1000 hanya dengan menggunakan fitur kompilator. Ini berarti bahwa saya tidak diizinkan untuk menulis program dan menjalankannya, tetapi saya sebaiknya menulis program yang dapat mendorong kompiler untuk menghitung jumlah ini saat kompilasi dan mencetak hasilnya saat kompilasi selesai. Sebagai petunjuk, dia mengatakan kepada saya bahwa saya dapat menggunakan fitur generik dan pra-prosesor dari kompilator. Anda dapat menggunakan kompiler C ++, C # atau Java. Ada ide ???
Pertanyaan ini tidak terkait dengan penghitungan jumlah tanpa loop apa pun yang ditanyakan di sini . Selain itu, perlu dicatat bahwa jumlah HARUS dihitung selama kompilasi. Mencetak hanya hasil menggunakan arahan kompilator C ++ tidak dapat diterima.
Membaca lebih lanjut tentang jawaban yang diposting, saya menemukan bahwa menyelesaikan masalah selama kompilasi menggunakan template C ++ disebut metaprogramming . Ini adalah teknik yang ditemukan secara tidak sengaja oleh Dr. Erwin Unruh, selama proses standarisasi bahasa C ++. Anda dapat membaca lebih lanjut tentang topik ini di halaman wiki meta-pemrograman . Tampaknya dimungkinkan untuk menulis program di Java menggunakan anotasi java. Anda bisa melihat jawaban maress di bawah ini.
Buku bagus tentang meta-pemrograman di C ++ adalah yang ini . Layak untuk dilihat jika tertarik.
Pustaka meta-pemrograman C ++ yang berguna adalah MPL Boost tautan ini .
const int value = 1 + 2 + 3.... + 1000; Console.WriteLine(value);
; PJawaban:
Diperbarui Sekarang dengan kedalaman rekursi yang ditingkatkan! Bekerja pada MSVC10 dan GCC tanpa peningkatan kedalaman. :)
Rekursi waktu kompilasi sederhana + penambahan:
Kode tes:
Keluaran untuk GCC:
Contoh langsung di Ideone .
Output untuk MSVC10:
sumber
C # contoh kesalahan pada waktu kompilasi.
Menghasilkan kesalahan kompilasi berikut:
sumber
Trik populer untuk mencetak nomor selama kompilasi adalah mencoba mengakses anggota template yang tidak ada yang dibuat dengan nomor yang ingin Anda cetak:
Kompiler kemudian berkata:
Untuk contoh yang lebih menarik dari teknik ini, lihat Memecahkan masalah delapan ratu pada waktu kompilasi .
sumber
print_n
tetap tidak terdefinisi, lihat jawaban saya.Karena tidak ada kompiler atau bahasa yang ditentukan dalam pertanyaan wawancara, saya berani mengirimkan solusi di Haskell menggunakan GHC:
Kompilasi:
Dan kami mendapat program kerja juga.
sumber
Hidup akan jauh lebih mudah dengan C ++ 11 yang menambahkan
constexpr
fungsi untuk penghitungan waktu kompilasi, meskipun saat ini hanya didukung oleh gcc 4.6 atau yang lebih baru.Standar tersebut hanya mensyaratkan kompilator untuk mendukung kedalaman rekursi 512, jadi masih perlu menghindari kedalaman rekursi linier. Berikut hasilnya:
Tentu saja Anda bisa menggunakan rumus:
sumber
constexpr
sejenak. Mungkin saya terlalu menyukai template. :(/ 2
menangani berbagai kemungkinanunsigned
hasil, nilai yang Anda geser ke kanan harus memiliki lebar n + 1 bit, tetapi sebenarnya tidak. Ada kemungkinan untuk mengatur ulang rumus untuk menghindarinya, seperti yang dilakukan clang untuk rentang variabel runtime: godbolt.org/z/dUGXqg menunjukkan bahwa clang mengetahui rumus bentuk tertutup dan menggunakannya untuk mengoptimalkantotal += i
loop.Di java, saya berpikir untuk menggunakan pemrosesan anotasi. Alat apt memindai file sumber sebelum benar-benar mengurai file sumber ke perintah javac.
Selama kompilasi file sumber, output akan dicetak:
Pabrik prosesor:
Pemroses anotasi sebenarnya:
Kemudian kami membuat file sumber. kelas sederhana yang menggunakan anotasi MyInterface:
Prosesor anotasi dikompilasi menjadi file jar, kemudian alat apt digunakan untuk mengkompilasi file sumber sebagai:
Keluaran proyek:
sumber
Berikut adalah implementasi yang bekerja di bawah VC ++ 2010. Saya harus memecah perhitungan menjadi 3 tahap karena kompilator mengeluh ketika templat berulang 500+ kali.
Ketika Anda mengkompilasi ini, Anda akan melihat keluaran dari kompilator seperti ini:
sumber
Saya merasa berkewajiban untuk memberikan kode C ini, karena belum ada orang lain yang:
Dan yang perlu saya lakukan adalah memeriksa perakitan untuk menemukan jawaban saya!
Dan saya melihat:
sumber
x
bersifat global, kompilator akan (lebih atau kurang) diperlukan untuk mengevaluasi ekspresi pada waktu kompilasi. ISO C tidak mengizinkan penginisialisasi variabel waktu proses untuk global. Tentu saja implementasi tertentu dapat memancarkan panggilan ke fungsi static-init seperti konstruktor yang menghitungnya pada waktu proses dan penyimpanan. Tetapi ISO C memungkinkan Anda menggunakan konstanta waktu kompilasi sebagai ukuran array (sepertiint y[x];
dalam definisi struct atau sebagai global lain misalnya), jadi implementasi pesimistis hipotetis apa pun masih harus mendukungnya.Diperpanjang dari jawaban Carl Walsh untuk benar-benar mencetak hasil selama kompilasi:
keluaran gcc:
sumber
Anda dapat menggunakan (dan kebanyakan menyalahgunakan) makro / template C ++ untuk melakukan metaprogramming . AFAIK, Java tidak mengizinkan hal yang sama.
sumber
Secara teori, Anda dapat menggunakan ini:
(berdasarkan kode yang diposting Xeo). Tapi GCC memberi saya kesalahan ini:
ditambah pelacakan pseudo-stack yang sangat besar.
sumber
Menggunakan java Anda dapat melakukan hal yang mirip dengan jawaban C #:
Anda dapat melakukan ini dalam skala menggunakan nomor peano karena Anda dapat memaksa kompiler untuk melakukan rekursi tetapi saya rasa Anda tidak dapat melakukan hal yang sama di c # / java
solusi lain tidak menggunakan -Xprint tetapi bahkan lebih cerdik
tanpa menggunakan flag compiler apapun. karena Anda dapat memeriksa jumlah konstanta yang berubah-ubah (bukan hanya 500500) solusi ini dapat diterima.
sumber
500500
, maaf.for (i = 0; i < 100000; ++i) {if (i == 1000*1000/2) print i}
. saya memiliki file java 160mb yang melakukan ini dan berfungsi :)Meskipun ini benar-benar berfungsi dengan angka kecil, clang ++ mengembalikan saya kesalahan kompiler jika saya menggunakan sum_first di mana N> 400.
sumber