做爲一個程序員,寫bug不是什麼丟臉的事。可是須要吃一塹長一智,不要在一樣的地方再犯錯誤就行。程序員
二分查找,做爲程序員再熟悉不過了。它是由John Mauchly在1946年第一次參加Moore School Lectures(電子計算機原理及技術課程)提出的。John本身在1986年發現他的二分查找算法中存在一個bug。算法
那麼,這究竟是個怎樣的bug呢?你們能夠先本身實現一個二分查找算法,看你會不會踩坑markdown
這裏貼一段go版本的二分查找算法ui
// 二分查找,找第一個目標數字的下標,沒有則返回-1
func binarySearch(arr []int64, target int64) int {
if len(arr) == 0 {
return -1
}
begin, end := 0, len(arr)-1
for begin <= end {
mid := (begin + end) / 2
if arr[mid] > target {
end = mid - 1
} else if arr[mid] < target {
begin = mid + 1
} else {
return mid
}
}
return -1
}
複製代碼
乍一看好像沒有問題,那問題究竟出在哪裏呢?spa
這裏涉及到計算機組成原理的知識。每一個操做系統能表示的整形位數是有限的,超過這個位數的數字計算機是表示不出來的,說到這裏,你再回頭看看呢?是否是發現了問題?操作系統
沒錯,問題就出在 mid := (begin + end) / 2
,這裏mid大小就容易超過計算機的限制。code
go語言int64最大能表示的數字是 (i<<63 - 1)orm
func main() {
i1 := 1<<63-1
i2 := 1
mid := (i1+i2) / 2
fmt.Println("i1=", i1)
fmt.Println("i2=", i2)
fmt.Println("mid=", mid)
}
結果:
i1= 9223372036854775807
i2= 1
mid= -4611686018427387904
複製代碼
既然加法不行,那就改爲減法get
func main() {
i1 := 1<<63-1
i2 := 1
mid := i2 + (i1-i2) / 2
fmt.Println("i1=", i1)
fmt.Println("i2=", i2)
fmt.Println("mid=", mid)
}
結果:
i1= 9223372036854775807
i2= 1
mid= 4611686018427387904
複製代碼
其實這不算是算法的bug,算法自己沒有問題,只是不一樣的計算機上不一樣的程序實現會產生bug。這種加法溢出的問題只要是兩個數字相加都由可能出現溢出問題,因此你們在寫程序的時候要注意,吃一塹長一智,才能不斷地提高本身string