2025年9月5日 星期五
想算數字裡有幾個 1?C++, Python3, Go, Rust 大亂鬥!
***此篇文章由 Gemini AI 產生***
哈囉,各位寫 code 的夥伴們,大家好!
今天我們來聊一個面試或刷題時偶爾會碰到,但其實也蠻有趣的小問題:「怎麼計算一個數字在二進位下有幾個 1?」
聽起來好像很學術,但別擔心,其實觀念很簡單。比方說,數字 5,寫成二進位是 `101`,那它就有兩個 1。數字 7,二進位是 `111`,就有三個 1。這在某些演算法或需要操作底層位元(bit)的場景,其實還蠻實用的。
今天我們就來看看用四種現在很夯的語言:C++, Python3, Go, 和 Rust,要怎麼解決這個問題。順便比較一下它們的寫法和「個性」有什麼不一樣。
#### C++:硬底子真功夫,效能我最強
C++ 就是那個班上最認真、對所有細節都一清二楚的學霸。要解決這個問題,C++ 提供了一個超級方便的內建函式(built-in function),不過在比較舊的 C++ 版本可能需要自己手刻。
在比較新的 C++ 標準 (C++20) 中,你可以直接用 `` 這個函式庫:
```cpp
#include
#include
int main() {
int num = 77; // 77 的二進位是 1001101
// std::popcount 會直接幫你數好有幾個 1
int count = std::popcount(static_cast<unsigned int>(num));
std::cout << "數字 " << num << " 裡有 " << count << " 個 1!" << std::endl;
// 輸出: 數字 77 裡有 4 個 1!
return 0;
}
```
**重點分析:**
* **`std::popcount`**: 這名字超直白,「pop」在這裡指的是 "population"(總數),所以 `popcount` 就是「計算總數」。這是編譯器等級的優化,速度快到飛起來。
* **`static_cast<unsigned int>`**: 這是在做「型別轉換」。因為 `popcount` 通常是針對無號整數 (unsigned) 操作的,所以我們先把 `num` 轉成無號整數,避免一些奇怪的問題。
C++ 的寫法就是這麼樸實無華且枯燥,但效能絕對是頂尖的!
#### Python3:人生苦短,我用 Python
Python 就是那個朋友群裡最會聊天的萬人迷,語法親切又好懂。解決這個問題,方法多到你可以自己選。
最直覺的方法,就是直接把它變成二進位字串,然後數裡面有幾個 '1'。
```python
num = 77 # 77 的二進位是 1001101
# bin(num) 會回傳 '0b1001101'
# 我們用 .count('1') 來數 '1' 的數量
count = bin(num).count('1')
print(f"數字 {num} 裡有 {count} 個 1!")
# 輸出: 數字 77 裡有 4 個 1!
```
如果你是 Python 3.10 以上的版本,還可以用一個更潮的寫法:
```python
num = 77
count = num.bit_count() # 直接呼叫!
print(f"數字 {num} 裡有 {count} 個 1!")
# 輸出: 數字 77 裡有 4 個 1!
```
**重點分析:**
* **`bin()`**: Python 的內建函式,可以馬上把數字轉成 `0b` 開頭的二進位字串,超方便。
* **`.count('1')`**: 字串的 method,用來計算某個字元出現的次數。
* **`.bit_count()`**: 在新版 Python 中,整數自己就有這個 method,寫起來更乾淨,而且底層的效能也很好。
Python 的寫法就是這麼優雅,幾行就搞定,可讀性超高。
#### Go:簡單、可靠,Google 親兒子
Go 語言給人的感覺,就像是個務實的工程師,不喜歡花俏的東西,但該有的都有,而且跑起來穩定又快速。
Go 在標準函式庫 `math/bits` 裡面,也直接提供了需要的功能。
```go
package main
import (
"fmt"
"math/bits"
)
func main() {
var num uint = 77 // 77 的二進位是 1001101
// Go 推薦使用無號整數 (uint) 來做位元運算
count := bits.OnesCount(num)
fmt.Printf("數字 %d 裡有 %d 個 1!\n", num, count)
// 輸出: 數字 77 裡有 4 個 1!
}
```
**重點分析:**
* **`import "math/bits"`**: Go 把跟位元操作相關的功能都整理在這個 package 裡,分工很清楚。
* **`bits.OnesCount()`**: 函式名稱也是簡單明瞭,就是「計算 1 的數量」。
* **`var num uint = 77`**: Go 是一個強型別語言,它會建議你,在做位元運算時,最好一開始就宣告成無號整數 (`uint`),這樣語意更明確。
Go 的風格就是這樣,清楚、直接,而且效能也很棒。
#### Rust:安全、並行,程式界的超級英雄
Rust 是這幾年超級紅的語言,主打的就是「安全」跟「極致效能」。它給人的感覺有點像 C++ 的進化版,嚴格但能讓你寫出非常可靠的程式碼。
Rust 在整數型別上,也直接內建了計算 1 數量的方法。
```rust
fn main() {
let num = 77_i32; // 77 的二進位是 1001101
// _i32 是告訴編譯器,這是一個 32 位元的整數
// 直接在數字後面呼叫 .count_ones()
let count = num.count_ones();
println!("數字 {} 裡有 {} 個 1!", num, count);
// 輸出: 數字 77 裡有 4 個 1!
}
```
**重點分析:**
* **`_i32`**: 這是 Rust 的語法糖,用來標明數字的型別,`i32` 代表 32 位元有號整數。Rust 對型別非常嚴格,所以寫清楚是好習慣。
* **`.count_ones()`**: Rust 把這個功能直接做成整數型別的一個 method,只要是數字,後面加上 `.count_ones()` 就能用,非常直覺。
Rust 的寫法兼具了 C++ 的效能和 Python 的簡潔,而且還有編譯器這個超級保母在後面幫你檢查,讓你寫 code 超有安全感。
-----
### 總結一下
| 語言 | 主要寫法 | 風格特色 |
| --- | --- | --- |
| **C++** | `std::popcount(num)` | 效能至上,語法較嚴謹 |
| **Python3** | `bin(num).count('1')` 或 `num.bit_count()` | 語法甜美,可讀性高,快速開發 |
| **Go** | `bits.OnesCount(num)` | 務實可靠,標準庫功能齊全 |
| **Rust** | `num.count_ones()` | 安全第一,語法現代且效能強悍 |
今天這個小問題,其實四種語言都有非常簡單、高效的解法。從這些小地方,我們也可以稍微窺探出不同程式語言在設計哲學上的差異。
沒有最好的語言,只有最適合的工具。希望這篇簡單的比較,能幫助大家對這幾種語言有更具體的認識。下次不管你用哪種語言,碰到要數 1 的時候,就知道該怎麼做了吧!
Happy coding!
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言