All Downloads are FREE. Search and download functionalities are using the official Maven repository.

h.complex-numbers.1.0.source-code.Complex.kt Maven / Gradle / Ivy

Go to download

A lightweight library that allows a comfortable handling of complex numbers in Kotlin

The newest version!
package org.kotlinmath

import java.util.*
import kotlin.math.*

/**
 * This interface represents a Complex number. Essentially, a complex number is
 * a tupel of two Double values, the real (re) and the imaginary (im) part.
 * Additionally, there are two further calculated properties arg and mod, which
 * are the values of the corresponding polar coordinate representation.
 * The main purpose of this interface/class is that you can combine complex numbers
 * using the four basic arithmetic operations (+, -, *, /) with each other but also
 * with all other objects of the type Number.
 */
interface Complex {

    companion object {
        const val DEFAULT_ZERO_SNAP_PRECISION = 1E-13
    }

    /** Real part */
    val re: Double

    /** Imaginary part */
    val im: Double

    // Hint: Usually it is not necessary to override the (calculated) properties
    // arg and mod with a lazy and caching-like kind. Using Kotlin's "lazy" increases
    // the execution time by a factor of 6. So the properties would have to be read
    // at least six times before caching would pay off, which is quite unlikely.

    /** The argument of this complex number (angle of the polar coordinate representation) */
    val arg: Double
        get() {
            return when {
                re > 0.0 -> atan(im / re)
                re < 0.0 && im >= 0.0 -> atan(im / re) + PI
                re < 0.0 && im < 0.0 -> atan(im / re) - PI
                re == 0.0 && im > 0.0 -> PI / 2
                re == 0.0 && im < 0.0 -> -PI / 2
                else -> 0.0
            }
        }

    /** The modulus (absolute value) of this complex number (radius of the polar coordinate representation)  */
    val mod: Double
        get() {
            return kotlin.math.sqrt(re * re + im * im)
        }

    /**
     *  checks infinity property (remark that in case of complex numbers there is only one unsigned infinity)
     *  @return true if this is infinite
     */
    fun isInfinite() = this === INF

    /**
     * checks the "not a number" property (NaN represents an essential singularity)
     * @return true if this is NaN
     */
    fun isNaN() = this === NaN

    /**
     * checks to zero
     *  @return true if this is zero
     */
    fun isZero() = this == ZERO

    /**
     * Plus operator adding two complex numbers
     * @param z the summand
     * @return sum of this and z
     */
    operator fun plus(z: Complex): Complex {
        return when {
            isNaN() || z.isNaN() -> NaN
            isInfinite() -> if (z.isInfinite()) NaN else INF
            z.isInfinite() -> if (isInfinite()) NaN else INF
            else -> complex(re + z.re, im + z.im)
        }
    }

    /**
     * Plus operator adding a complex number and a number of type Double
     * @param x the summand
     * @return sum of this and x
     */
    operator fun plus(x: Double): Complex {
        return when {
            isNaN() || x.isNaN() -> NaN
            isInfinite() -> if (x.isInfinite()) NaN else INF
            x.isInfinite() -> if (isInfinite()) NaN else INF
            else -> complex(re + x, im)
        }
    }

    /**
     * Plus operator adding a complex number and one of type Number except Double
     * @param x the summand
     * @return sum of this and x
     */
    operator fun plus(x: Number) = plus(x.toDouble())

    /**
     * Minus operator subtracting two complex numbers
     * @param z the minuend
     * @return difference of this and x
     */
    operator fun minus(z: Complex): Complex {
        return when {
            isNaN() || z.isNaN() -> NaN
            isInfinite() -> if (z.isInfinite()) NaN else INF
            z.isInfinite() -> if (isInfinite()) NaN else INF
            else -> complex(re - z.re, im - z.im)
        }
    }

    /**
     * Minus operator subtracting a complex number and one of type Double
     * @param x the minuend
     * @return difference of this and x
     */
    operator fun minus(x: Double): Complex {
        return when {
            isNaN() || x.isNaN() -> NaN
            isInfinite() -> if (x.isInfinite()) NaN else INF
            x.isInfinite() -> if (isInfinite()) NaN else INF
            else -> complex(re - x, im)
        }
    }

    /**
     * Minus operator subtracting a complex number and one of type Number except Double
     * @param x the minuend
     * @return difference of this and x
     */
    operator fun minus(x: Number) = minus(x.toDouble())

