Apakah integer digunakan terlalu banyak sebagai tipe data?

9

Apakah sebagian besar pengembang aplikasi menggunakan bilangan bulat yang ditandatangani di tempat-tempat di mana mereka benar-benar bermaksud menggunakan bilangan bulat yang tidak ditandatangani? Saya melakukannya sepanjang waktu, begitu juga rekan kerja saya. Saya belum melihat banyak basis kode luas lainnya (selain Delphi VCL) dan contoh di internet biasanya menggunakan integer. Sedangkan pengembang VCL menggunakan tipe data mereka sendiri (yang akan menjadi cara yang paling tidak malas untuk mendeklarasikan variabel).

Sesuatu sepertinya sedikit mengerikan tentang kode seperti ini

TStuffRec = record
   recordID : Integer;
   thingID : Integer;
   otherThingID : Integer;
end;

ketika itu bisa ditulis sebagai

TStuffRec = record
   recordID : Cardinal;
   thingID : Cardinal;
   otherThingID : Cardinal;
end;

Secara fungsional, catatan ini hampir selalu berfungsi sama (dan mudah-mudahan akan terus bekerja sama bahkan dalam Delphi 64-bit). Tetapi jumlah yang sangat besar akan memiliki masalah konversi.

Tapi ada juga kelemahan menggunakan int unsigned. Terutama berasal dari betapa menyebalkannya mencampur keduanya.

Pertanyaan sebenarnya adalah, apakah ini hal yang benar-benar dipikirkan atau dimasukkan dalam praktik terbaik? Apakah biasanya hanya tergantung pengembang?

Peter Turner
sumber
5
Peter, apakah Anda mencari jawaban khusus Delphi saja?
Adam Lear
3
@Anna Memahami bagaimana datatypes Delphi bekerja akan membuat jawaban yang paling baik. Saya cukup yakin bahwa programmer C dapat memahami dan menjawab pertanyaan ini.
Peter Turner

Jawaban:

9

Salah satu alasan mengapa saya tidak menggunakan tipe integer yang tidak ditandai terlalu banyak di Delphi adalah bahwa mereka dapat membuat masalah ketika dicampur dengan integer yang ditandatangani. Inilah yang menggigit saya sekali:

for i := 0 to List.Count - 1 do
  //do something here

Saya telah imenyatakan sebagai bilangan bulat yang tidak ditandatangani, (setelah semua, ini adalah indeks ke dalam daftar yang dimulai dari 0, tidak pernah harus negatif, kan?), Tetapi ketika List.Count0, itu tidak akan hubungan pendek loop seperti yang diharapkan karena 0 - 1mengevaluasi ke angka positif yang sangat tinggi. Ups!

Antara potensi masalah keselamatan yang melekat dalam pencampuran bilangan bulat bertanda tangan dan tidak bertanda, dan masalah jangkauan, (jika Anda akan membutuhkan bilangan positif lebih besar dari high(signed whatever), kemungkinan besar Anda juga akan membutuhkan bilangan positif lebih besar dari high(unsigned whatever)itu, jadi bergeraklah hingga ukuran yang lebih besar berikutnya alih-alih beralih dari ditandatangani menjadi unsigned dengan ukuran yang sama biasanya merupakan tindakan yang benar,) Saya benar-benar belum menemukan terlalu banyak kegunaan untuk integer unsigned ketika mewakili sebagian besar data.

