Contenu connexe
Similaire à SwiftでRiemann球面を扱う (20)
SwiftでRiemann球面を扱う
- 1. SpeeeKaigi資料
hayato_iida August 25, 2017 3:32 p.m.
PJD飯田勇人
一応iOSエンジニア
最近はrails書いたり社内業務分析みたいな仕事
新宿のVR行きたい
Swiftに複素数を実装する
Riemann球面とは
Riemann球面を実装する
演算子を新たに定義できる
既存型にprotocolを追加出来る
既存の演算子の処理を上書きする事もできる
.swift
SwiftでRiemann球面を扱う
自己紹介
導入
ちょっとした関数を計算したいときに何を使いますか?
playgroundでSwiftをさくっと書きますよね?
色々値を代入したあとは複素数を代入したくなりますよ
ね?
Swiftには複素数がない!
じゃ作ろう
目次
Swiftで数学を実装
- 2. // Intの足し算を掛け算に変える
protocol X {
static func +(a: Self, b: Self) -> Self
}
extension Int:X{
static func +(a: Int, b: Int) -> Int {
return a * b
}
}
10 + 10 // 100
Complex型を作る
極座標形式で実装
.swift
public struct Complex {
public let angle: Double // 偏角
public let radius: Double // 絶対値
}
実部、虚部
.swift
public var real: Double {
get {
return radius * cos(angle)
}
}
public var imaginary: Double {
get {
return radius * sin(angle)
}
}
初期化
.swift
public init(angle: Double, radius: Double) {
self.radius = radius
self.angle = angle
}
public init(real: Double, imaginary: Double) {
let radius = sqrt(real * real + imaginary * imaginary)
let angle = atan2(imaginary, real)
self.init(angle: angle, radius: radius)
}
.swift
複素数を実装する
複素数の定義
便利に使うAPIを追加
- 3. Complex(angle: pi / 2, radius: 1) // i
Complex(real: 1, imaginary: 1) // 1 + i
定数
.swift
let pi = Double.pi
let i = Complex(angle: pi / 2, radius: 1)
加算
減算
乗算
除算
加算
.swift
extension Complex {
static public func +(a: Complex, b: Complex) -> Complex {
return Complex(real: a.real + b.real, imaginary: a.imaginary + b.imaginary)
}
}
減算
.swift
extension Complex {
static public func -(a: Complex, b: Complex) -> Complex {
return Complex(real: a.real - b.real, imaginary: a.imaginary - b.imaginary)
}
}
乗算
.swift
extension Complex {
static public func *(a: Complex, b: Complex) -> Complex {
return Complex(angle: a.angle + b.angle, radius: a.radius * b.radius)
}
}
除算
.swift
演算の定義
加減乗除を定義する
Swift実装
- 4. extension Complex {
static public func /(a: Complex, b: Complex) -> Complex {
return Complex(angle: a.angle - b.angle, radius: a.radius / b.radius)
}
}
.swift
i * i // == -1
let x = Complex(angle:pi / 4, radius:1)
let y = Complex(angle:-pi / 4, radius:1)
x * y // == 1
.swift
1 + i
1 / i
(1 + i) * (1.0 - i)
「Complex型に変換可能」なprotocol(Complexable)を定義
Int,Double,Floatにextensionで差し込む
Complexable型の演算として定義しなおす
Complex型同士の演算はできた
数値とComplex型の演算をしたい
こうしたい
数値型と統合する
設計
クラス図
実装
- 5. .swift
public protocol Complexable {
func asComplex() -> Complex
}
extension Int: Complexable {
public func asComplex() -> Complex {return Complex(Double(self))}
}
extension Float: Complexable {
public func asComplex() -> Complex {return Complex(Double(self))}
}
extension Double: Complexable {
public func asComplex() -> Complex {return Complex(self)}
}
public struct Complex: Complexable {
・・・
public func asComplex() -> Complex {
return self
}
}
.swift
public struct Complex: Complexable {
・・・
static public func +(a: Complex, b: Complexable) -> Complex {
return a.asComplex() + b.asComplex()
}
static public func +(a: Complexabe, b: Complex) -> Complex {
return a.asComplex() + b.asComplex()
}
}
他の演算も同様に実装する
Swift2製のが多い
Riemann球面にしたい
.swift
1/0 // 無限大?
IEEE754「浮動小数点数算術標準」
できた
既存の複素数ライブラリの課題
Riemann球面
ゼロ除算
- 9. すでにCの演算は実装済み
上記の無限遠点にまつわる演算を実装すればリーマン球面を実装したと言える
TDDで実装する
.swift
let inf = Complex.infinity
let nan = Complex.nan
assert(inf != nan)
assert(inf == inf)
assert(inf != z)
assert(inf + z == inf)
assert(z + inf == inf)
assert(0 + inf == inf + 0)
assert(0 + inf == inf)
assert((inf + inf).isNan)
assert(inf - z == inf)
assert(z - inf == inf)
assert(0 - inf == inf - 0)
assert(0 - inf == inf)
assert((inf - inf).isNan)
assert(z * inf == inf * z)
assert(z * inf == inf)
assert((0 * inf).isNan)
assert((inf * 0).isNan)
assert(inf * inf == inf)
assert(i / 0 == inf)
assert(z / 0 == inf)
assert(1 / inf == 0)
assert(0 / z == 0)
assert((inf / inf).isNan)
.swift
extension Complex {
static public let infinity = Complex(angle: Double.nan, radius: Double.infinit
y)
static public let nan = Complex(angle: Double.nan, radius: Double.nan)
static public func +(a: Complex, b: Complex) -> Complex {
if a.isInfinite && b.isInfinite {
return Complex.nan
} else if a.isInfinite || b.isInfinite {
return Complex.infinity
} else if a.isNan || b.isNan {
return Complex.nan
}
return Complex(real: a.asComplex().real + b.asComplex().real, imaginary: a.a
sComplex().imaginary + b.asComplex().imaginary)
}
}
他の演算子にも同様に実装して
実装
実装
実装
Swiftのライブラリにしました