Kotlin/Complex.kt

出典: フリー教科書『ウィキブックス(Wikibooks)』
Complex.kt
import kotlin.math.abs
import kotlin.math.atan2
import kotlin.math.hypot

import kotlin.math.sin
import kotlin.math.cos
import kotlin.math.tan
import kotlin.math.sinh
import kotlin.math.cosh
import kotlin.math.tanh

import kotlin.math.PI

class Complex(real_: Double, imag_: Double) : Number() {
    private val pair = doubleArrayOf(real_, imag_)
    val real get() = pair[0]
    val imag  get() = pair[1]
    constructor(real_: Number, imag_: Number) : this(real_.toDouble(), imag_.toDouble()) {
        // println("($real_, ${imag_}.i) => (${this.real}, ${this.imag}.i)")
    }
    companion object {
     	public val i = Complex(0, 1)
     	public val NaN = Complex(Double.NaN, Double.NaN)
     	public val INFINITY = Complex(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)
    }
    fun isNaN() = real.isNaN() or imag.isNaN()
    fun isFinite() = real.isFinite() and imag.isFinite()
    fun imagAsZero() = abs(imag) < 1e-12
    fun check() = 
    	when {
        	this.isNaN() -> throw Exception("NaN!")
        	!this.imagAsZero() -> throw Exception("imag($imag) != 0")
        	else -> true
        }
    override fun toChar()   = toInt().toChar()
    override fun toByte()   = toInt().toByte()
    override fun toShort()  = toInt().toShort()
    override fun toInt()    = if (check()) real.toInt() else 0
    override fun toLong()   = if (check()) real.toLong() else 0L
    override fun toFloat()  = if (check()) real.toFloat() else 0.0F
    override fun toDouble() = if (check()) real else 0.0
    override fun toString() = "${real.toString()}+${imag.toString()}.i".replace("+-","-")
    val abs get() = hypot(real, imag)
    val arg get() =
    	when {
            isNaN() -> Double.NaN
            !isFinite() -> Double.NaN
            real > 0.0 -> atan2(imag, real)
            real < 0.0 && imag >= 0.0 -> atan2(imag, real) + PI
            real < 0.0 && imag < 0.0 -> atan2(imag, real) - PI
            real == 0.0 && imag > 0.0 -> +PI / 2
            real == 0.0 && imag < 0.0 -> -PI / 2
            else -> 0.0 // indeterminate
     	}
    val angle get() = arg
    val phase get() = arg
    val conjugate get() = Complex(+real, -imag)
    val conj get() = conjugate
    operator fun plus(r: Number)  = Complex(real + r.toDouble(), imag)
    operator fun plus(r: Complex) = Complex(real + r.real, imag + r.imag)
    operator fun minus(r: Number) = Complex(real - r.toDouble(), imag)
    operator fun minus(r: Complex) = Complex(real - r.real, imag - r.imag)
    operator fun times(r: Number) = Complex(real * r.toDouble(), imag * r.toDouble())
    // (a+bi)(c+di) = a c + bi c + a di + bi di = ac - b d + (b c + a d)i
    operator fun times(r: Complex) = Complex(real * r.real - imag * r.imag, imag * r.real + real * r.imag)
    operator fun div(r: Number) = Complex(real / r.toDouble(), imag / r.toDouble())
    // this / r = this * r.conjugate / r * r.conjugate
    operator fun div(r: Complex) = this * r.conjugate / (r.real * r.real + r.imag * r.imag)
    operator fun unaryMinus() = Complex(-real, -imag)
    override fun equals(other: Any?) = when {
        this === other -> true
        other !is Complex -> false
        real != other.real -> false
        else ->  imag == other.imag
    }
    fun sin() : Complex { val c = Complex(-imag, real).sinh(); return Complex(c.imag, -c.real) }
    fun sinh()  = sinh(real) * cos(imag) + (cosh(real) * sin(imag)).i
}
operator fun Number.plus(c:Complex)  = Complex(this.toDouble(), 0.0) + c
operator fun Number.minus(c:Complex) = Complex(this.toDouble(), 0.0) - c
operator fun Number.times(c:Complex) = Complex(this.toDouble(), 0.0) * c
operator fun Number.div(c:Complex)   = Complex(this.toDouble(), 0.0) / c
val Number.r get() = Complex(toDouble(), 0.0)
val Number.i get() = Complex(0.0, toDouble())

