Go | 初步了解「複數」型別
💬 簡介
複數型別(Complex Types)是一種特殊的數值型別,主複數是一種由實數部分和虛數部分組成的數字,通常以 a + bi
的形式表示。在 Go 語言中,內建了對複數型別的支持,提供了 complex64
和 complex128
兩種型別。
本篇文章將介紹 Go 語言中複數型別的基本特性、操作方式及應用場景,幫助在數學運算、科學計算及其他需要複數的場景中得心應手地使用。
圖片來源:Gophers(地鼠造型的原創者為 Renee French)
🔎 Go 語言中的複數型別
提供了兩種複數型別,分別為 complex64
和 complex128
。它們的區別在於表示實數部分和虛數部分所使用的精度不同。
1️⃣ complex64 與 complex128 比較
complex64
:實數部分和虛數部分均使用float32
表示。complex128
:實數部分和虛數部分均使用float64
表示,精度較高。
2️⃣ 宣告與初始化
Go 使用 complex
函式來創建複數,也可以直接使用字面值表示。
- 範例:複數的宣告與初始化
1
2
3
4
5
6
7
8
9
10
11package main
import "fmt"
func main() {
var c1 complex64 = 1 + 2i
c2 := complex(3.5, -4.5)
fmt.Println("複數 c1:", c1) // 輸出:1+2i
fmt.Println("複數 c2:", c2) // 輸出:3.5-4.5i
}📝在這個範例中,
c1
是使用字面值宣告的複數,c2
則是使用complex
函式創建的複數。
➕ 複數的基本操作
對複數進行加法、減法、乘法、除法等運算,並提供了標準庫函式來操作複數的實數部分與虛數部分。
1️⃣ 基本運算
- 範例:複數的運算
1
2
3
4
5
6
7
8
9
10
11
12
13package main
import "fmt"
func main() {
c1 := complex(1, 2)
c2 := complex(3, -4)
fmt.Println("加法:", c1+c2) // 輸出:4-2i
fmt.Println("減法:", c1-c2) // 輸出:-2+6i
fmt.Println("乘法:", c1*c2) // 輸出:11+2i
fmt.Println("除法:", c1/c2) // 輸出:約 -0.2+0.4i
}📝在這個範例中,我們進行了複數的加減乘除運算,並輸出結果。
2️⃣ 提取實數與虛數部分
提供了 real
和 imag
函式來分別提取複數的實數部分與虛數部分。
- 範例:提取實數與虛數部分
1
2
3
4
5
6
7
8
9
10package main
import "fmt"
func main() {
c := complex(5, -7)
fmt.Println("實數部分:", real(c)) // 輸出:5
fmt.Println("虛數部分:", imag(c)) // 輸出:-7
}📝在這個範例中,
real
函式返回複數的實數部分,imag
函式返回虛數部分。
⚠️ 注意事項
1️⃣ 複數運算的結果
在進行複數運算時,需要注意其結果會依照運算的性質而有所不同,並且可能會涉及到四則運算中的誤差。
例如,複數的除法可能會帶來精度上的問題,這需要特別注意。
- 範例:複數除法的精度問題
1
2
3
4
5
6
7
8
9
10
11
12package main
import "fmt"
func main() {
c1 := complex(3, 4)
c2 := complex(1, 1)
// 複數除法
quot := c1 / c2
fmt.Println("複數除法結果:", quot) // 輸出:3.5+0.5i
}📝在複數除法的運算中,我們可能會遇到精度損失的情況,這類問題在數值計算中比較常見,特別是在進行大量運算時。
2️⃣ 使用複數型別時的建議
由於複數的運算在某些情況下可能會引起浮點數精度的問題,因此在使用複數型別時,建議使用精度更高的浮點數型別(如 complex128
)來儘量減少這些誤差。
🌍 應用場景
複數型別在許多科學、工程及數學領域中都有廣泛的應用,特別是在需要處理涉及波動、旋轉、電壓與電流等現象的情況下。以下是一些典型的應用領域:
⚡ 電路分析與信號處理
在電子學中,複數被用來描述交流電的相位與幅度。例如,交流電的電壓和電流經常使用複數來表示,因為它們涉及到正弦波的相位和頻率。複數使得這些問題的運算變得簡單且直觀。
- 範例:複數在電路分析中的應用
1
2
3
4
5
6
7
8
9
10
11
12
13package main
import "fmt"
func main() {
// 假設有一個電壓 V = 10 + 5i 和電流 I = 3 + 4i
V := complex(10, 5) // 複數電壓
I := complex(3, 4) // 複數電流
// 計算阻抗 Z = V / I
Z := V / I
fmt.Println("電路的阻抗 Z:", Z) // 輸出:(2-1i)
}📝在這個範例中,我們使用複數表示電壓和電流,然後計算阻抗。這使得交流電的分析變得更加簡便。
🌀 波動與旋轉運算
複數在物理學中也有重要的應用,特別是在描述波動現象時。波動的運動可以使用複數來簡化,並且利用複數表示波的幅度和相位關係。
例如,物理學中描述光波、聲波等波動現象時,經常會將波的形狀表示為複數。複數可以幫助我們更輕鬆地處理旋轉、變形等現象。
- 範例:旋轉矩陣與複數的關聯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package main
import (
"fmt"
"math"
"math/cmplx"
)
func main() {
// 旋轉 90 度的複數
c1 := complex(1, 0) // 初始複數 1 + 0i
rotation := cmplx.Exp(complex(0, math.Pi/2)) // 使用 math.Pi 旋轉 90 度
// 旋轉後的複數
rotated := c1 * rotation
// 處理誤差,將非常接近 0 的實部視為 0
if math.Abs(real(rotated)) < 1e-15 {
rotated = complex(0, imag(rotated))
}
fmt.Println("旋轉後的複數:", rotated) // 輸出: (0+1i)
}📝這個範例使用複數來表示旋轉,通過旋轉矩陣將一個數字從初始位置旋轉 90 度,並簡單地得到結果
(0 + 1i)
。
🖥️ 圖像處理與電腦視覺
複數也在圖像處理中發揮重要作用,特別是在頻域處理中。透過將圖像轉換到頻域(例如傅里葉變換),我們可以利用複數進行圖像的濾波、降噪等操作。
- 範例:圖像處理中的傅里葉變換
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package main
import (
"fmt"
"math/cmplx"
)
func main() {
// 假設圖像的頻域資料為複數
freqData := []complex128{
complex(10, 5), // 頻域資料點
complex(3, 2),
complex(7, 1),
}
// 輸出每個頻域資料的模和相位
for _, freq := range freqData {
fmt.Println("模:", cmplx.Abs(freq), " 相位:", cmplx.Phase(freq))
}
}📝在這個範例中,我們模擬了圖像的頻域資料,並使用複數計算其模和相位,這在傅里葉變換中是非常重要的。
🎶 音頻處理與數字信號處理
在音頻處理中,複數同樣扮演著關鍵角色,尤其是在數字信號處理(DSP)中。通過使用複數,音頻信號的頻率、相位和幅度能夠更加精確地進行表示與操作。
- 範例:音頻信號的頻率分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package main
import (
"fmt"
"math/cmplx"
)
func main() {
// 假設音頻信號在頻域的表示
signal := complex(5, 3)
// 計算其頻率(模)和相位
fmt.Println("信號的幅度(頻率):", cmplx.Abs(signal))
fmt.Println("信號的相位:", cmplx.Phase(signal))
}📝這個範例展示了如何使用複數分析音頻信號的幅度與相位,這在音頻信號處理中非常常見。
🎯總結
複數型別是一個強大工具,特別適用於處理涉及實數與虛數的計算。理解複數型別的結構與運算,能幫助更高效地進行數學與科學計算,並解決許多工程問題。
通過學習 Go 中複數的應用,我們能夠在複雜的領域中解決更多問題。
最後建議回顧一下 Go | 菜鳥教學 目錄,了解其章節內容。
註:以上參考了
Go