Nol sebagai konstanta?

15

Saya menemukan idiom pemrograman ini baru-baru ini:

const float Zero = 0.0;

yang kemudian digunakan dalam perbandingan:

if (x > Zero) {..}

Adakah yang bisa menjelaskan apakah ini benar-benar lebih efisien atau dapat dibaca atau dipelihara daripada:

if (x > 0.0) {..}

CATATAN: Saya dapat memikirkan alasan lain untuk mendefinisikan konstanta ini, saya hanya ingin tahu tentang penggunaannya dalam konteks ini .

NWS
sumber
31
Para pengembang berencana untuk porting kode ke alam semesta di mana hukum matematika berbeda?
vaughandroid
6
Tapi sungguh, aku tidak bisa memikirkan satu pun alasan bagus untuk ini. Satu-satunya penjelasan yang dapat saya kemukakan adalah standar pengkodean yang terlalu bersemangat, atau beberapa dev yang pernah mendengar "angka ajaib itu buruk" tetapi tidak mengerti mengapa (atau apa yang membentuk angka ajaib) ...
vaughandroid
@ Baqueta - Sebuah semesta alternatif? Saya pikir mereka sudah tinggal di sana! Adapun angka ajaib, saya setuju, namun saya menggunakan aturan praktis bahwa Semuanya Kecuali 0 & 1 harus dibuat konstan.
NWS
1
Jika xmemiliki tipe float, maka x > 0.0paksakan promosi double, yang mungkin kurang efisien. Itu bukan alasan yang baik untuk menggunakan konstanta bernama, hanya untuk memastikan konstanta Anda memiliki tipe yang benar (misalnya 0f, float(0)atau decltype(x)(0)).
Mike Seymour
1
@ JoSo: untuk bersikap adil, jenis 13.37tidak float, itu double. Jadi, jika Anda menginginkannya floatmaka mungkin saja tutor Anda benar. Dalam beberapa konteks (mis. Penugasan ke float) 13.37akan secara implisit dikonversi ke floatyang Anda inginkan, dan dalam konteks lain (mis. Pengurangan tipe templat) tidak akan, sedangkan yang static const floatselalu dimulai sebagai jenis yang Anda inginkan. Oleh karena itu, lebih aman. Pikiran Anda, jadi akan 13.37f! Namun, ada alasan lain untuk menghindari makro selain "keamanan jenis", jadi kemungkinan besar tutor memberi Anda argumen yang buruk.
Steve Jessop

Jawaban:

29

Kemungkinan alasannya adalah jenis caching, penamaan atau pemaksaan

Caching (tidak berlaku)

Anda ingin menghindari biaya membuat objek selama tindakan perbandingan. Di Jawa contohnya adalah

BigDecimal zero = new BigDecimal ("0.0");

ini melibatkan proses pembuatan yang cukup berat dan lebih baik dilayani menggunakan metode statis yang disediakan:

BigDecimal zero = BigDecimal.ZERO;

Ini memungkinkan perbandingan tanpa menimbulkan biaya pembuatan berulang karena BigDecimal sudah di-cache oleh JVM selama inisialisasi.

Dalam hal apa yang telah Anda gambarkan, primitif melakukan pekerjaan yang sama. Ini sebagian besar berlebihan dalam hal caching dan kinerja.

Penamaan (tidak mungkin)

Pengembang asli berupaya memberikan konvensi penamaan yang seragam untuk nilai-nilai umum di seluruh sistem. Ini memiliki beberapa kelebihan, terutama dengan nilai-nilai yang tidak biasa tetapi sesuatu yang mendasar seperti nol hanya sepadan dengan kasus caching sebelumnya.

Jenis pemaksaan (kemungkinan besar)

Pengembang asli berupaya untuk memaksa tipe primitif tertentu untuk memastikan bahwa perbandingan dilakukan pada tipe yang benar dan mungkin ke skala tertentu (jumlah tempat desimal). Ini OK, tetapi nama sederhana "nol" mungkin tidak cukup detail untuk kasus penggunaan ini dengan ZERO_1DP sebagai ekspresi maksud yang lebih tepat.

Gary Rowe
sumber
2
+1 untuk tipe pemaksaan. Saya akan menambahkan bahwa dalam bahasa seperti C ++ yang memungkinkan operator overloading, mendefinisikan konstanta dan penggunaan typedefakan membuat tipe variabel tepat satu tempat dan memungkinkan mengubahnya tanpa harus mengubah kode.
Blrfl
3
Tipe pemaksaan kemungkinan besar bukan yang mereka coba, namun ini adalah penjelasan terbaik mengapa itu bisa dilakukan!
NWS
7
Untuk tipe pemaksaan, saya mungkin lebih suka menggunakan saja 0.0f.
Svish
Jenis pemaksaan kadang-kadang bisa berguna di vb.net, di mana melakukan operator bitwise pada byte menghasilkan hasil byte. Mengatakan byteVar1 = byteVar2 Or CB128sepertinya sedikit lebih baik daripada byteVar1 = byteVar2 Or CByte(128). Tentu saja, memiliki akhiran numerik yang tepat untuk byte akan lebih baik. Karena C # mempromosikan operan bitwise ke operator intbahkan ketika hasilnya dijamin sesuai dengan byte, masalah tidak begitu relevan di sana.
supercat
Saya tidak yakin tentang memiliki nama konstan sebagai Nol untuk '0' tetapi kadang-kadang membantu dalam keterbacaan kode; misalnya, memiliki konstanta ini untuk nol - "ROOT_TYPE_ID = 0" akan membantu menulis pernyataan seperti jika (id! = ROOT_TYPE_ID) {..}
Tech Junkie
6

