Saya telah melihat programmer menggunakan formula
mid = start + (end - start) / 2
alih-alih menggunakan rumus yang lebih sederhana
mid = (start + end) / 2
untuk menemukan elemen tengah dalam array atau daftar.
Mengapa mereka menggunakan yang sebelumnya?
(start + end)
mungkin meluap, sementara(end - start)
tidak bisa.start
danend
sedang pointer.start + (end - start) / 2
juga membawa makna semantik:(end - start)
adalah panjang, jadi ini mengatakan:start + half the length
.Jawaban:
Ada tiga alasan.
Pertama-tama,
start + (end - start) / 2
berfungsi bahkan jika Anda menggunakan pointer, asalkanend - start
tidak melimpah 1 .Kedua,
start + (end - start) / 2
tidak akan meluap jikastart
danend
merupakan angka positif yang besar. Dengan operan yang ditandatangani, overflow tidak ditentukan:(Perhatikan bahwa
end - start
mungkin meluap, tetapi hanya jikastart < 0
atauend < 0
.)Atau dengan aritmatika yang tidak ditandatangani, overflow didefinisikan tetapi memberi Anda jawaban yang salah. Namun, untuk operan yang tidak ditandatangani,
start + (end - start) / 2
tidak akan pernah meluap selamaend >= start
.Akhirnya, Anda sering ingin membulatkan ke
start
elemen.Catatan kaki
1 Menurut standar C, jika hasil pengurangan pointer tidak dinyatakan sebagai a
ptrdiff_t
, maka perilaku tidak terdefinisi. Namun, dalam praktiknya, ini membutuhkan mengalokasikanchar
array menggunakan setidaknya setengah dari seluruh ruang alamat.sumber
(end - start)
dalamsigned int
case tidak terdefinisi ketika meluap.end-start
tidak akan meluap? AFAIK jika Anda mengambil negatifstart
itu harus memungkinkan untuk membuatnya meluap. Tentu, sebagian besar waktu ketika Anda menghitung rata-rata Anda tahu bahwa nilainya adalah>= 0
...end - start
tidak terdefinisi, karena ukuran objek tidak ditandai sedangkan perbedaan pointer ditandatangani. Jadiend - start
"berfungsi bahkan menggunakan pointer", asalkan Anda juga entah bagaimana menjaga ukuran array di bawah iniPTRDIFF_MAX
. Agar adil dengan standar, itu tidak banyak penghalang pada sebagian besar arsitektur karena itu setengah dari ukuran peta memori.Kita dapat mengambil contoh sederhana untuk menunjukkan fakta ini. Misalkan dalam array besar tertentu , kami mencoba menemukan titik tengah rentang
[1000, INT_MAX]
. Sekarang,INT_MAX
adalah nilai terbesar yangint
bisa disimpan oleh tipe data. Bahkan jika1
ditambahkan ke ini, nilai akhir akan menjadi negatif.Juga,
start = 1000
danend = INT_MAX
.Menggunakan rumus:
(start + end)/2
,titik tengah akan menjadi
Tapi, menggunakan rumus
(start + (end-start)/2)
,, kita mendapatkan:sumber
INT_MAX
, hasilnya tidak akan negatif, tetapi tidak ditentukan.INT_MAX
ke-INT_MAX
. Tapi itu kebiasaan buruk untuk mengandalkan itu.Untuk menambah apa yang sudah dikatakan orang lain, yang pertama menjelaskan artinya lebih jelas bagi mereka yang kurang berpikir matematis:
terbaca sebagai:
sedangkan:
terbaca sebagai:
Yang sepertinya tidak sejelas yang pertama, setidaknya ketika diungkapkan seperti itu.
seperti yang ditunjukkan Kos itu juga dapat membaca:
Yang lebih jelas tapi tetap tidak, setidaknya menurut saya, sejelas yang pertama.
sumber
start + (end-start) / 2 dapat menghindari kemungkinan overflow, misalnya start = 2 ^ 20 dan end = 2 ^ 30
sumber