Mason Wheeler
sumber
2
Agak terkait, salah satu risiko utama menggunakan tipe data yang berpotensi lebih kecil dari yang diperlukan (dibandingkan dengan yang tidak ditandatangani vs ditandatangani) adalah bahwa jika kondisi keluar lebih besar dari yang Anda rencanakan, Anda sebenarnya dapat berakhir dengan loop tak terbatas karena konter meluap berulang kali. Kedengarannya bodoh di belakang, tapi saya pernah menulis sebuah program yang seharusnya mengulang setiap nilai byte yang mungkin, dan butuh sekitar 15 menit untuk akhirnya meyakinkan diri sendiri bahwa itu tidak mungkin dilakukan dengan penghitung byte.
Aaronaught
@Aaronaught: Tidak dalam Delphi. (Setidaknya tidak kecuali Anda melakukan sesuatu yang bodoh seperti menonaktifkan pemeriksaan bawaan meluap.) Anda akan berakhir dengan pengecualian ketika penghitung meluap, alih-alih loop yang tak terbatas. Ini masih bug, tetapi jauh lebih mudah untuk dilacak.
Mason Wheeler
Jika Anda berkata begitu. Saya selalu menonaktifkan pemeriksaan overflow di Delphi; setelah terus-menerus dibombardir dengan positif palsu dari hal-hal seperti kode hash dan checksum, saya hanya menyerah pada "fitur" itu sepenuhnya. Tapi saya kira Anda benar, itu akan menangkap kesalahan spesifik itu.
Aaronaught
@Aaronaught: Ya, Anda ingin menonaktifkannya untuk hal-hal seperti kode hash dan checksum yang dirancang khusus untuk meluap dan membungkus. Tetapi untuk perhitungan tujuan umum yang tidak dirancang untuk meluap dan membungkus, itu adalah fitur keselamatan yang penting dan mematikannya seperti mengemudi tanpa sabuk pengaman.
Mason Wheeler
Mungkin Anda sudah lupa, tetapi arahan memeriksa melimpah dan kompiler sangat buggy di versi Delphi yang lebih lama. Saya ingat dengan jelas merobek rambut saya pada beberapa kesempatan setelah melihat debugger berhenti tepat di tengah-tengah blok {$ O -} / {$ O +} untuk dengan senang hati melaporkan melimpah. Setelah beberapa saat saya tidak tahan lagi dan hanya menonaktifkannya secara global. Sekali lagi, ya, itu akan menangkap masalah ini, tapi saya masih tidak berpikir itu sepadan dengan jumlah positif palsu. Untuk masing-masing miliknya, tentu saja!
Aaronaught
3

Sejujurnya saya cenderung menggunakan Integer berdasarkan kebiasaan. Saya terbiasa bahwa mereka menawarkan rentang yang cukup besar untuk sebagian besar situasi dan memungkinkan nilai negatif (seperti -1). Memang, banyak kali menggunakan bytes / word / shortint akan lebih tepat. Sekarang memikirkannya, saya bisa fokus pada titik-titik ini:

  • Perspektif. Ukuran Tilemap terbatas pada 192x192 ubin, jadi saya bisa menggunakan byte untuk menangani ubin dan loop. Tetapi jika ukuran peta harus ditingkatkan, saya harus melalui setiap penggunaan dan menggantinya dengan kata misalnya. Ketika saya perlu mengizinkan objek off-peta saya harus pergi lagi untuk mengubah ke smallint.

  • Loop. Seringkali saya menulis loop "dari i: = 0 ke Count-1", apa yang terjadi jika "i" adalah byte dan Count = 0 adalah loop berjalan dari 0 hingga 255. Bukannya saya menginginkannya.

  • Seragam. Lebih mudah untuk mengingat dan menerapkan "var i: integer;" daripada berhenti di setiap kasus dan berpikir "Hm .. di sini kita berurusan dengan kisaran 0..120 .. byte .. tidak, tunggu, kita mungkin perlu -1 untuk tidak diinisialisasi .. shortint .. tunggu .. bagaimana jika 128 adalah tidak cukup .. Arrgh! " atau "Mengapa kecil di tempat ini, bukan jalan pendek?"

  • Menggabungkan. Ketika saya perlu menggabungkan dua atau lebih kelas bersama-sama mereka mungkin menggunakan tipe data yang berbeda untuk tujuan mereka, menggunakan tipe yang lebih luas memungkinkan untuk melewati konversi yang tidak perlu.

  • -1. Bahkan ketika nilai berada pada kisaran 0..n-1 saya sering perlu menetapkan nilai "tidak ada nilai / tidak diketahui / tidak diinisialisasi / kosong", yang merupakan praktik umum -1.

Menggunakan Integer memungkinkan untuk melewati semua masalah ini, lupakan optimasi tingkat rendah di mana tidak diperlukan, naik ke level yang lebih tinggi dan fokus pada masalah yang lebih nyata.

