Skip to content

Instantly share code, notes, and snippets.

@BlueRayi
Last active September 11, 2018 11:41
Show Gist options
  • Save BlueRayi/e023ef48a3d3b1fe76a67605c0c99a6e to your computer and use it in GitHub Desktop.
Save BlueRayi/e023ef48a3d3b1fe76a67605c0c99a6e to your computer and use it in GitHub Desktop.
拡張複素数構造体(貧弱)
// Neary equal needs this value
fileprivate let ALLOEABLE_ERROR = 1e-12
// Custom operators
prefix operator /
infix operator **: MultiplicationPrecedence
// <Extentions for using float easily>
// Reciprocal
prefix func /(rhs: Float) -> Float
{
return 1 / rhs
}
prefix func /(rhs: Double) -> Double
{
return 1 / rhs
}
// Nearly Equal
func ~=(lhs: Float, rhs: Float) -> Bool
{
if lhs == rhs {
return true
} else {
let absE = (lhs - rhs).magnitude < Float(ALLOEABLE_ERROR)
let relE = (lhs - rhs).magnitude < [lhs.magnitude, rhs.magnitude].max()! * Float(ALLOEABLE_ERROR)
return absE || relE
}
}
func ~=(lhs: Double, rhs: Double) -> Bool
{
if lhs == rhs {
return true
} else {
let absE = (lhs - rhs).magnitude < ALLOEABLE_ERROR
let relE = (lhs - rhs).magnitude < [lhs.magnitude, rhs.magnitude].max()! * ALLOEABLE_ERROR
return absE || relE
}
}
// </Extentions for using float easily>
// <Extentions for using complex easily>
extension Double
{
// You can write complex number by "x.i", it's like "xi".
var i: Complex
{
return Complex(self) * .aye
}
// You can write complex number by "r.expi(φ)", it's like "r exp iφ".
func expi(_ phase: Double) -> Complex
{
return Complex(self) * Complex(1, expi: phase)
}
func cis(_ phase: Double) -> Complex
{
return self.expi(phase)
}
}
// You can wirte complex number by "a + b.i", it's like "a + bi"
func +(lhs: Double, rhs: Complex) -> Complex {
return Complex(lhs) + rhs
}
func -(lhs: Double, rhs: Complex) -> Complex {
return Complex(lhs) - rhs
}
// </Extentions for using complex easily>
// Extentions for cast to complex
protocol ConvertibleToDouble
{
var toDouble: Double { get }
}
extension Int: ConvertibleToDouble
{
var toDouble: Double { return Double(self) }
}
extension Float: ConvertibleToDouble
{
var toDouble: Double { return Double(self) }
}
// and more
// Xtended complex struct
struct Complex: Equatable {
// Methematical constants (Type propaties)
static let zero = Complex(ar: 0, phi: .nan)
static let one = Complex(ar: 1, phi: 0)
static let aye = Complex(ar: 1, phi: 0.5)
static let infinity = Complex(ar: .infinity, phi: .nan)
static let nan = Complex(ar: .nan, phi: .nan)
// Closed propaties
fileprivate var ar: Double
fileprivate var phi: Double
// Mathematical propaties
var magnitude: Double { return self.ar }
var phase: Double { return self.phi * atan2(0, -1) }
var real: Double { return self.ar ** cos(self.phi * atan2(0, -1)) }
var imaginary: Double { return self.ar ** sin(self.phi * atan2(0, -1)) }
// Is-propaties
var isZero: Bool { return self.ar.isZero}
var isFinite: Bool { return self.ar.isFinite}
var isInfinite : Bool { return self.ar.isInfinite}
var isNaN: Bool { return self.ar.isNaN }
// Initializers
init(_ real: Double, _ imaginary: Double)
{
self.init(ar: sqrt(real * real + imaginary * imaginary), phi: atan2(imaginary, real) / atan2(0, -1))
}
init(_ magnitude: Double, expi phase: Double)
{
self.init(ar: magnitude, phi: phase / .pi)
}
init(_ real: Double)
{
if real >= 0 {
self.init(ar: real, phi: 0)
} else {
self.init(ar: -real, phi: 1)
}
}
init<T: ConvertibleToDouble>(_ number: T)
{
self.init(number.toDouble)
}
// Root initializer(Closed)
fileprivate init(ar: Double, phi: Double)
{
var _ar = ar
var _phi = phi
if ar < 0 {
assert(false, "Magnitude must be NON-Negative value.")
_ar = .nan
_phi = .nan
} else if !ar.isFinite || ar == 0 {
_phi = .nan
}
self.ar = _ar
self.phi = Complex.nomalizephi(_phi)
}
// Closed methods
fileprivate static func nomalizephi(_ phi: Double) -> Double
{
var ret = phi
if phi.isFinite {
if phi > 0 {
while ret > 1 {
ret -= 2
}
} else {
while ret <= -1 {
ret += 2
}
}
} else {
ret = .nan
}
return ret
}
fileprivate static func simplify(_ prm: Double) -> Double
{
var rtn = prm
rtn *= 1e12
rtn.round(.toNearestOrEven)
rtn /= 1e12
return rtn
}
}
extension Complex: CustomStringConvertible
{
public var description: String {
if self.isZero {
return "(0)"
} else if self.isInfinite {
return "(∞)"
} else if self.isFinite {
if self.imaginary ~= 0 {
return "(\(Complex.simplify(self.real)))"
} else {
return "(\(Complex.simplify(self.real)), \(Complex.simplify(self.imaginary)))"
}
} else {
return "(nan)"
}
}
}
// Self, Negate, Reciprocal, Conjugate
prefix func +(rhs: Complex) -> Complex
{
return rhs
}
prefix func -(rhs: Complex) -> Complex
{
return Complex(ar: rhs.ar, phi: rhs.phi + 1.0)
}
prefix func /(rhs: Complex) -> Complex
{
return Complex(ar: /rhs.ar, phi: -rhs.phi)
}
prefix func !(rhs: Complex) -> Complex
{
return Complex(ar: rhs.ar, phi: -rhs.phi)
}
// Arithmetic
func +(lhs: Complex, rhs: Complex) -> Complex
{
if lhs.isInfinite || rhs.isInfinite {
if lhs.isFinite != rhs.isFinite {
return .infinity
} else {
return .nan
}
} else {
return Complex(lhs.real + rhs.real, lhs.imaginary + rhs.imaginary)
}
}
func -(lhs: Complex, rhs: Complex) -> Complex
{
return lhs + -rhs
}
func *(lhs: Complex, rhs: Complex) -> Complex
{
return Complex(ar: lhs.ar * rhs.ar, phi: lhs.phi + rhs.phi)
}
func /(lhs: Complex, rhs: Complex) -> Complex
{
return lhs * /rhs
}
// Comparison
func ==(lhs: Complex, rhs: Complex) -> Bool
{
if lhs.isInfinite && rhs.isInfinite {
return true
} else if lhs.ar == 0 && rhs.ar == 0 {
return true
} else {
return lhs.ar == rhs.ar && lhs.phi == rhs.phi
}
}
func !=(lhs: Complex, rhs: Complex) -> Bool
{
return !(lhs == rhs)
}
func ~=(lhs: Complex, rhs: Complex) -> Bool
{
if lhs == rhs {
return true
} else if lhs.ar ~= 0 && rhs.ar ~= 0 {
return true
} else {
return lhs.ar ~= rhs.ar && lhs.phi ~= rhs.phi
}
}
// Short-circuit multiple(Closed)
fileprivate func **(lhs: Double, rhs: Double) -> Double
{
if lhs == 0.0 || rhs == 0.0 {
return 0.0
} else {
return lhs * rhs
}
}
/* Confirm
let zero: Complex = .zero
let z1 = -8 + 12.i
let z2 = 2 + 2.i
let infinity: Complex = .infinity
let nan: Complex = .nan
let z1pz2 = -6 + 14.i
let z1mz2 = -10 + 10.i
let z1tz2 = -40 + 8.i
let z1oz2 = 1 + 5.i
"Addition"
(zero + zero).isZero
(zero + z2) ~= z2
(zero + infinity).isInfinite
(zero + nan).isNaN
(z1 + zero) ~= z1
(z1 + z2) ~= z1pz2
(z1 + infinity).isInfinite
(z1 + nan).isNaN
(infinity + zero).isInfinite
(infinity + z2).isInfinite
(infinity + infinity).isNaN
(infinity + nan).isNaN
(nan + zero).isNaN
(nan + z2).isNaN
(nan + infinity).isNaN
(nan + nan).isNaN
"Subtraction"
(zero - zero).isZero
(zero - z2) ~= -z2
(zero - infinity).isInfinite
(zero - nan).isNaN
(z1 - zero) ~= z1
(z1 - z2) ~= z1mz2
(z1 - infinity).isInfinite
(z1 - nan).isNaN
(infinity - zero).isInfinite
(infinity - z2).isInfinite
(infinity - infinity).isNaN
(infinity - nan).isNaN
(nan - zero).isNaN
(nan - z2).isNaN
(nan - infinity).isNaN
(nan - nan).isNaN
"Multiplication"
(zero * zero).isZero
(zero * z2).isZero
(zero * infinity).isNaN
(zero * nan).isNaN
(z1 * zero).isZero
(z1 * z2) ~= z1tz2
(z1 * infinity).isInfinite
(z1 * nan).isNaN
(infinity * zero).isNaN
(infinity * z2).isInfinite
(infinity * infinity).isInfinite
(infinity * nan).isNaN
(nan * zero).isNaN
(nan * z2).isNaN
(nan * infinity).isNaN
(nan * nan).isNaN
"Division"
(zero / zero).isNaN
(zero / z2).isZero
(zero / infinity).isZero
(zero / nan).isNaN
(z1 / zero).isInfinite
(z1 / z2) ~= z1oz2
(z1 / infinity).isZero
(z1 / nan).isNaN
(infinity / zero).isInfinite
(infinity / z2).isInfinite
(infinity / infinity).isNaN
(infinity / nan).isNaN
(nan / zero).isNaN
(nan / z2).isNaN
(nan / infinity).isNaN
(nan / nan).isNaN
"It's fine."
/* */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment