Versi yang menggunakan bitwise dan (&) jauh lebih efisien daripada versi modulo (%). Anda harus mengubah jawaban yang Anda pilih sebagai jawaban yang benar.
Stefan Rusek
6
Tidak mungkin menjadi masalah - argumen adalah konstan. Mudah untuk pengoptimal
MSalters
2
Faktor keterbacaan ke dalam ini juga.
Brian G
2
Dalam aplikasi embedded (dunia tempat saya menghabiskan sebagian besar waktu pemrograman saya), beberapa prosesor memiliki unit aritmatika yang sangat primitif dan tidak dapat melakukan operasi divisi / modulus dengan mudah. Untuk alasan ini, saya biasanya menggunakan metode bitwise-dan sebagai gantinya. Namun, pada CPU desktop modern ini tidak akan terjadi.
bta
3
Saya tidak pernah menemukan operasi modulus lebih mudah dimengerti. Ketika saya pertama kali perlu menentukan genap atau ganjil, topeng bitwise adalah hal pertama yang terlintas di benak saya. Ini agak alami, karena cara kita cenderung melakukan ini dengan tangan adalah dengan melihat angka paling tidak signifikan untuk melihat apakah angka itu ada di {0 2 4 6 8} atau {1 3 5 7 9}. Itu berarti langsung melihat sedikit yang paling signifikan untuk melihat apakah itu 0 atau 1.
P Ayah
Jawaban:
449
Gunakan operator modulo (%) untuk memeriksa apakah ada sisa saat membaginya dengan 2:
if(x %2){/* x is odd */}
Beberapa orang mengkritik jawaban saya di atas yang menyatakan bahwa menggunakan x & 1 adalah "lebih cepat" atau "lebih efisien". Saya tidak percaya ini yang terjadi.
Karena penasaran, saya membuat dua program kasus uji sepele:
/* modulo.c */#include<stdio.h>int main(void){int x;for(x =0; x <10; x++)if(x %2)
printf("%d is odd\n", x);return0;}/* and.c */#include<stdio.h>int main(void){int x;for(x =0; x <10; x++)if(x &1)
printf("%d is odd\n", x);return0;}
Saya kemudian mengompilasinya dengan gcc 4.1.3 di salah satu mesin saya 5 kali berbeda:
Tanpa flag optimasi.
Dengan -O
Dengan -Os
Dengan -O2
Dengan -O3
Saya memeriksa output perakitan dari setiap kompilasi (menggunakan gcc -S) dan menemukan bahwa dalam setiap kasus, output untuk dan.c dan modulo.c adalah identik (mereka berdua menggunakan andl $ 1,% instruksi eax%). Saya ragu ini adalah fitur "baru", dan saya menduga ini berasal dari versi kuno. Saya juga meragukan kompiler non-arcane (komersial dalam 20 tahun terakhir) modern, komersial atau open source, tidak memiliki optimasi seperti itu. Saya akan menguji pada kompiler lain, tetapi saya tidak memiliki yang tersedia saat ini.
Jika ada orang lain yang mau menguji kompiler dan / atau target platform lain, dan mendapatkan hasil yang berbeda, saya akan sangat tertarik untuk mengetahuinya.
Akhirnya, versi modulo dijamin oleh standar untuk bekerja apakah bilangan bulat positif, negatif atau nol, terlepas dari representasi implementasi bilangan bulat yang ditandatangani. Bitwise-dan versinya tidak. Ya, saya menyadari bahwa komplemen dua jenis ini agak ada di mana-mana, jadi ini bukan masalah.
Pertanyaannya secara khusus menanyakan bagaimana melakukannya di C jadi saya menjawabnya di C, meskipun menyebutkan bahwa mereka tidak bisa melakukannya di Jawa. Saya tidak mengklaim atau menyiratkan ini adalah jawaban Java, saya tidak tahu Java. Saya pikir saya baru saja downvote pertama saya dan saya bingung mengapa. Baiklah.
Chris Young
33
Saya akan mengatakan, jika (x% 2! = 0) {/ * x aneh * /}, tetapi siapa tahu. Tidak tahu java juga.
eugensk
9
Semakin banyak upvotes untuk membedakannya dari orang bodoh operator bitwise, tanpa harus menghabiskan karma kami untuk memberikan suara.
Berkumandang
13
Saya setuju dengan semuanya, kecuali satu hal: Saya suka menjaga bilangan bulat dan nilai kebenaran terpisah, secara konseptual, jadi saya lebih suka menulis "jika (x% 2 == 1)". Itu sama dengan kompiler, tapi mungkin sedikit lebih jelas bagi manusia. Plus, Anda dapat menggunakan kode yang sama dalam bahasa yang tidak menafsirkan non-nol sebagai benar.
Thomas Padron-McCarthy
46
Benchmark saya? Benchmark apa? Saya tidak melakukan pembandingan. Saya memeriksa bahasa assembly yang dihasilkan. Ini sama sekali tidak ada hubungannya dengan printf.
Chris Young
207
Kalian waaaaaaaay terlalu efisien. Yang Anda inginkan adalah:
public boolean isOdd(int num){int i =0;
boolean odd =false;while(i != num){
odd =!odd;
i = i +1;}return odd;}
Ulangi untuk isEven.
Tentu saja, itu tidak berfungsi untuk angka negatif. Tetapi dengan kecemerlangan datang pengorbanan ...
Jika Anda melemparkan pengecualian argumen pada nilai negatif, dan mencatat dalam dokumentasi bahwa fungsi ini adalah O (N), maka saya akan setuju dengan ini.
Jeffrey L Whitledge
7
Versi perusahaan harus menggunakan XML. Tentu saja saat ini Anda akan memiliki layanan web yang dapat Anda tanyakan
Martin Beckett
58
Anda harus mengoptimalkan ini dengan tabel pencarian.
Weeble
1
Saya seorang bhikkhu, harus memberi +1 6.999 perwakilan Anda ke milenium baru
Eran Medan
7
Ini brilian! Bos saya memberi tahu saya bahwa kami memiliki klien yang marah karena dia merasa Lisensi Perusahaannya tidak memberikan apa pun selain Lisensi Standar. Sekarang kami telah menambahkan fungsi ini dalam program kami, dan hanya karena dijalankan lebih lambat, ia pikir perangkat lunaknya melakukan CARA lebih banyak pekerjaan !!!
Saya tidak berpikir itu adil untuk mengatakan itu lebih cepat daripada menggunakan pembagian atau modulus. Standar C tidak mengatakan apa pun tentang kinerja operator, dan penyusun yang layak apa pun akan menghasilkan kode cepat untuk keduanya. Saya pribadi akan memilih idiom yang mengomunikasikan maksud saya, dan% tampaknya lebih sesuai di sini
Chris Young
21
Saya suka (x & 1) lebih baik, karena memeriksa apakah nomornya bahkan sama dengan yang dilakukan orang: memeriksa apakah angka terakhir genap atau ganjil. Menurut pendapat saya itu mengomunikasikan maksudnya lebih dari metode modulo. (Bukan berarti itu penting.)
Jeremy Ruten
2
Anda benar, saya kira itu subjektif. Meskipun definisi "bahkan" yang umum adalah "integer yang dapat dibagi dengan 2", bukan "integer yang berakhir dengan 0, 2, 4, 6 atau 8". :-)
Chris Young
4
@TraumaPony - untuk standar ANSI C dan Java awal, tergantung pada sistem komputer. Tidak ditentukan representasi apa yang digunakan untuk angka yang ditandatangani - pujian 2, pujian 1, kode abu-abu, dll. Tapi modulus selalu modulus
Aaron
9
Tidak bekerja secara universal untuk angka negatif. Lihat Periksa jawaban ini untuk detail lebih lanjut: stackoverflow.com/questions/160930/… untuk detailnya.
Wow ... ini lebih gila daripada solusi SCdF! Pujian! Tidak ada suara positif ... tidak dapat merekomendasikan ini. Tapi terima kasih untuk yang lucu!
Wes P
1
Keuntungan dari pendekatan ini adalah ia bekerja dengan lebih dari sekedar angka. Juga, jika Anda mengganti baris ini: char bar = foo [foo.Length - 1]; dengan ini: double bar = Char.GetNumericValue (foo [foo.Length - 1]); Maka itu akan bekerja dengan sistem nomor apa pun.
Jeffrey L Whitledge
5
laporan bug: 14,65 dilaporkan aneh ketika seharusnya tidak diketahui.
TheSoftwareJedi
4
Perangkat lunak Jedi, ini adalah "fitur". ;)
Sklivvz
31
TheSoftwareJedi: 14.65 adalah salah satu bilangan bulat paling aneh yang pernah saya lihat.
Bruce Alderman
16
Menanggapi ffpf - saya memiliki argumen yang persis sama dengan seorang rekan bertahun-tahun yang lalu, dan jawabannya adalah tidak , itu tidak bekerja dengan angka negatif.
Standar C menetapkan bahwa angka negatif dapat direpresentasikan dalam 3 cara:
Pelengkap 2
Pelengkap 1
tanda dan besarnya
Memeriksa seperti ini:
isEven =(x &1);
akan bekerja untuk komplemen 2 dan tanda dan representasi besarnya, tetapi tidak untuk komplemen 1.
Namun, saya percaya bahwa yang berikut ini akan berfungsi untuk semua kasus:
isEven =(x &1)^((-1&1)|((x <0)?0:1)));
Terima kasih kepada ffpf karena menunjukkan bahwa kotak teks memakan segalanya setelah karakter saya yang kurang!
Saya pikir contoh kode kedua Anda kehilangan beberapa teks.
Jeff Yates
3
Mari kita memuji angka-angka itu!
thejh
14
Yang bagus adalah:
/*forward declaration, C compiles in one pass*/bool isOdd(unsignedint n);bool isEven(unsignedint n){if(n ==0)returntrue;// I know 0 is evenelsereturn isOdd(n-1);// n is even if n-1 is odd}bool isOdd(unsignedint n){if(n ==0)returnfalse;elsereturn isEven(n-1);// n is odd if n-1 is even}
Perhatikan bahwa metode ini menggunakan rekursi ekor yang melibatkan dua fungsi. Ini dapat diimplementasikan secara efisien (berubah menjadi semacam sementara / sampai loop) jika kompiler Anda mendukung rekursi ekor seperti kompiler Skema. Dalam hal ini tumpukan tidak boleh meluap!
Saya pikir Anda punya loop tak terbatas (dengan rekursi ekor) atau stack overflow (tanpa rekursi ekor) untuk isOdd () dengan nilai genap atau isEven () dengan nilai ganjil. Itu hanya berakhir dengan true. Ini masalah penghentian lagi.
Jeffrey L Whitledge
7
Oh, tentu, perbaiki tanpa komentar, dan buat aku terlihat seperti orang idiot. Tidak apa-apa.
Jeffrey L Whitledge
1
Sekarang, Anda memiliki kesalahan kompilasi: di isEven tidak semua jalur kode mengembalikan nilai. Tidak, saya belum benar-benar mencoba kode ini, itu kompiler di kepala saya yang mengeluh.
Jeffrey L Whitledge
5
kompilasi kesalahan: tidak semua jalur mengembalikan nilai benci untuk membombardir Anda dengan komentar bug pada kode sampel Anda, tetapi apa yang terjadi ketika Anda memanggil isEven (5)
Kevin
11
Angka adalah bahkan jika, ketika dibagi dua, sisanya adalah 0. Angka ganjil jika, ketika dibagi 2, sisanya adalah 1.
// Javapublicstatic boolean isOdd(int num){return num %2!=0;}/* C */int isOdd(int num){return num %2;}
Metode Java Anda rusak karena num% 2 == -1 untuk angka ganjil negatif.
WMR
Apakah itu sebabnya Anda menurunkan saya?
jjnguy
3
Saya menurunkannya karena fungsi Anda di C membutuhkan lebih banyak karakter untuk diketik daripada apa yang dilakukannya. IE num% I adalah 7 karakter termasuk spasi IsOdd (I) adalah 8 karakter. Mengapa Anda membuat fungsi yang lebih lama dari sekadar melakukan operasi?
Kevin
13
@Kevin dalam kode pendapat saya tidak diukur dengan karakter melainkan pada saat Anda menulisnya, termasuk waktu think + debug. num% 2 membutuhkan milidetik lebih untuk dipikirkan daripada isOdd. sekarang tambahkan angka secara global dan Anda kehilangan tahun kolektif. juga isOdd dapat diuji, dan diverifikasi dan akhirnya disertifikasi bebas bug (mis. menangani angka negatif) di mana num% 2 - beberapa pengembang akan selalu ragu dan bereksperimen. kode yang baik adalah kode yang tidak Anda tulis, gunakan kembali ... hanya 2 sen saya.
Eran Medan
2
@EranMedan, Logika yang sama akan berlaku untuk mengganti i ++ dengan IncrementByOne (i) dan itu adalah ide yang sama buruknya. Jika pengembang ragu tentang apa yang dilakukan angka 2, saya tidak ingin dia mendekati kode saya.
Saya akan membatalkan ini, tapi agak lambat pada angka negatif. :)
Chris Young
3
Semua angka cerah dan positif. Atau apakah Anda berprasangka terhadap beberapa orang? :))
eugensk
3
Di komputer, semua angka yang dulu negatif, akhirnya menjadi positif. Kami menyebutnya Rollover of Happiness (tidak berlaku untuk BIGNUMS, YMMY, tidak berlaku di semua negara bagian).
Will Hartung
@WillHartung "rollover of happiness" is great! : D
thejh
6
Saya akan membangun tabel paritas (0 jika bahkan 1 jika ganjil) dari bilangan bulat (sehingga orang dapat melakukan pencarian: D), tetapi gcc tidak akan membiarkan saya membuat array dengan ukuran seperti ini:
Jadi mari kita beralih ke definisi matematika genap dan gantinya.
Integer n adalah bahkan jika ada integer k sehingga n = 2k.
Suatu bilangan bulat n ganjil jika ada bilangan bulat k sedemikian sehingga n = 2k + 1.
Ini kode untuk itu:
char even (int n){int k;for(k = INT_MIN; k <= INT_MAX;++k){if(n ==2* k){return1;}}return0;}char odd (int n){int k;for(k = INT_MIN; k <= INT_MAX;++k){if(n ==2* k +1){return1;}}return0;}
Biarkan C-integer menunjukkan nilai yang mungkin dari intdalam kompilasi C yang diberikan. (Perhatikan bahwa C-integer adalah subset dari integer.)
Sekarang orang mungkin khawatir bahwa untuk n yang diberikan dalam C-integer bahwa k integer yang sesuai mungkin tidak ada dalam C-integer. Tetapi dengan sedikit bukti dapat ditunjukkan bahwa untuk semua bilangan bulat n, | n | <= | 2n | (*), di mana | n | adalah "n jika n positif dan -n sebaliknya". Dengan kata lain, untuk semua n dalam bilangan bulat setidaknya salah satu dari pegangan berikut (tepatnya case (1 dan 2) atau case (3 dan 4) sebenarnya tetapi saya tidak akan membuktikannya di sini):
Kasus 1: n <= 2n.
Kasus 2: -n <= -2n.
Kasus 3: -n <= 2n.
Kasus 4: n <= -2n.
Sekarang ambil 2k = n. (Ak semacam itu memang ada jika n adalah genap, tetapi saya tidak akan membuktikannya di sini. Jika n tidak genap maka loop ineven gagal kembali lebih awal, jadi itu tidak masalah.) Tapi ini menyiratkan k <n jika n bukan 0 oleh (*) dan fakta (sekali lagi tidak terbukti di sini) bahwa untuk semua m, z dalam bilangan bulat 2m = z menyiratkan z tidak sama dengan m yang diberikan m bukan 0. Dalam kasus n adalah 0, 2 * 0 = 0 jadi 0 bahkan kita sudah selesai (jika n = 0 maka 0 ada di C-integer karena n ada di C-integer dalam fungsi even, maka k = 0 ada di C-integer). Dengan demikian ak dalam C-integer ada untuk n dalam C-integer jika n adalah genap.
Argumen serupa menunjukkan bahwa jika n ganjil, ada ak di C-integer sehingga n = 2k + 1.
Karenanya fungsi evendan yang odddisajikan di sini akan berfungsi dengan baik untuk semua C-integer.
Bisakah Anda jelaskan ini? Saya sangat tidak terbiasa dengan operator bitwise
Abdul
Bergeser ke kanan dan ke kiri akan nol bit terakhir Anda (yang paling kanan). Jika nomor baru sama dengan yang asli, ini berarti bahwa bit terakhir dari angka asli adalah 0. Jadi itu genap. Lihatlah jawaban saya yang diperbarui.
Kiril Aleksandrov
terima kasih, saya mengerti sekarang
Abdul
Saya tidak yakin pendekatan mana yang lebih cepat. Saya belum mencoba membandingkan mereka.
Kiril Aleksandrov
Bukankah ini juga nol bit paling signifikan Anda? Masalah dengan int unsigned dalam beberapa bahasa dan int negatif di sebagian besar ...
Troyseph
4
Membaca diskusi yang agak menghibur ini, saya ingat bahwa saya memiliki dunia nyata, fungsi sensitif waktu yang menguji angka ganjil dan genap di dalam lingkaran utama. Ini adalah fungsi daya integer, diposting di tempat lain di StackOverflow, sebagai berikut. Tolok ukurnya cukup mengejutkan. Setidaknya dalam fungsi dunia nyata ini, modulo lebih lambat , dan sangat signifikan. Pemenang, dengan selisih yang lebar, membutuhkan 67% waktu modulo, adalah pendekatan atau (|) , dan tidak ditemukan di mana pun di halaman ini.
static dbl IntPow(dbl st0,int x){
UINT OrMask= UINT_MAX -1;
dbl st1=1.0;if(0==x)return(dbl)1.0;while(1!= x){if(UINT_MAX ==(x|OrMask)){// if LSB is 1... //if(x & 1) {//if(x % 2) {
st1 *= st0;}
x = x >>1;// shift x right 1 bit...
st0 *= st0;}return st1 * st0;}
Untuk 300 juta loop, timing benchmark adalah sebagai berikut.
3.962 | dan pendekatan topeng
4.851 pendekatan &
5.850 pendekatan%
Untuk orang-orang yang berpikir teori, atau daftar bahasa majelis, menyelesaikan argumen seperti ini, ini harus menjadi kisah peringatan. Ada lebih banyak hal di surga dan bumi, Horatio, daripada yang diimpikan dalam filosofi Anda.
Lebih baik digunakan unsigned xsebagaimana x = x >> 1;implementasi-didefinisikan perilaku saat x < 0. Belum jelas alasan xdan OrMaskjenisnya berbeda. Cukup sederhana untuk menulis ulang menggunakan while(x)tes.
chux
2
Saya ingin tahu kompiler mana yang Anda gunakan untuk benchmark ini, karena sebagian besar kompiler harus cukup pintar untuk mengkompilasi % 2kasing menggunakan bitwise &. Saya baru saja menguji ini dan hasilnya benar-benar sama (VS2015, Rilis dibangun dengan semua optimisasi, baik x86 dan x64). Jawaban yang diterima juga menyatakan ini untuk GCC (ditulis pada 2008).
Lou
2
Masalah dengan posting ini adalah bahwa premis bahwa bitwise orakan lebih cepat daripada andsangat tidak mungkin, pada platform / kompiler. Bahkan jika ada kombinasi platform / kompiler yang aneh (dan Anda belum mempostingnya atau kode yang digunakan untuk melakukan benchmark), tergantung pada kompiler lain untuk berperilaku yang sama akan menjadi taruhan optimasi yang buruk. Jadi, ketika saya menulis, saya bertanya-tanya di platform / kompiler mana ini diuji , karena saya hampir yakin itu tidak diukur dengan benar.
Lou
2
Tidak menyebut Anda pembohong, hanya mengklaim dengan kepastian tinggi bahwa Anda tidak mengukur dengan benar. Tidak perlu memanggil saya seorang pengemudi truk, baca komentar asli saya: Saya memang membuat patokan, dan hasilnya, seperti yang diharapkan, sepenuhnya sama dalam ketiga kasus (kepastian ~ 3 sigma, setelah menjalankan setiap tes 10 kali untuk 500.000 .000 iterasi). Jika Anda benar-benar memiliki karir yang terkenal, mundur selangkah dan berpikir jika klaim Anda masuk akal, maka poskan kode aktual yang digunakan untuk melakukan tolok ukur. Kalau tidak, posting itu adalah apa yang saya yakini, hanya kesalahan dalam pengukuran.
Ini adalah tindak lanjut dari diskusi dengan @RocketRoy mengenai jawabannya , tetapi mungkin bermanfaat bagi siapa saja yang ingin membandingkan hasil ini.
tl; dr Dari apa yang saya lihat, pendekatan Roy ( (0xFFFFFFFF == (x | 0xFFFFFFFE)) tidak sepenuhnya dioptimalkan x & 1sebagai modpendekatan, tetapi dalam praktiknya waktu berjalan seharusnya menjadi sama dalam semua kasus.
Jadi, pertama saya membandingkan output yang dikompilasi menggunakan Compiler Explorer :
Fungsi yang diuji:
int isOdd_mod(unsigned x){return(x %2);}int isOdd_and(unsigned x){return(x &1);}int isOdd_or(unsigned x){return(0xFFFFFFFF==(x |0xFFFFFFFE));}
Klik 3.9.0 dengan -O3:
isOdd_mod(unsignedint):# @isOdd_mod(unsigned int)
and edi,1
mov eax, edi
ret
isOdd_and(unsignedint):# @isOdd_and(unsigned int)
and edi,1
mov eax, edi
ret
isOdd_or(unsignedint):# @isOdd_or(unsigned int)
and edi,1
mov eax, edi
ret
GCC 6.2 dengan -O3:
isOdd_mod(unsignedint):
mov eax, edi
and eax,1
ret
isOdd_and(unsignedint):
mov eax, edi
and eax,1
ret
isOdd_or(unsignedint):
or edi,-2
xor eax, eax
cmp edi,-1
sete al
ret
Angkat ke CLang, itu menyadari bahwa ketiga kasus secara fungsional sama. Namun, pendekatan Roy tidak dioptimalkan dalam GCC, begitu YMMV.
Ini mirip dengan Visual Studio; memeriksa Rilis pembongkaran x64 (VS2015) untuk tiga fungsi ini, saya bisa melihat bahwa bagian perbandingannya sama untuk case "mod" dan "dan", dan sedikit lebih besar untuk case Roy "atau":
// x % 2
test bl,1
je (some address)// x & 1
test bl,1
je (some address)// Roy's bitwise or
mov eax,ebx
or eax,0FFFFFFFEh
cmp eax,0FFFFFFFFh
jne (some address)
Namun, setelah menjalankan tolok ukur yang sebenarnya untuk membandingkan tiga opsi ini (mod sederhana, bitwise atau, bitwise dan), hasilnya benar-benar sama (sekali lagi, Visual Studio 2005 x86 / x64, rilis Rilis, tidak ada debugger terpasang).
Majelis rilis menggunakan testinstruksi untuk anddan modkasus, sedangkan kasus Roy menggunakancmp eax,0FFFFFFFFh pendekatan, tetapi sangat terbuka dan dioptimalkan sehingga tidak ada perbedaan dalam prakteknya.
Hasil saya setelah 20 berjalan (i7 3610QM, rencana daya Windows 10 diatur ke Kinerja Tinggi):
[Tes: Plain mod 2] WAKTU RATA-RATA: 689,29 ms (Perbedaan relatif .: + 0,000%)
[Tes: Bitwise atau] WAKTU RATA-RATA: 689,63 ms (Perbedaan relatif .: + 0,048%)
[Tes: Bitwise dan] WAKTU RATA-RATA: 687,80 ms (Perbedaan relatif .: -0,217%)
Perbedaan antara opsi-opsi ini kurang dari 0,3%, jadi agak jelas rakitannya sama dalam semua kasus.
Berikut adalah kode jika ada yang ingin mencoba, dengan peringatan bahwa saya hanya mengujinya pada Windows (periksa #if LINUXpersyaratan untuk get_timedefinisi dan menerapkannya jika perlu, diambil dari jawaban ini ).
Saya percaya Anda telah melakukan dosa pembandingan dari Kardinal; membuat satu yang begitu spesifik itu tidak mewakili lingkungan dunia nyata. Lihatlah bahasa majelis Anda dan perhatikan sedikitnya register yang Anda gunakan. Nilai tinggi untuk usaha, tetapi hasil ini tidak akan bertahan dalam pemrosesan dunia nyata.
@RocketRoy: karena semua output persis sama untuk ketiga kasus (well, sedikit lebih buruk untuk program Anda dalam satu kasus), saya tidak terlalu peduli berapa banyak register yang digunakan. Tetapi sekali lagi, jangan ragu untuk membuat dan memposting contoh program / lingkungan yang akan membingungkan kompiler untuk membuat perakitan yang lebih optimal dalam salah satu kasus, semua hal lain dianggap sama.
Lou
Saya selalu suka programmer sombong. Ini adalah sifat yang baik untuk dimiliki seorang programmer, tetapi dalam program dunia nyata yang lebih kompleks, metode saya akan berkinerja lebih baik daripada Anda karena kompiler memiliki lebih banyak cara untuk menyelesaikan masalah sehingga instruksi yang tumpang tindih (pada arsitektur Intel) menghasilkan hasil yang lebih baik . Sangat sedikit programmer veteran dengan pengalaman benchmark yang baik akan lebih suka benchmark Anda, tetapi tetap bekerja dengan baik, dan ingat untuk menjalankan kembali benchmark Anda ketika rilis chip baru keluar. Banyak hal berubah seiring waktu.
3
Saya tahu ini hanya gula sintaksis dan hanya berlaku di .net tetapi bagaimana dengan metode ekstensi ...
Metode bitwise tergantung pada representasi bagian dalam bilangan bulat. Modulo akan bekerja di mana saja ada operator modulo. Sebagai contoh, beberapa sistem benar-benar menggunakan bit level rendah untuk penandaan (seperti bahasa dinamis), sehingga x & 1 mentah tidak akan benar-benar berfungsi dalam kasus itu.
Bukti kebenaran - pertimbangkan himpunan semua bilangan bulat positif dan anggap ada satu set bilangan bulat yang tidak kosong yang tidak aneh. Karena bilangan bulat positif disusun dengan baik, akan ada bilangan terkecil bukan bilangan ganjil, yang dengan sendirinya cukup aneh, sehingga jelas bilangan itu tidak dapat diatur. Karenanya set ini tidak boleh kosong. Ulangi untuk bilangan bulat negatif kecuali mencari bilangan terbesar bukan ganjil.
Seperti yang telah diposting beberapa orang, ada banyak cara untuk melakukan ini. Menurut situs web ini , cara tercepat adalah operator modulus:
if(x %2==0)
total +=1;//even numberelse
total -=1;//odd number
Namun, berikut adalah beberapa kode lain yang ditandai oleh penulis yang berjalan lebih lambat daripada operasi modulus umum di atas:
if((x &1)==0)
total +=1;//even numberelse
total -=1;//odd numberSystem.Math.DivRem((long)x,(long)2, out outvalue);if( outvalue ==0)
total +=1;//even numberelse
total -=1;//odd numberif(((x /2)*2)== x)
total +=1;//even numberelse
total -=1;//odd numberif(((x >>1)<<1)== x)
total +=1;//even numberelse
total -=1;//odd numberwhile(index >1)
index -=2;if(index ==0)
total +=1;//even numberelse
total -=1;//odd number
tempstr = x.ToString();
index = tempstr.Length-1;//this assumes base 10if(tempstr[index]=='0'|| tempstr[index]=='2'|| tempstr[index]=='4'|| tempstr[index]=='6'|| tempstr[index]=='8')
total +=1;//even numberelse
total -=1;//odd number
Berapa banyak orang yang tahu tentang metode Math.System.DivRem atau mengapa mereka menggunakannya ??
Untuk memberikan elaborasi lebih lanjut tentang metode operator bitwise bagi kita yang tidak melakukan banyak aljabar boolean selama studi kami, berikut adalah penjelasannya. Mungkin tidak banyak berguna untuk OP, tapi saya ingin menjelaskan mengapa NUMBER & 1 berfungsi.
Harap perhatikan seperti ketika seseorang menjawab di atas, cara angka negatif ditampilkan dapat menghentikan metode ini berfungsi. Bahkan ia dapat merusak metode operator modulo juga karena masing-masing bahasa dapat berbeda dalam bagaimana berurusan dengan operan negatif.
Namun jika Anda tahu bahwa NUMBER akan selalu positif, ini berfungsi dengan baik.
Seperti Tooony di atas menyatakan bahwa hanya digit terakhir dalam biner (dan denary) yang penting.
Logika AND gerbang boolean menentukan bahwa kedua input harus berupa 1 (atau tegangan tinggi) agar 1 dikembalikan.
1 & 0 = 0.
0 & 1 = 0.
0 & 0 = 0.
1 & 1 = 1.
Jika Anda mewakili angka apa pun sebagai biner (saya telah menggunakan representasi 8 bit di sini), angka ganjil memiliki 1 di akhir, bahkan angka memiliki 0.
Sebagai contoh:
1 = 00000001
2 = 00000010
3 = 00000011
4 = 00000100
Jika Anda mengambil nomor apa pun dan menggunakan bitwise AND (& dalam java) dengan 1 maka akan mengembalikan 00000001, = 1 yang berarti angkanya ganjil. Atau 00000000 = 0, artinya angkanya genap.
Misalnya
Aneh?
1 & 1 =
00000001 &
00000001 =
00000001 <- Ganjil
2 & 1 =
00000010 &
00000001 =
00000000 <- Merata
54 & 1 =
00000001 &
00110110 =
00000000 <- Merata
Inilah mengapa ini bekerja:
if(number &1){//Number is odd}else{//Number is even}
# defining function for number parity check
def parity(number):"""Parity check function"""# if number is 0 (zero) return 'Zero neither ODD nor EVEN',# otherwise number&1, checking last bit, if 0, then EVEN, # if 1, then ODD.return(number ==0 and 'Zero neither ODD nor EVEN') \
or (number&1 and 'ODD' or 'EVEN')# cycle trough numbers from 0 to 13 for number in range(0,14):
print "{0:>4} : {0:08b} : {1:}".format(number, parity(number))
Keluaran:
0:00000000:Zero neither ODD nor EVEN
1:00000001: ODD
2:00000010: EVEN
3:00000011: ODD
4:00000100: EVEN
5:00000101: ODD
6:00000110: EVEN
7:00000111: ODD
8:00001000: EVEN
9:00001001: ODD
10:00001010: EVEN
11:00001011: ODD
12:00001100: EVEN
13:00001101: ODD
@ el.pescado, Terima Kasih. Jika Nol genap, berapa pasangan yang dimilikinya?
@ el.pescado, Ok, saya setuju dengan Anda. Lalu, Kalau dipikir-pikir, kenapa kita bagi 2 (dua)? Apa yang ingin kita ketahui, ketika kita bagi dua? Mengapa tidak membagi menjadi 3, atau, 5, dll.?
@ el.pescado Artikel Wikipedia ini Parity of Zero salah. Banyak orang tertipu oleh artikel ini. Pikirkan sebelum Wink.
1
Kamu benar. Sekarang saya sudah membaca jawaban lain saya menemukan jawaban Anda yang paling komprehensif :)
el.pescado
@ el.pescado. Terima kasih. :) Sekarang teman terbaik You're Zero. (pelukan)
1
I execute this code for ODD & EVEN:#include<stdio.h>int main(){int number;
printf("Enter an integer: ");
scanf("%d",&number);if(number %2==0)
printf("%d is even.", number);else
printf("%d is odd.", number);}
Anda hanya perlu melihat angka terakhir di nomor mana saja untuk melihat apakah angka itu genap atau ganjil. Ditandatangani, tidak ditandatangani, positif, negatif - semuanya sama dalam hal ini. Jadi ini harus bekerja sepanjang: -
void tellMeIfItIsAnOddNumberPlease(int iToTest){int iLastDigit;
iLastDigit = iToTest -(iToTest /10*10);if(iLastDigit %2==0){
printf("The number %d is even!\n", iToTest);}else{
printf("The number %d is odd!\n", iToTest);}}
Kuncinya di sini adalah di baris ketiga kode, operator divisi melakukan divisi integer, sehingga hasilnya hilang bagian fraksi dari hasil. Jadi misalnya 222/10 akan memberikan 22 hasilnya. Kemudian kalikan lagi dengan 10 dan Anda memiliki 220. Kurangi itu dari yang asli 222 dan Anda berakhir dengan 2, yang dengan sihir adalah angka yang sama dengan angka terakhir di angka asli. ;-) Tanda kurung ada di sana untuk mengingatkan kita tentang urutan perhitungan yang dilakukan. Pertama lakukan pembagian dan perkaliannya, kemudian kurangi hasilnya dari angka aslinya. Kita dapat mengabaikannya, karena prioritas lebih tinggi untuk pembagian dan penggandaan daripada pengurangan, tetapi ini memberi kita kode "lebih mudah dibaca".
Kita bisa membuat semuanya benar-benar tidak dapat dibaca jika kita mau. Tidak ada bedanya untuk kompiler modern: -
printf("%d%s\n",iToTest,0==(iToTest-iToTest/10*10)%2?" is even":" is odd");
Tapi itu akan membuat kode lebih sulit untuk dipertahankan di masa depan. Bayangkan saja Anda ingin mengubah teks untuk angka ganjil menjadi "tidak genap". Kemudian orang lain di kemudian hari ingin mengetahui perubahan apa yang Anda buat dan melakukan svn diff atau yang serupa ...
Jika Anda tidak khawatir tentang portabilitas tetapi lebih banyak tentang kecepatan, Anda bisa melihat sedikit yang paling signifikan. Jika bit itu diatur ke 1 itu adalah angka ganjil, jika itu 0 itu adalah angka genap. Pada sistem endian kecil, seperti arsitektur x86 Intel akan menjadi seperti ini: -
Apa sebenarnya yang salah dengan hanya menjalankan iToTest% 2 == 0? Anda menyia-nyiakan divisi yang mengekstraksi digit terakhir, jadi Anda dua kali lebih lambat dari yang seharusnya.
freespace
@freespace: Saya membuang lebih dari itu, bukan? :-) Penggandaan dan pengurangan juga. Tapi apa yang paling efisien di antara dua solusi yang saya tidak berani katakan. Tidak pernah mengklaim ini sebagai solusi tercepat, justru sebaliknya jika Anda membaca baris pertama posting saya lagi.
Tooony
@Tonyony, ah, topi humor saya jatuh. Ini secara resmi kembali sekarang: D Maaf tentang itu :)
freespace
0
Jika Anda ingin menjadi efisien, gunakan operator bitwise ( x & 1), tetapi jika Anda ingin dibaca, gunakan modulo 2 ( x % 2)
-1: Jika Anda ingin menjadi efisien, gunakan salah satunya. Jika Anda ingin portabel, gunakan %. Jika Anda ingin dapat dibaca, gunakan %. Hmmm, saya melihat polanya di sini.
Thomas Eding
@trinithis, tidak ada pola dan solusi ini jauh lebih baik daripada milik Anda.
Subs
0
Memeriksa genap atau ganjil adalah tugas sederhana.
Kita tahu bahwa angka apa pun yang dapat habis dibagi 2 adalah angka genap.
Kami hanya perlu memeriksa pembagian nomor apa pun dan untuk memeriksa pembagian, kami menggunakan %operator
Kode memeriksa bit terakhir dari integer jika 1 dalam Binary
Penjelasan
Binary:Decimal-------------------0000=00001=10010=20011=30100=40101=50110=60111=71000=81001=9
and so on...
Perhatikan bit paling kanan selalu 1 untuk nomor Ganjil .
yang & bitwise operator AND cek bit paling kanan di kami kembali baris jika itu 1
Anggap itu benar & salah
Ketika kita membandingkan n dengan 1 yang berarti 0001dalam biner (jumlah nol tidak masalah).
maka mari kita bayangkan saja kita memiliki bilangan bulat n dengan ukuran 1 byte.
Itu akan diwakili oleh 8-bit / 8-binary digit.
Jika int n adalah 7 dan kami membandingkannya dengan 1 , Ini seperti
7(1-byte int)|00000111&1(1-byte int)|00000001********************************************Result| F F F F F F F T
Yang F adalah false dan T untuk true.
Itu hanya membandingkan bit paling kanan jika keduanya benar. Jadi, secara otomatis 7 & 1adalah T rue.
Bagaimana jika saya ingin memeriksa bit sebelum yang paling kanan?
Hanya mengubah n & 1ke n & 2yang 2 mewakili 0010di Binary dan sebagainya.
Saya sarankan menggunakan notasi heksadesimal jika Anda seorang pemula untuk operasi bitwise return n & 1;>> return n & 0x01;.
Jawaban:
Gunakan operator modulo (%) untuk memeriksa apakah ada sisa saat membaginya dengan 2:
Beberapa orang mengkritik jawaban saya di atas yang menyatakan bahwa menggunakan x & 1 adalah "lebih cepat" atau "lebih efisien". Saya tidak percaya ini yang terjadi.
Karena penasaran, saya membuat dua program kasus uji sepele:
Saya kemudian mengompilasinya dengan gcc 4.1.3 di salah satu mesin saya 5 kali berbeda:
Saya memeriksa output perakitan dari setiap kompilasi (menggunakan gcc -S) dan menemukan bahwa dalam setiap kasus, output untuk dan.c dan modulo.c adalah identik (mereka berdua menggunakan andl $ 1,% instruksi eax%). Saya ragu ini adalah fitur "baru", dan saya menduga ini berasal dari versi kuno. Saya juga meragukan kompiler non-arcane (komersial dalam 20 tahun terakhir) modern, komersial atau open source, tidak memiliki optimasi seperti itu. Saya akan menguji pada kompiler lain, tetapi saya tidak memiliki yang tersedia saat ini.
Jika ada orang lain yang mau menguji kompiler dan / atau target platform lain, dan mendapatkan hasil yang berbeda, saya akan sangat tertarik untuk mengetahuinya.
Akhirnya, versi modulo dijamin oleh standar untuk bekerja apakah bilangan bulat positif, negatif atau nol, terlepas dari representasi implementasi bilangan bulat yang ditandatangani. Bitwise-dan versinya tidak. Ya, saya menyadari bahwa komplemen dua jenis ini agak ada di mana-mana, jadi ini bukan masalah.
sumber
Kalian waaaaaaaay terlalu efisien. Yang Anda inginkan adalah:
Ulangi untuk
isEven
.Tentu saja, itu tidak berfungsi untuk angka negatif. Tetapi dengan kecemerlangan datang pengorbanan ...
sumber
Gunakan bit aritmatika:
Ini lebih cepat daripada menggunakan pembagian atau modulus.
sumber
[Mode Joke = "on"]
[Mode Lelucon = "mati"]
EDIT: Menambahkan nilai membingungkan ke enum.
sumber
Menanggapi ffpf - saya memiliki argumen yang persis sama dengan seorang rekan bertahun-tahun yang lalu, dan jawabannya adalah tidak , itu tidak bekerja dengan angka negatif.
Standar C menetapkan bahwa angka negatif dapat direpresentasikan dalam 3 cara:
Memeriksa seperti ini:
akan bekerja untuk komplemen 2 dan tanda dan representasi besarnya, tetapi tidak untuk komplemen 1.
Namun, saya percaya bahwa yang berikut ini akan berfungsi untuk semua kasus:
Terima kasih kepada ffpf karena menunjukkan bahwa kotak teks memakan segalanya setelah karakter saya yang kurang!
sumber
Yang bagus adalah:
Perhatikan bahwa metode ini menggunakan rekursi ekor yang melibatkan dua fungsi. Ini dapat diimplementasikan secara efisien (berubah menjadi semacam sementara / sampai loop) jika kompiler Anda mendukung rekursi ekor seperti kompiler Skema. Dalam hal ini tumpukan tidak boleh meluap!
sumber
Angka adalah bahkan jika, ketika dibagi dua, sisanya adalah 0. Angka ganjil jika, ketika dibagi 2, sisanya adalah 1.
Metode sangat bagus!
sumber
sumber
Saya akan mengatakan hanya membaginya dengan 2 dan jika ada sisa 0, itu genap, kalau tidak aneh.
Menggunakan modulus (%) membuatnya mudah.
misalnya. 4% 2 = 0 karena itu 4 bahkan 5% 2 = 1 oleh karena itu 5 aneh
sumber
Satu lagi solusi untuk masalah ini
(anak-anak boleh memilih)
sumber
Saya akan membangun tabel paritas (0 jika bahkan 1 jika ganjil) dari bilangan bulat (sehingga orang dapat melakukan pencarian: D), tetapi gcc tidak akan membiarkan saya membuat array dengan ukuran seperti ini:
Jadi mari kita beralih ke definisi matematika genap dan gantinya.
Integer n adalah bahkan jika ada integer k sehingga n = 2k.
Suatu bilangan bulat n ganjil jika ada bilangan bulat k sedemikian sehingga n = 2k + 1.
Ini kode untuk itu:
Biarkan C-integer menunjukkan nilai yang mungkin dari
int
dalam kompilasi C yang diberikan. (Perhatikan bahwa C-integer adalah subset dari integer.)Sekarang orang mungkin khawatir bahwa untuk n yang diberikan dalam C-integer bahwa k integer yang sesuai mungkin tidak ada dalam C-integer. Tetapi dengan sedikit bukti dapat ditunjukkan bahwa untuk semua bilangan bulat n, | n | <= | 2n | (*), di mana | n | adalah "n jika n positif dan -n sebaliknya". Dengan kata lain, untuk semua n dalam bilangan bulat setidaknya salah satu dari pegangan berikut (tepatnya case (1 dan 2) atau case (3 dan 4) sebenarnya tetapi saya tidak akan membuktikannya di sini):
Kasus 1: n <= 2n.
Kasus 2: -n <= -2n.
Kasus 3: -n <= 2n.
Kasus 4: n <= -2n.
Sekarang ambil 2k = n. (Ak semacam itu memang ada jika n adalah genap, tetapi saya tidak akan membuktikannya di sini. Jika n tidak genap maka loop in
even
gagal kembali lebih awal, jadi itu tidak masalah.) Tapi ini menyiratkan k <n jika n bukan 0 oleh (*) dan fakta (sekali lagi tidak terbukti di sini) bahwa untuk semua m, z dalam bilangan bulat 2m = z menyiratkan z tidak sama dengan m yang diberikan m bukan 0. Dalam kasus n adalah 0, 2 * 0 = 0 jadi 0 bahkan kita sudah selesai (jika n = 0 maka 0 ada di C-integer karena n ada di C-integer dalam fungsieven
, maka k = 0 ada di C-integer). Dengan demikian ak dalam C-integer ada untuk n dalam C-integer jika n adalah genap.Argumen serupa menunjukkan bahwa jika n ganjil, ada ak di C-integer sehingga n = 2k + 1.
Karenanya fungsi
even
dan yangodd
disajikan di sini akan berfungsi dengan baik untuk semua C-integer.sumber
i % 2
jauh lebih kecil dan mungkin lebih efisien.%2
bekerja untuk semua bilangan bulat.sumber
typedef
atau#define
atau sesuatu.Ini jawaban di Jawa:
sumber
Coba ini:
return (((a>>1)<<1) == a)
Contoh:
sumber
Membaca diskusi yang agak menghibur ini, saya ingat bahwa saya memiliki dunia nyata, fungsi sensitif waktu yang menguji angka ganjil dan genap di dalam lingkaran utama. Ini adalah fungsi daya integer, diposting di tempat lain di StackOverflow, sebagai berikut. Tolok ukurnya cukup mengejutkan. Setidaknya dalam fungsi dunia nyata ini, modulo lebih lambat , dan sangat signifikan. Pemenang, dengan selisih yang lebar, membutuhkan 67% waktu modulo, adalah pendekatan atau (|) , dan tidak ditemukan di mana pun di halaman ini.
Untuk 300 juta loop, timing benchmark adalah sebagai berikut.
3.962 | dan pendekatan topeng
4.851 pendekatan &
5.850 pendekatan%
Untuk orang-orang yang berpikir teori, atau daftar bahasa majelis, menyelesaikan argumen seperti ini, ini harus menjadi kisah peringatan. Ada lebih banyak hal di surga dan bumi, Horatio, daripada yang diimpikan dalam filosofi Anda.
sumber
unsigned x
sebagaimanax = x >> 1;
implementasi-didefinisikan perilaku saatx < 0
. Belum jelas alasanx
danOrMask
jenisnya berbeda. Cukup sederhana untuk menulis ulang menggunakanwhile(x)
tes.% 2
kasing menggunakan bitwise&
. Saya baru saja menguji ini dan hasilnya benar-benar sama (VS2015, Rilis dibangun dengan semua optimisasi, baik x86 dan x64). Jawaban yang diterima juga menyatakan ini untuk GCC (ditulis pada 2008).or
akan lebih cepat daripadaand
sangat tidak mungkin, pada platform / kompiler. Bahkan jika ada kombinasi platform / kompiler yang aneh (dan Anda belum mempostingnya atau kode yang digunakan untuk melakukan benchmark), tergantung pada kompiler lain untuk berperilaku yang sama akan menjadi taruhan optimasi yang buruk. Jadi, ketika saya menulis, saya bertanya-tanya di platform / kompiler mana ini diuji , karena saya hampir yakin itu tidak diukur dengan benar.Ini adalah tindak lanjut dari diskusi dengan @RocketRoy mengenai jawabannya , tetapi mungkin bermanfaat bagi siapa saja yang ingin membandingkan hasil ini.
tl; dr Dari apa yang saya lihat, pendekatan Roy (
(0xFFFFFFFF == (x | 0xFFFFFFFE)
) tidak sepenuhnya dioptimalkanx & 1
sebagaimod
pendekatan, tetapi dalam praktiknya waktu berjalan seharusnya menjadi sama dalam semua kasus.Jadi, pertama saya membandingkan output yang dikompilasi menggunakan Compiler Explorer :
Fungsi yang diuji:
Klik 3.9.0 dengan -O3:
GCC 6.2 dengan -O3:
Angkat ke CLang, itu menyadari bahwa ketiga kasus secara fungsional sama. Namun, pendekatan Roy tidak dioptimalkan dalam GCC, begitu YMMV.
Ini mirip dengan Visual Studio; memeriksa Rilis pembongkaran x64 (VS2015) untuk tiga fungsi ini, saya bisa melihat bahwa bagian perbandingannya sama untuk case "mod" dan "dan", dan sedikit lebih besar untuk case Roy "atau":
Namun, setelah menjalankan tolok ukur yang sebenarnya untuk membandingkan tiga opsi ini (mod sederhana, bitwise atau, bitwise dan), hasilnya benar-benar sama (sekali lagi, Visual Studio 2005 x86 / x64, rilis Rilis, tidak ada debugger terpasang).
Majelis rilis menggunakan
test
instruksi untukand
danmod
kasus, sedangkan kasus Roy menggunakancmp eax,0FFFFFFFFh
pendekatan, tetapi sangat terbuka dan dioptimalkan sehingga tidak ada perbedaan dalam prakteknya.Hasil saya setelah 20 berjalan (i7 3610QM, rencana daya Windows 10 diatur ke Kinerja Tinggi):
Perbedaan antara opsi-opsi ini kurang dari 0,3%, jadi agak jelas rakitannya sama dalam semua kasus.
Berikut adalah kode jika ada yang ingin mencoba, dengan peringatan bahwa saya hanya mengujinya pada Windows (periksa
#if LINUX
persyaratan untukget_time
definisi dan menerapkannya jika perlu, diambil dari jawaban ini ).sumber
Saya tahu ini hanya gula sintaksis dan hanya berlaku di .net tetapi bagaimana dengan metode ekstensi ...
Sekarang Anda dapat melakukan hal berikut
sumber
Dalam "kategori kreatif tapi membingungkan" saya menawarkan:
Varian pada tema ini yang khusus untuk Microsoft C ++:
sumber
Metode bitwise tergantung pada representasi bagian dalam bilangan bulat. Modulo akan bekerja di mana saja ada operator modulo. Sebagai contoh, beberapa sistem benar-benar menggunakan bit level rendah untuk penandaan (seperti bahasa dinamis), sehingga x & 1 mentah tidak akan benar-benar berfungsi dalam kasus itu.
sumber
IsOdd (int x) {return true; }
Bukti kebenaran - pertimbangkan himpunan semua bilangan bulat positif dan anggap ada satu set bilangan bulat yang tidak kosong yang tidak aneh. Karena bilangan bulat positif disusun dengan baik, akan ada bilangan terkecil bukan bilangan ganjil, yang dengan sendirinya cukup aneh, sehingga jelas bilangan itu tidak dapat diatur. Karenanya set ini tidak boleh kosong. Ulangi untuk bilangan bulat negatif kecuali mencari bilangan terbesar bukan ganjil.
sumber
Portabel:
Tidak dapat diangkut:
sumber
Seperti yang telah diposting beberapa orang, ada banyak cara untuk melakukan ini. Menurut situs web ini , cara tercepat adalah operator modulus:
Namun, berikut adalah beberapa kode lain yang ditandai oleh penulis yang berjalan lebih lambat daripada operasi modulus umum di atas:
Berapa banyak orang yang tahu tentang metode Math.System.DivRem atau mengapa mereka menggunakannya ??
sumber
selesai
sumber
Untuk memberikan elaborasi lebih lanjut tentang metode operator bitwise bagi kita yang tidak melakukan banyak aljabar boolean selama studi kami, berikut adalah penjelasannya. Mungkin tidak banyak berguna untuk OP, tapi saya ingin menjelaskan mengapa NUMBER & 1 berfungsi.
Harap perhatikan seperti ketika seseorang menjawab di atas, cara angka negatif ditampilkan dapat menghentikan metode ini berfungsi. Bahkan ia dapat merusak metode operator modulo juga karena masing-masing bahasa dapat berbeda dalam bagaimana berurusan dengan operan negatif.
Namun jika Anda tahu bahwa NUMBER akan selalu positif, ini berfungsi dengan baik.
Seperti Tooony di atas menyatakan bahwa hanya digit terakhir dalam biner (dan denary) yang penting.
Logika AND gerbang boolean menentukan bahwa kedua input harus berupa 1 (atau tegangan tinggi) agar 1 dikembalikan.
1 & 0 = 0.
0 & 1 = 0.
0 & 0 = 0.
1 & 1 = 1.
Jika Anda mewakili angka apa pun sebagai biner (saya telah menggunakan representasi 8 bit di sini), angka ganjil memiliki 1 di akhir, bahkan angka memiliki 0.
Sebagai contoh:
1 = 00000001
2 = 00000010
3 = 00000011
4 = 00000100
Jika Anda mengambil nomor apa pun dan menggunakan bitwise AND (& dalam java) dengan 1 maka akan mengembalikan 00000001, = 1 yang berarti angkanya ganjil. Atau 00000000 = 0, artinya angkanya genap.
Misalnya
Aneh?
1 & 1 =
00000001 &
00000001 =
00000001 <- Ganjil
2 & 1 =
00000010 &
00000001 =
00000000 <- Merata
54 & 1 =
00000001 &
00110110 =
00000000 <- Merata
Inilah mengapa ini bekerja:
Maaf jika ini berlebihan.
sumber
Angka nol paritas | nol http://tinyurl.com/oexhr3k
Urutan kode python.
sumber
sumber
Demi diskusi ...
Anda hanya perlu melihat angka terakhir di nomor mana saja untuk melihat apakah angka itu genap atau ganjil. Ditandatangani, tidak ditandatangani, positif, negatif - semuanya sama dalam hal ini. Jadi ini harus bekerja sepanjang: -
Kuncinya di sini adalah di baris ketiga kode, operator divisi melakukan divisi integer, sehingga hasilnya hilang bagian fraksi dari hasil. Jadi misalnya 222/10 akan memberikan 22 hasilnya. Kemudian kalikan lagi dengan 10 dan Anda memiliki 220. Kurangi itu dari yang asli 222 dan Anda berakhir dengan 2, yang dengan sihir adalah angka yang sama dengan angka terakhir di angka asli. ;-) Tanda kurung ada di sana untuk mengingatkan kita tentang urutan perhitungan yang dilakukan. Pertama lakukan pembagian dan perkaliannya, kemudian kurangi hasilnya dari angka aslinya. Kita dapat mengabaikannya, karena prioritas lebih tinggi untuk pembagian dan penggandaan daripada pengurangan, tetapi ini memberi kita kode "lebih mudah dibaca".
Kita bisa membuat semuanya benar-benar tidak dapat dibaca jika kita mau. Tidak ada bedanya untuk kompiler modern: -
Tapi itu akan membuat kode lebih sulit untuk dipertahankan di masa depan. Bayangkan saja Anda ingin mengubah teks untuk angka ganjil menjadi "tidak genap". Kemudian orang lain di kemudian hari ingin mengetahui perubahan apa yang Anda buat dan melakukan svn diff atau yang serupa ...
Jika Anda tidak khawatir tentang portabilitas tetapi lebih banyak tentang kecepatan, Anda bisa melihat sedikit yang paling signifikan. Jika bit itu diatur ke 1 itu adalah angka ganjil, jika itu 0 itu adalah angka genap. Pada sistem endian kecil, seperti arsitektur x86 Intel akan menjadi seperti ini: -
sumber
Jika Anda ingin menjadi efisien, gunakan operator bitwise (
x & 1
), tetapi jika Anda ingin dibaca, gunakan modulo 2 (x % 2
)sumber
%
. Jika Anda ingin dapat dibaca, gunakan%
. Hmmm, saya melihat polanya di sini.Memeriksa genap atau ganjil adalah tugas sederhana.
Kami hanya perlu memeriksa pembagian nomor apa pun dan untuk memeriksa pembagian, kami menggunakan
%
operatorMemeriksa bahkan aneh menggunakan jika lain
Program C untuk memeriksa genap atau ganjil menggunakan jika lain
Menggunakan operator Conditional / Ternary
Program C untuk memeriksa genap atau ganjil menggunakan operator kondisional .
Menggunakan operator Bitwise
sumber
+ 66% lebih cepat>
!(i%2) / i%2 == 0
Kode memeriksa bit terakhir dari integer jika 1 dalam Binary
Penjelasan
yang & bitwise operator AND cek bit paling kanan di kami kembali baris jika itu 1
Anggap itu benar & salah
Ketika kita membandingkan n dengan 1 yang berarti
0001
dalam biner (jumlah nol tidak masalah).maka mari kita bayangkan saja kita memiliki bilangan bulat n dengan ukuran 1 byte.
Itu akan diwakili oleh 8-bit / 8-binary digit.
Jika int n adalah 7 dan kami membandingkannya dengan 1 , Ini seperti
Yang F adalah false dan T untuk true.
Bagaimana jika saya ingin memeriksa bit sebelum yang paling kanan?
Hanya mengubah
n & 1
ken & 2
yang 2 mewakili0010
di Binary dan sebagainya.Saya sarankan menggunakan notasi heksadesimal jika Anda seorang pemula untuk operasi bitwise
return n & 1;
>>return n & 0x01;
.sumber