Itu karena "Tooling Nagging"

Kemungkinan alasan yang tidak saya lihat tercantum di sini adalah karena banyak alat berkualitas menandai penggunaan angka ajaib . Seringkali merupakan praktik yang buruk untuk memiliki angka ajaib yang dilemparkan ke dalam algoritma tanpa membuatnya terlihat jelas untuk perubahan nanti, terutama jika mereka digandakan di beberapa tempat dalam kode.

Jadi, walaupun alat ini benar dalam menandai masalah seperti itu, mereka sering menghasilkan positif palsu untuk situasi di mana nilai-nilai ini tidak berbahaya dan kemungkinan besar bersifat statis, atau hanya menjadi nilai inisialisasi.

Dan ketika itu terjadi, kadang-kadang Anda menghadapi pilihan:

  • menandainya sebagai false positive, jika alat memungkinkan (biasanya dengan komentar yang diformat khusus, yang menjengkelkan bagi orang-orang TIDAK menggunakan alat)
  • atau mengekstraksi nilai-nilai ini ke konstanta, apakah itu penting atau tidak.

Tentang Kinerja

Tergantung pada bahasa saya kira, tetapi ini cukup umum di Jawa dan tidak memiliki dampak kinerja, karena nilai-nilai yang diuraikan pada waktu kompilasi jika mereka adalah konstanta nyata static final. Ini tidak akan berdampak pada C atau C ++ jika mereka dinyatakan sebagai konstanta atau bahkan sebagai makro pra-prosesor.

haylem
sumber
5

Ini mungkin masuk akal karena secara eksplisit didefinisikan Zerosebagai tipe float.

Setidaknya dalam C dan C ++ nilainya 0.0bertipe double, sedangkan yang setara floatadalah 0.0f. Jadi dengan asumsi xAnda membandingkan terhadap juga selalu floatmengatakan

x > 0.0

sementara benar-benar mempromosikan xuntuk doublemencocokkan jenis 0.0yang dapat menyebabkan masalah (dengan tes kesetaraan khususnya). Perbandingan tanpa konversi tentunya

x > 0.0f

yang melakukan hal yang sama seperti

float Zero = 0.0; // double 0.0 converted to float  
x > Zero

Namun demikian, saya pikir akan jauh lebih berguna untuk mengaktifkan peringatan konversi di kompiler daripada meminta pengguna menulis kode yang aneh.

Benjamin Bannier
sumber
1

Pertama-tama, di sini nol didefinisikan sebagai float, bukan int. Tentu saja, ini tidak mempengaruhi apa pun dalam perbandingan, tetapi dalam kasus lain ketika konstanta ini digunakan, itu mungkin membuat perbedaan.

Saya tidak melihat alasan lain mengapa Zerodinyatakan konstan di sini. Ini hanya beberapa gaya pengkodean, dan lebih baik untuk mengikuti gaya jika digunakan di tempat lain dalam program tertentu.

superM
sumber
1

Ini hampir pasti sama efisiennya selama eksekusi (kecuali jika kompiler Anda sangat primitif) dan sedikit kurang efisien selama kompilasi.

Mengenai apakah itu lebih mudah dibaca daripada x > 0... ingat bahwa ada orang-orang yang jujur, dengan tulus, berpikir bahwa COBOL adalah ide bagus dan kesenangan untuk bekerja dengan - dan kemudian ada orang yang berpikir persis sama tentang C. (Rumor memiliki bahwa bahkan ada beberapa programmer dengan pendapat yang sama tentang C ++!) Dengan kata lain, Anda tidak akan mendapatkan kesepakatan umum tentang hal ini, dan mungkin tidak layak diperebutkan.

Kilian Foth
sumber
0

Ini benar-benar lebih efisien atau dapat dibaca atau dipelihara daripada:

if (x > 0.0) {..}

Jika Anda menulis kode generik (yaitu non-tipe-spesifik), maka sangat mungkin. Suatu zero()fungsi dapat berlaku untuk semua jenis aljabar, atau jenis apa pun yang merupakan penambahan grup. Ini bisa berupa bilangan bulat, bisa berupa nilai titik-mengambang, bahkan bisa menjadi fungsi jika variabel Anda, katakanlah, itu sendiri adalah fungsi dalam beberapa ruang linear (mis. X adalah fungsi linear dari bentuk z -> a_x * z + b_x) dan kemudian zero()menyediakan fungsi dengan a dan b keduanya zero()dari jenis yang mendasarinya.

Jadi Anda akan mengharapkan kode seperti itu, katakanlah, C ++ mungkin (meskipun zero()AFAIK tidak terlalu umum), atau di Julia, dan mungkin bahasa lain.

einpoklum
sumber