fun main() {
    val a =  2.1 +  3.9.i
    val b = -7.8 + 11.11.i
    val c =  3 + 4.i
    val p = 2.3.r
    val q = 1.3.i

    try { Complex.NaN.toDouble()                } catch (e: Exception) { println("Complex.NaN.toDouble() raises $e") }
    try { Complex.INFINITY.toDouble()           } catch (e: Exception) { println("Complex.INFINITY.toDouble() raises $e")}
    try { Double.POSITIVE_INFINITY.r.toDouble() } catch (e: Exception) { println("Double.POSITIVE_INFINITY.r.toDouble() raises $e")}
    try { 1.i.toDouble()                        } catch (e: Exception) { println("1.i.toDouble() raises $e")}

    println(
"""
a == a => ${a == a}
a != a => ${a != a}
a == 2.1 + 3.9.i => ${a == 2.1 + 3.9.i}
3.14.i == 3.14.i => ${3.14.i == 3.14.i}
Double.NaN.i == Double.NaN.i => ${Double.NaN.i == Double.NaN.i} 
Double.POSITIVE_INFINITY.r == Double.POSITIVE_INFINITY.r + 1 => ${Double.POSITIVE_INFINITY.r == Double.POSITIVE_INFINITY.r + 1}

Complex(0, 1).arg => ${Complex(0.0, 1).arg}
Complex(0, -1).arg => ${Complex(0.0, -1).arg}
Complex(1, 1).arg => ${Complex(1.0, 1).arg}
Complex(1, -1).arg => ${Complex(1.0, -1).arg}
Complex(1, 0.0).arg => ${Complex(1.0, 0.0).arg}
Complex(-1, 0.0).arg => ${Complex(-1.0, 0.0).arg}
Complex(0.0, 0.0).arg => ${Complex(0.0, 0.0).arg}

2.toBigDecimal() = ${2.toBigDecimal()}
2.toBigDecimal().i = ${2.toBigDecimal().i}
a => $a
b => $b
c => $c
p => $p
q => $q

Double.NaN.r => ${Double.NaN.r}
Double.NaN.i => ${Double.NaN.i}
Double.POSITIVE_INFINITY.r => ${Double.POSITIVE_INFINITY.r}
Double.POSITIVE_INFINITY.i => ${Double.POSITIVE_INFINITY.i}
-Double.POSITIVE_INFINITY.r => ${-Double.POSITIVE_INFINITY.r}
Double.POSITIVE_INFINITY.i.conj => ${Double.POSITIVE_INFINITY.i.conj}

(1+2.i) / 0 => ${(1+2.i) / 0}
(0+0.i) / 0 => ${(0+0.i) / 0.0}
Double.NaN.i.isNaN() => ${Double.NaN.i.isNaN()}
Double.NaN.i.isFinite() => ${Double.NaN.i.isFinite()}
1.i.isNaN() => ${1.i.isNaN()}
1.i.isFinite() => ${1.i.isFinite()}
Complex.INFINITY.isNaN() => ${Complex.INFINITY.isNaN()}
Complex.INFINITY.isFinite() => ${Complex.INFINITY.isFinite()}

-a => ${-a}
a + 8 => ${a + 8}
8 + a => ${8 + a}
a + b => ${a + b}
a - b => ${a - b}
a * b => ${a * b}
a * Complex(1, 1) => ${a * Complex(1, 1)}
a / 2 => ${a / 2}
a / b => ${a / b}
a / b * b => ${a / b * b}
a * 1.i => ${a * 1.i}
a / 1.i => ${a / 1.i}
1.i => ${1.i}
1.i / 1.i => ${1.i / 1.i}
1.0 + 3.2.i => ${1.0 + 3.2.i}
a + 3.2 => ${a + 3.2}
a.conjugate => ${a.conjugate}
1 + 2.i => ${1 + 2.i}
"""
    )
}
実行結果
Complex.NaN.toDouble() raises java.lang.Exception: NaN!
Complex.INFINITY.toDouble() raises java.lang.Exception: imag(Infinity) != 0
1.i.toDouble() raises java.lang.Exception: imag(1.0) != 0

a == a => true
a != a => false
a == 2.1 + 3.9.i => true
3.14.i == 3.14.i => true
Double.NaN.i == Double.NaN.i => false 
Double.POSITIVE_INFINITY.r == Double.POSITIVE_INFINITY.r + 1 => true

Complex(0, 1).arg => 1.5707963267948966
Complex(0, -1).arg => -1.5707963267948966
Complex(1, 1).arg => 0.7853981633974483
Complex(1, -1).arg => -0.7853981633974483
Complex(1, 0.0).arg => 0.0
Complex(-1, 0.0).arg => 6.283185307179586
Complex(0.0, 0.0).arg => 0.0

2.toBigDecimal() = 2
2.toBigDecimal().i = 0.0+2.0.i
a => 2.1+3.9.i
b => -7.8+11.11.i
c => 3.0+4.0.i
p => 2.3+0.0.i
q => 0.0+1.3.i

Double.NaN.r => NaN+0.0.i
Double.NaN.i => 0.0+NaN.i
Double.POSITIVE_INFINITY.r => Infinity+0.0.i
Double.POSITIVE_INFINITY.i => 0.0+Infinity.i
-Double.POSITIVE_INFINITY.r => -Infinity-0.0.i
Double.POSITIVE_INFINITY.i.conj => 0.0-Infinity.i

(1+2.i) / 0 => Infinity+Infinity.i
(0+0.i) / 0 => NaN+NaN.i
Double.NaN.i.isNaN() => true
Double.NaN.i.isFinite() => false
1.i.isNaN() => false
1.i.isFinite() => true
Complex.INFINITY.isNaN() => false
Complex.INFINITY.isFinite() => false

-a => -2.1-3.9.i
a + 8 => 10.1+3.9.i
8 + a => 10.1+3.9.i
a + b => -5.699999999999999+15.01.i
a - b => 9.9-7.209999999999999.i
a * b => -59.70899999999999-7.088999999999999.i
a * Complex(1, 1) => -1.7999999999999998+6.0.i
a / 2 => 1.05+1.95.i
a / b => 0.14624568776282462-0.2916936421737203.i
a / b * b => 2.1000000000000005+3.8999999999999995.i
a * 1.i => -3.9+2.1.i
a / 1.i => 3.9-2.1.i
1.i => 0.0+1.0.i
1.i / 1.i => 1.0+0.0.i
1.0 + 3.2.i => 1.0+3.2.i
a + 3.2 => 5.300000000000001+3.9.i
a.conjugate => 2.1-3.9.i
1 + 2.i => 1.0+2.0.i