    /**
     * Times operator multiplying two complex numbers
     * @param z the multiplicand
     * @return product of this and z
     */
    operator fun times(z: Complex): Complex {
        return when {
            isNaN() || z.isNaN() -> NaN
            isInfinite() -> if (z.isZero()) NaN else INF
            z.isInfinite() -> if (isZero()) NaN else INF
            else -> complex(re * z.re - im * z.im, im * z.re + re * z.im)
        }
    }

    /**
     * Times operator multiplying a complex number and one of type Double
     * @param x the multiplicand
     * @return product of this and x
     */
    operator fun times(x: Double): Complex {
        return when {
            isNaN() || x.isNaN() -> NaN
            isInfinite() -> if (x == 0.0) NaN else INF
            x.isInfinite() -> if (isZero()) NaN else INF
            else -> complex(re * x, im * x)
        }
    }

    /**
     * Times operator multiplying a complex number and one of type Number except Double
     * @param x the multiplicand
     * @return the product of this and x
     */
    operator fun times(x: Number) = times(x.toDouble())

    /**
     * Divide operator dividing two complex numbers
     * @param z the denominator
     * @return product of this and z
     */
    operator fun div(z: Complex): Complex {
        return when {
            isNaN() || z.isNaN() -> NaN
            isInfinite() -> if (z.isInfinite()) NaN else INF
            z.isInfinite() -> ZERO
            z.isZero() -> if (isZero()) NaN else INF
            else -> {
                val d = z.re * z.re + z.im * z.im
                complex((re * z.re + im * z.im) / d, (im * z.re - re * z.im) / d)
            }
        }
    }

    /**
     * Divide operator dividing a complex number and one of type Double
     * @param x the divisor
     * @return division of this and z
     */
    operator fun div(x: Double): Complex {
        return when {
            isNaN() || x.isNaN() -> NaN
            isInfinite() -> if (x.isInfinite()) NaN else INF
            x.isInfinite() -> ZERO
            x == 0.0 -> if (isZero()) NaN else INF
            else -> complex(re / x, im / x)
        }
    }

    /**
     * Divide operator dividing a complex number and one of type Number except Double
     * @param x the divisor
     * @return division of this and z
     */
    operator fun div(x: Number) = div(x.toDouble())

    /**
     * Negates a complex number
     * @return negation of this
     */
    operator fun unaryMinus(): Complex {
        return when {
            isNaN() -> NaN
            isInfinite() -> INF
            else -> complex(-re, -im)
        }
    }

    /**
     * Calculates the complex conjugation
     * @return complex conjugation of this
     */
    operator fun not(): Complex = conj()

    /**
     * Calculates the complex conjugation
     * @return complex conjugation of this
     */
    fun conj(): Complex {
        return when {
            isNaN() -> NaN
            isInfinite() -> INF
            else -> complex(re, -im)
        }
    }

    /**
     * Sets the real and/or the imaginary part to 0 if the value is lower than precision
     * @param precision
     * @return the "rounded" number
     */
    fun zeroSnap(precision: Double = DEFAULT_ZERO_SNAP_PRECISION): Complex {
        return complex(if (abs(re) <= precision) 0 else re,
                if (abs(im) <= precision) 0 else im
        )
    }

    /**
     * A string representation of a complex number (this) in the Form "2.5+3.1i" for example.
     * @param format This parameter affects the real an the imaginary part equally.
     * @param locale The locale determines e.g. whether a dot or a comma is output.
     */
    fun asString(format: String = "", locale: Locale = Locale.getDefault()): String {
        return when (this) {
            NaN -> "NaN"
            INF -> "Infinity"
            else -> {
                val reFormatted = if (format.isEmpty()) re.toString() else String.format(locale, format, re)
                val imFormatted = when (im) {
                    1.0 -> "i"
                    -1.0 -> "-i"
                    else -> "${if (format.isEmpty()) im.toString() else String.format(locale, format, im)}i"
                }
                if (re == 0.0) {
                    if (im == 0.0) "0.0" else imFormatted
                } else {
                    when {
                        im > 0.0 -> "$reFormatted+$imFormatted"
                        im < 0.0 -> "$reFormatted$imFormatted"
                        else -> reFormatted
                    }
                }
            }
        }
    }
}

