Last active
September 11, 2018 11:41
-
-
Save BlueRayi/e023ef48a3d3b1fe76a67605c0c99a6e to your computer and use it in GitHub Desktop.
拡張複素数構造体(貧弱)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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