PS Kapan saya menggunakan tipe lain?

  • Counters, mereka tidak pernah negatif dan hanya baca di luar kelas mereka.
  • Alasan Kinerja / Memori, memaksa untuk menggunakan tipe data yang lebih pendek di tempat-tempat tertentu.
Kromster
sumber
1

Praktik terbaik adalah menggunakan tipe data yang sesuai dengan kebutuhan untuk data yang digunakan (data yang diharapkan).

Contoh C #: Jika saya hanya perlu mendukung 0 hingga 255, saya akan menggunakan byte.

Jika saya perlu mendukung 1.000.000 negatif dan positif, maka int.

Lebih besar dari 4,2 miliar, lalu gunakan yang lama.

Dengan memilih jenis yang benar, program akan menggunakan jumlah memori yang optimal serta berbagai jenis menggunakan jumlah memori yang berbeda.

Berikut ini adalah referensi C # int dari MSDN.

int 
 -2,147,483,648 to 2,147,483,647
 Signed 32-bit integer

uint 
 0 to 4,294,967,295
 Unsigned 32-bit integer

long 
 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
 Signed 64-bit integer

ulong 
 0 to 18,446,744,073,709,551,615
 Unsigned 64-bit integer
Jon Raynor
sumber
Dalam C # (atau .net secara umum) akan panjang dan ulong menjadi 128 bit pada mesin 128-bit? Karena dalam Delphi, Integerdatatype adalah 32 bit pada mesin 32-bit dan tampaknya akan 64 bit pada mesin 64-bit.
Peter Turner
1
@Peter Turner: Tidak, dalam C # inthanyalah singkatan untuk System.Int32, tidak peduli mesin apa kode berjalan.
nikie
@nikie, apakah hanya seperti type int System.Int32atau sesuatu untuk efek itu? Mungkinkah itu diubah dengan mudah di versi kerangka kerja yang akan datang?
Peter Turner
@Peter Turner / nikie (sizeof (int) .ToString ()); ==> Pengembalian 4 (sizeof (Int64) .ToString ()); ==> Mengembalikan 8 Pada OS Windows 64bit saya. Sebagai nikie, stats, int benar-benar adil dan Int32.
Jon Raynor
1
Satu hal yang perlu diperhatikan adalah bahwa tidak semua jenis sesuai dengan Spesifikasi Bahasa Umum . uintadalah salah satu dari jenis yang tidak patuh yang artinya tidak boleh digunakan dalam API terbuka untuk menghindari melanggar kemampuan untuk menggunakan API itu dalam bahasa .NET selain dari yang ditulis pustaka. Ini juga mengapa kerangka .NET API sendiri menggunakan di intmana uintakan dilakukan.
Adam Lear
1

Jenis integer yang tidak ditandai hanya boleh digunakan untuk mewakili nomor kardinal dalam bahasa yang mewakili nomor kardinal. Karena cara komputer yang menjalankan C bekerja, tipe integer yang tidak bertanda berperilaku sebagai anggota cincin aljabar mod-2 (artinya perhitungan yang meluap akan "membungkus" dapat diprediksi), dan bahasa tersebut menentukan bahwa dalam banyak kasus jenis tersebut adalah diperlukan untuk berperilaku sebagai cincin aljabar abstrak bahkan ketika perilaku seperti itu tidak konsisten dengan perilaku bilangan kardinal atau bilangan bulat matematika.

Jika sebuah platform sepenuhnya mendukung tipe terpisah untuk nomor kardinal dan cincin aljabar, maka saya menyarankan agar nomor kardinal harus diproses menggunakan tipe nomor kardinal (dan hal-hal yang perlu dibungkus menggunakan jenis cincin). Tidak hanya tipe seperti itu dapat menyimpan angka dua kali lipat dari tipe yang ditandatangani, tetapi metode yang menerima parameter dari tipe seperti itu tidak perlu memeriksa apakah itu negatif.

Namun, mengingat relatif kurangnya jenis-jenis nomor kardinal, biasanya yang terbaik adalah menggunakan bilangan bulat untuk mewakili bilangan bulat matematika dan angka-angka kardinal.

supercat
sumber