/**
 * Makes a number "imaginary". The result is the same as if the number (this) is multiplied by I.
 * @return this * I
 */
val Number.I: Complex
    get() = complex(0, toDouble())

/**
 * Creates a complex number with this as real part and no imaginary part
 * @return this as complex number
 */
val Number.R: Complex
    get() = complex(toDouble(), 0)

/**
 * Plus operator adding a number of type Number and a complex one
 * @param z the summand
 * @return sum of this and z
 */
operator fun Number.plus(z: Complex) = z + this

/**
 * Minus operator subtracting a number of type Number and a complex one
 * @param z the minuend
 * @return difference of this and z
 */
operator fun Number.minus(z: Complex) = -z + this

/**
 * Times operator multiplying a number of type Number and a complex one
 * @param z the multiplicand
 * @return product of this and z
 */
operator fun Number.times(z: Complex) = z * this

/**
 * Division operator dividing a number of type Number and a complex one
 * @param z the divisor
 * @return division of this and z
 */
operator fun Number.div(z: Complex) = ONE / z * this

/**
 * Creates a complex number from a string. A valid representation is e.g. "2.5+3.1i"
 * @return the created complex number
 */
var toComplex: String.() -> Complex = {

    fun parseIm(arg: String): String {
        val im = arg.removeSuffix("i")
        return if (im.isEmpty()) "1.0" else im
    }

    when (this) {
        "Infinity" -> INF
        "NaN" -> NaN
        else -> {
            val parts = StringTokenizer(this, "+-", true)
                    .toList().map { it.toString().replace('I', 'i') }
            when (parts.size) {
                0 -> throw NumberFormatException("empty String")
                1 -> if (parts[0].endsWith("i")) {
                    complex(0.0, parseIm(parts[0]).toDouble())
                } else {
                    complex(parts[0].toDouble(), 0.0)
                }
                2 -> if (parts[1].endsWith("i")) {
                    complex(0.0, (parts[0] + parseIm(parts[1])).toDouble())
                } else {
                    complex((parts[0] + parts[1]).toDouble(), 0.0)
                }
                3 -> complex(parts[0].toDouble(), (parts[1] + parseIm(parts[2])).toDouble())
                4 -> complex((parts[0] + parts[1]).toDouble(), (parts[2] + parseIm(parts[3])).toDouble())
                else -> throw NumberFormatException("For input string: \"$this\"")
            }
        }
    }
}

/**
 * Creates a complex number from real and imaginary part.
 * Here instances of class DefaultComplex are created which implements 
 * the interface Complex is used by
 * the factory function toComplex. If you would like to use your own
 * implementation of Complex you can do this by replacing toComplex
 * with a factory which is creating your custom class. So, the entire application code can
 * remain the same.
 * @param re the real part
 * @param im the imaginary part
 * @return the created complex number
 */
var complex: (re: Number, im: Number) -> Complex = { re, im -> DefaultComplex(re.toDouble(), im.toDouble()) }

/** The imaginary unit i as constant */
val I = complex(0, 1)

/** Number 0 as complex constant */
val ZERO = complex(0, 0)

/** The real unit 1 as constant */
val ONE = complex(1, 0)

/** "Not a number" represents a essential singularity */
val NaN = complex(Double.NaN, Double.NaN)

/** Infinity represents the north pole of the complex sphere. */
val INF = complex(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)


/**
 * A default implementation of the interface Complex. This class is used by
 * the factory function complex (s. above). If you would like to use your own
 * implementation of Complex you can do this by replacing complex
 * with a factory function which is creating your custom class. In this way the entire
 * application code can remain the same.
 */
open class DefaultComplex(override val re: Double, override val im: Double = 0.0) : Complex {
    constructor(z: Complex) : this(z.re, z.im)
    constructor(str: String) : this(str.toComplex())

    // equals had to be overwritten because of a bug comparing data classes with
    // -0.0 as (real or imaginary) Double value. Without overwriting equals the
    // following would apply: DefaultComplex(0.0, 0.0) != DefaultComplex(-0.0, 0.0)
    // although 0.0 == -0.0.

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other === null) return false
        if (other is Complex) {
            if (re != other.re) return false
            if (im != other.im) return false
            return true
        }
        return false
    }

    override fun hashCode(): Int {
        var result = re.hashCode()
        result = 31 * result + im.hashCode()
        return result
    }

    override fun toString() = asString()
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy