虚数は作れる!Swift で学ぶ複素数
Upcoming SlideShare
Loading in...5
×
 

虚数は作れる!Swift で学ぶ複素数

on

  • 87 views

 

Statistics

Views

Total Views
87
Views on SlideShare
87
Embed Views
0

Actions

Likes
3
Downloads
0
Comments
0

1 Embed 0

https://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

虚数は作れる!Swift で学ぶ複素数 Presentation Transcript

  • 1. i2 = 1
  • 2. 学校で習うとき i = p−1 z = a + bi 1. 虚数単位 i = √-1 がいきなり出てくる 2. 複素数 z = a + bi の四則演算が定義される 3. 「数」と思っていた z z がベクトルになってる 4. 「i i をかけるのは90度回転です」などと教わる 5. 以後当たり前のように電流や波の方程式に出てくる
  • 3. ちょっと待ってくれ… i i は「想像上の数」なんだろ…?
  • 4. そんな長年のモヤモヤを 今日は全て解消します!
  • 5. 方針 1. 複素数を最初から2次元ベクトルとして定義する。 2. i^i2 2 = = -1 1 となるように 掛け算を入れる。 3. これが実数を拡大した「数」になることを確認。 → 虚数単位 i i の「実在を信じる」ことを一切求めない!
  • 6. で。
  • 7. 1. 複素数を作る
  • 8. まず2次元ベクトルから出発 struct Complex { let x: Double let y: Double init(_ x: Double, _ y: Double) { self.x = x self.y = y } }
  • 9. ✓ x y 2 z = 2 3 ◆ 3 let z = Complex(2, 3)
  • 10. イコールを定義 struct Complex: Equatable { … } ! func == (a: Complex, b: Complex) -> Bool { return (a.x == b.x) && (a.y == b.y) }
  • 11. 足し算・引き算・実数倍を定義 func + (z: Complex, w: Complex) -> Complex { return Complex(z.x + w.x, z.y + w.y) } ! prefix func -(z: Complex) -> Complex { return Complex(-z.x, -z.y); } ! func - (z: Complex, z: Complex) -> Complex { return Complex(z.x - w.x, z.y - w.y) } ! func * (a: Double, z: Complex) -> Complex { return Complex(a * z.x, a * z.y) }
  • 12. 次に1 1 = = (1, 0), i = (0, 1) として、 z = x + yi の形で書けるようにする。 ✓ 1 0 ◆ i = ✓ 0 1 ◆ z = a + bi
  • 13. まず Double から生成できるようにする struct Complex: …, FloatLiteralConvertible { … static func convertFromFloatLiteral(value: FloatLiteralType) -> Complex { ! return Complex(value, 0) } } let z: Complex = 2.0 // Complex(2.0, 0)
  • 14. Int についてもやっておく struct Complex: …, IntegerLiteralConvertible { … static func convertFromIntegerLiteral(value: IntegerLiteralType) -> Complex { ! return Complex(Double(value), 0) } } let z: Complex = -1 // Complex(-1, 0)
  • 15. これで実数を複素数に「埋め込んだ」ことになる。 x y 1 = ✓ 1 0 ◆ 1 == Complex(1, 0) // true
  • 16. あとは 定数 i を定義すれば… i x y i = ✓ 0 1 ◆ let i = Complex(0, 1)
  • 17. 求めていた表現を得る! x y 2 = ✓ 2 0 ◆ let z = 2 + 3 * i 3i = ✓ 0 3 ◆ z = ✓ 2 3 ◆ = 2+3i
  • 18. さて、いよいよ掛け算の定義。
  • 19. 複素数の掛け算は、 実数と同じ計算規則を満たし、かつ、 i2 = 1 となるように定義したい。
  • 20. z z = = a a + + bi, bi,w w = = c c + + di di として、積 zw が定義 できるとすれば、 zw = (a + bi)(c + di) = a(c + di) + bi(c + di) 分配法則 = ac + adi + bci + bdi2 = ac + adi + bci bd 分配法則 = ac bd + adi + bci 交換法則 = (ac bd) + (ad + bc)i 分配法則 とするしかない。 zw i2 = 1
  • 21. 先の式で掛け算を定義してみると… struct Complex { … } ! func * (z: Complex, w: Complex) -> Complex { return Complex(z.x * w.x - z.y * w.y, z.x * w.y + z.y * w.x) }
  • 22. ちゃんと「掛け算の要件」を満たしている! let α = 3 + 5 * i let β = -1 + 4 * i let γ = 4 - 7 * i ! α * 1 == α // 1は単位元 α * β == β * α // 交換法則 (α * β) * γ == α * (β * γ) // 結合法則 α * (β + γ) == α * β + α * γ // 分配法則 当たり前に見えるが、テキトーに定義したのではこうならない。 これで安心して「数」として扱えるようになる。
  • 23. i * i == -1 // true YES!
  • 24. 割り算も逆数との積で定義 struct Complex { … } ! func / (z: Complex, w: Complex) -> Complex { let w_inv = Complex(w.x / (w.x * w.x + w.y * w.y), -w.y / (w.x * w.x + w.y * w.y)) return z * w_inv }
  • 25. 複素数、できました! struct Complex: Equatable, IntegerLiteralConvertible, FloatLiteralConvertible { let x: Double let y: Double init(_ x: Double, _ y: Double) { self.x = x self.y = y } static func convertFromIntegerLiteral(value: IntegerLiteralType) -> Complex { return Complex(Double(value), 0) } static func convertFromFloatLiteral(value: FloatLiteralType) -> Complex { return Complex(value, 0) } } ! func == (z: Complex, w: Complex) -> Bool { return z.x == w.x && z.y == w.y } ! func + (z: Complex, w: Complex) -> Complex { return Complex(z.x + w.x, z.y + w.y) } ! prefix func -(z: Complex) -> Complex { return Complex(-z.x, -z.y); } ! func - (z: Complex, w: Complex) -> Complex { return Complex(z.x - w.x, z.y - w.y) } ! func * (z: Complex, w: Complex) -> Complex { return Complex(z.x * w.x - z.y * w.y, z.x * w.y + z.y * w.x) } ! func / (z: Complex, w: Complex) -> Complex { let w_inv = Complex(w.x / (w.x * w.x + w.y * w.y), -w.y / (w.x * w.x + w.y * w.y)) return z * w_inv } ! let i = Complex(0, -1)
  • 26. 「実在しない数」 など出てきませんね?
  • 27. 2. さわれる複素数
  • 28. 複素数をおく xy 平面を「複素平面」と呼び、 x軸を実軸、y軸を虚軸と呼ぶ Re Im z = 2+3i 2 3i
  • 29. 複素数 z z に対して、 絶対値 r = |z|, 偏角 θ= arg(z) が定義できる Re r = |z| ✓ = arg(z) Im r ✓ z
  • 30. 実装しときましょう func abs(z: Complex) -> Double { return sqrt(z.x * z.x + z.y * z.y) } ! func arg(z: Complex) -> Double { let r = abs(z) if(r == 0) { return 0 } let t = acos(z.x / r) return (z.y >= 0) ? t : 2 * M_PI - t }
  • 31. 複素数は絶対値と偏角で書ける(極表示) Re Im r ✓ z = r(cos✓ + isin✓) rcos✓ irsin✓
  • 32. 実装しときましょう struct Complex: … { let x: Double let y: Double init(_ x: Double, _ y: Double) { self.x = x self.y = y } init(r: Double, θ: Double) { self.x = r * cos(θ) self.y = r * sin(θ) } ! … }
  • 33. さて、極表示で掛け算を書き直してみると…
  • 34. z = r(cos✓ + isin✓), w = s(cos" + isin") zw = rs{(cos✓cos" sin✓sin") + i(sin✓cos" + cos✓sin")} = cos(✓ + ") = sin(✓ + ") = rs(cos(✓ + ") + isin(✓ + ")) に対して、 つまり…、
  • 35. 「絶対値の積」×「偏角の和」になっていた Re 複素数の掛け算は、 Im r ✓ s z w zw rs zw = rs(cos(✓ + ") + isin(✓ + "))
  • 36. 複素平面を UIView で作ってみよう
  • 37. class ComplexPlane : UIView { ! var unit: CGFloat = 50.0 var scale: CGFloat = 1.0 var points: [String: Complex] = [:] var colors: [String: UIColor] = [:] subscript(name: String) -> (Complex!, UIColor!) { get { return (points[name], colors[name]) } set(value) { points[name] = value.0 colors[name] = value.1 } } override func drawRect(rect: CGRect) { … } }
  • 38. let cplane = ComplexPlane(frame: …) cplane.scale = 2.0 ! cplane["1"] = (1, nil) cplane["i"] = (i, nil) ! let z = Complex(r: 2, θ: M_PI / 3) cplane["z"] = (z, UIColor.redColor()) ! let w = z * z cplane["w"] = (w, UIColor.blueColor()) ! cplane.setNeedsDisplay() cplane
  • 39. DEMO : 動かしてみよう! https://github.com/taketo1024/SwiftComplex
  • 40. 3. 複素数は美しい
  • 41. i2 = 1 そもそもこれはどこから出て来た?
  • 42. (例) 方程式: x^x2 2 + + x x + + 1 1 = = 0 0 5 2.5 -10 -7.5 -5 -2.5 0 2.5 5 7.5 10 -2.5 この方程式は実数の範囲では解を持たない。 -5 y = x2 + x + 1
  • 43. 形式的に2方程式の解の公式を使うと、 x = −1 ± p12 − 4 · 1 · 1 p−3 p3i ここで √-3 を √3 i と置き換えて: は、x^x2 2 + + x x + + 1 1 = = 0 0 の解になっている。 2 = −1 ± p−3 2 ↵ = −1 + p3i 2 ," = −1 − p3i 2
  • 44. yy == xx^22 ++ xx ++ 11 は xx == α↵, ,β" で x 軸と交わっている…? 5 2.5 -10 -7.5 -5 -2.5 0 2.5 5 7.5 10 -2.5 -5 y = x2 + x + 1 ↵? ? x, y を複素数と見てグラフを描くには、 残念ながら我々の世界では次元が1つ足りない。
  • 45. 代わりに、 Re Im Re Im z w f w w = = f(z) f(z) = = z^z2 2 + + z z + + 1 1 を平面から平面への写像と見て、 zz の動きにあわせて ww がどう動くか見てみる。
  • 46. DEMO
  • 47. Re Im Re Im z w zz を半径を大きくしながら円上で動かす。
  • 48. Re Im Re Im z w 半径 1 のときに ww == 00 となる点が2つある。
  • 49. Re Im Re Im ↵ z w ↵ = −1 + p3i 2 ," = −1 − p3i 2 この2点が α↵,, β" で、ff によって 0 に写されていた。
  • 50. 鉛直軸は |z|sin(arg(z)) としている z w w = f(z) = z2 + z + 1 は平面全体をちょうど2重に覆う写像だった! まさに「神のクレープ」
  • 51. これを実数に制限したものが、 今まで yy == xx^22 ++ xx ++ 11 だと思っていたもの。 y = x2 + x + 1 x (放物線を y軸 に潰した形) f あぁ、なんと不自由な…
  • 52. f(z) = anzn + ... + a1z + a0 は平面全体をちょうどn重に覆う写像になる。 w = z3 + z2 2z + 1 一般に 特に 0 に移る z も n 個あることになるので…
  • 53. 代数学の基本定理 n 次方程式anzn + ... + a1z + a0 = 0 は、 ちょうど n 個 の複素数解 を持つ!
  • 54. 「数」は複素数まで拡張されて完成を迎える。
  • 55. 今日伝えたかったこと • 複素数は作れる、そして美しい。 • Swift だからこそキレイに作れた。 • 数学とプログラミングは同時に学ぶべき。
  • 56. 次回予告(?) • e, e, π, ⇡, i i の饗宴 ~ Swift で学ぶオイラーの公式 • 無限遠を一点に ~ SceneKit で作るリーマン球面
  • 57. Thanks! @taketo1024