Home Reference Source

src/math/core/Complex.js

/**
 * The script is part of konpeito.
 * 
 * AUTHOR:
 *  natade (http://twitter.com/natadea)
 * 
 * LICENSE:
 *  The MIT license https://opensource.org/licenses/MIT
 */

import Polyfill from "../tools/Polyfill.js";
import Probability from "./tools/Probability.js";
import Random from "./tools/Random.js";
import Matrix from "./Matrix.js";
import BigInteger from "./BigInteger.js";
import BigDecimal from "./BigDecimal.js";
import Fraction from "./Fraction.js";
import MathContext from "./context/MathContext.js";
import KonpeitoFloat from "./base/KonpeitoFloat.js";

/**
 * Complex type argument.
 * - Complex
 * - number
 * - boolean
 * - string
 * - Array<number>
 * - {_re:number,_im:number}
 * - {doubleValue:number}
 * - {toString:function}
 * 
 * Initialization can be performed as follows.
 * - 1200, "1200", "12e2", "1.2e3"
 * - "3 + 4i", "4j + 3", [3, 4].
 * @typedef {Complex|number|boolean|string|Array<number>|{_re:number,_im:number}|{doubleValue:number}|{toString:function}} KComplexInputData
 */

/**
 * Random number generation class used within Complex.
 * @type {Random}
 * @ignore
 */
const random_class = new Random();

/**
 * Collection of functions used in Complex.
 * @ignore
 */
class ComplexTool {

	/**
	 * Create data for complex numbers from strings.
	 * @param {string} text - Target strings.
	 * @returns {{real : number, imag : number}}
	 */
	static ToComplexFromString(text) {
		let str = text.replace(/\s/g, "").toLowerCase();
		str = str.replace(/infinity|inf/g, "1e100000");
		// 複素数の宣言がない場合
		if(!(/[ij]/.test(str))) {
			return {
				real : parseFloat(str),
				imag : 0.0
			};
		}
		// この時点で複素数である。
		// 以下真面目に調査
		let re = 0;
		let im = 0;
		let buff;
		// 最後が$なら右側が実数、最後が[+-]なら左側が実数
		buff = str.match(/[+-]?(([0-9]+(\.[0-9]+)?(e[+-]?[0-9]+)?)|(nan))($|[+-])/);
		if(buff) {
			re = parseFloat(buff[0]);
		}
		// 複素数は数値が省略される場合がある
		buff = str.match(/[+-]?(([0-9]+(\.[0-9]+)?(e[+-]?[0-9]+)?)|(nan))?[ij]/);
		if(buff) {
			buff = buff[0].substring(0, buff[0].length - 1);
			// i, +i, -j のように実数部がなく、数値もない場合
			if((/^[-+]$/.test(buff)) || buff.length === 0) {
				im = buff === "-" ? -1 : 1;
			}
			else {
				im = parseFloat(buff);
			}
		}
		return {
			real : re,
			imag : im
		};
	}

}

/**
 * Complex number class. (immutable)
 */
export default class Complex extends KonpeitoFloat {

	/**
	 * Create a complex number.
	 * 
	 * Initialization can be performed as follows.
	 * - 1200, "1200", "12e2", "1.2e3"
	 * - "3 + 4i", "4j + 3", [3, 4].
	 * @param {KComplexInputData} number - Complex number. See how to use the function.
	 */
	constructor(number) {
		super();
		
		// 行列で使うためイミュータブルは必ず守ること。
		if(arguments.length === 1) {
			const obj = number;
			if(obj instanceof Complex) {
				
				/**
				 * The real part of this Comlex.
				 * @private
				 * @type {number}
				 */
				this._re = obj._re;
				
				/**
				 * The imaginary part of this Comlex.
				 * @private
				 * @type {number}
				 */
				this._im = obj._im;
			}
			else if(typeof obj === "number") {
				this._re = obj;
				this._im = 0.0;
			}
			else if(typeof obj === "string") {
				const x = ComplexTool.ToComplexFromString(obj);
				this._re = x.real;
				this._im = x.imag;
			}
			else if(obj instanceof Array) {
				if(obj.length === 2) {
					this._re = obj[0];
					this._im = obj[1];
				}
				else {
					throw "Complex Unsupported argument " + arguments;
				}
			}
			else if(typeof obj === "boolean") {
				this._re = obj ? 1 : 0;
				this._im = 0.0;
			}
			else if("doubleValue" in obj) {
				this._re = obj.doubleValue;
				this._im = 0.0;
			}
			else if(("_re" in obj) && ("_im" in obj)) {
				this._re = obj._re;
				this._im = obj._im;
			}
			else if(obj instanceof Object) {
				const x = ComplexTool.ToComplexFromString(obj.toString());
				this._re = x.real;
				this._im = x.imag;
			}
			else {
				throw "Complex Unsupported argument " + arguments;
			}
		}
		else {
			throw "Complex Many arguments : " + arguments.length;
		}
	}

	/**
	 * Create an entity object of this class.
	 * @param {KComplexInputData} number
	 * @returns {Complex}
	 */
	static create(number) {
		if(number instanceof Complex) {
			return number;
		}
		else {
			return new Complex(number);
		}
	}
	
	/**
	 * Convert number to Complex type.
	 * @param {KComplexInputData} number
	 * @returns {Complex}
	 */
	static valueOf(number) {
		return Complex.create(number);
	}
	
	/**
	 * Convert to Complex.
	 * If type conversion is unnecessary, return the value as it is.
	 * @param {KComplexInputData} number 
	 * @returns {Complex}
	 * @ignore
	 */
	static _toComplex(number) {
		if(number instanceof Complex) {
			return number;
		}
		else if(number instanceof Matrix) {
			return Matrix._toComplex(number);
		}
		else {
			return new Complex(number);
		}
	}

	/**
	 * Convert to real number.
	 * @param {KComplexInputData} number 
	 * @returns {number}
	 * @ignore
	 */
	static _toDouble(number) {
		if(typeof number === "number") {
			return number;
		}
		const complex_number = Complex._toComplex(number);
		if(complex_number.isReal()) {
			return complex_number.real;
		}
		else {
			throw "not support complex numbers.[" + number + "]";
		}
	}

	/**
	 * Convert to integer.
	 * @param {KComplexInputData} number 
	 * @returns {number}
	 * @ignore
	 */
	static _toInteger(number) {
		return Math.trunc(Complex._toDouble(number));
	}

	/**
	 * Deep copy.
	 * @returns {Complex} 
	 */
	clone() {
		return this;
	}

	/**
	 * Convert to string.
	 * @returns {string} 
	 */
	toString() {
		/**
		 * @type {function(number): string }
		 */
		const formatG = function(x) {
			let numstr = x.toPrecision(6);
			if(numstr.indexOf(".") !== -1) {
				numstr = numstr.replace(/\.?0+$/, "");  // 1.00 , 1.10
				numstr = numstr.replace(/\.?0+e/, "e"); // 1.0e , 1.10e
			}
			else if(/inf/i.test(numstr)) {
				if(x === Number.POSITIVE_INFINITY) {
					return "Inf";
				}
				else {
					return "-Inf";
				}
			}
			else if(/nan/i.test(numstr)) {
				return "NaN";
			}
			return numstr;
		};
		if(!this.isReal()) {
			if(this._re === 0) {
				return formatG(this._im) + "i";
			}
			else if((this._im >= 0) || (Number.isNaN(this._im))) {
				return formatG(this._re) + " + " + formatG(this._im) + "i";
			}
			else {
				return formatG(this._re) + " - " + formatG(-this._im) + "i";
			}
		}
		else {
			return formatG(this._re);
		}
	}

	/**
	 * Convert to JSON.
	 * @returns {string} 
	 */
	toJSON() {
		if(!this.isReal()) {
			if(this._re === 0) {
				return this._im.toString() + "i";
			}
			else if((this._im >= 0) || (Number.isNaN(this._im))) {
				return this._re.toString() + "+" + this._im.toString() + "i";
			}
			else {
				return this._re.toString() + this._im.toString() + "i";
			}
		}
		else {
			return this._re.toString();
		}
	}
	
	/**
	 * The real part of this Comlex.
	 * @returns {number} real(A)
	 */
	get real() {
		return this._re;
	}
	
	/**
	 * The imaginary part of this Comlex.
	 * @returns {number} imag(A)
	 */
	get imag() {
		return this._im;
	}

	/**
	 * norm.
	 * @returns {number} |A|
	 */
	get norm() {
		if(this._im === 0) {
			return Math.abs(this._re);
		}
		else if(this._re === 0) {
			return Math.abs(this._im);
		}
		else {
			return Math.sqrt(this._re * this._re + this._im * this._im);
		}
	}

	/**
	 * The argument of this complex number.
	 * @returns {number} arg(A)
	 */
	get arg() {
		if(this._im === 0) {
			return this._re >= 0 ? 0 : Math.PI;
		}
		else if(this._re === 0) {
			return Math.PI * (this._im >= 0.0 ? 0.5 : -0.5);
		}
		else {
			return Math.atan2(this._im, this._re);
		}
	}

	/**
	 * Return number of decimal places for real and imaginary parts.
	 * - Used to make a string.
	 * @returns {number} Number of decimal places.
	 */
	getDecimalPosition() {
		/**
		 * @type {function(number): number }
		 */
		const getDecimal = function(x) {
			if(!Number.isFinite(x)) {
				return 0;
			}
			let a = x;
			let point = 0;
			for(let i = 0; i < 20; i++) {
				if(Math.abs(a - Math.round(a)) <= Number.EPSILON) {
					break;
				}
				a *= 10;
				point++;
			}
			return point;
		};
		return Math.max( getDecimal(this.real), getDecimal(this.imag) );
	}

	/**
	 * The positive or negative sign of this number.
	 * - +1 if positive, -1 if negative, 0 if 0.
	 * @returns {Complex} 
	 */
	sign() {
		if(!this.isFinite()) {
			if(this.isNaN() || this._im === Infinity || this._im === -Infinity) {
				return Complex.NaN;
			}
			if(this._re === Infinity) {
				return Complex.ONE;
			}
			else {
				return Complex.MINUS_ONE;
			}
		}
		if(this._im === 0) {
			if(this._re === 0) {
				return Complex.ZERO;
			}
			else {
				return new Complex(this._re > 0 ? 1 : -1);
			}
		}
		return this.div(this.norm);
	}
	
	// ----------------------
	// 四則演算
	// ----------------------
	
	/**
	 * Add.
	 * @param {KComplexInputData} number 
	 * @returns {Complex} A + B
	 */
	add(number) {
		const A = this;
		const B = new Complex(number);
		B._re = A._re + B._re;
		B._im = A._im + B._im;
		return B;
	}

	/**
	 * Subtract.
	 * @param {KComplexInputData} number
	 * @returns {Complex} A - B
	 */
	sub(number) {
		const A = this;
		const B = new Complex(number);
		B._re = A._re - B._re;
		B._im = A._im - B._im;
		return B;
	}

	/**
	 * Multiply.
	 * @param {KComplexInputData} number
	 * @returns {Complex} A * B
	 */
	mul(number) {
		const A = this;
		const B = new Complex(number);
		if((A._im === 0) && (B._im === 0)) {
			B._re = A._re * B._re;
			return B;
		}
		else if((A._re === 0) && (B._re === 0)) {
			B._re = - A._im * B._im;
			B._im = 0;
			return B;
		}
		else {
			const re = A._re * B._re - A._im * B._im;
			const im = A._im * B._re + A._re * B._im;
			B._re = re;
			B._im = im;
			return B;
		}
	}
	
	/**
	 * Inner product/Dot product.
	 * @param {KComplexInputData} number
	 * @returns {Complex} A * conj(B)
	 */
	dot(number) {
		const A = this;
		const B = new Complex(number);
		if((A._im === 0) && (B._im === 0)) {
			B._re = A._re * B._re;
			return B;
		}
		else if((A._re === 0) && (B._re === 0)) {
			B._re = A._im * B._im;
			B._im = 0;
			return B;
		}
		else {
			const re =   A._re * B._re + A._im * B._im;
			const im = - A._im * B._re + A._re * B._im;
			B._re = re;
			B._im = im;
			return B;
		}
	}
	
	/**
	 * Divide.
	 * @param {KComplexInputData} number
	 * @returns {Complex} A / B
	 */
	div(number) {
		const A = this;
		const B = new Complex(number);
		if((A._im === 0) && (B._im === 0)) {
			B._re = A._re / B._re;
			return B;
		}
		else if((A._re === 0) && (B._re === 0)) {
			B._re = A._im / B._im;
			B._im = 0;
			return B;
		}
		else {
			const re = A._re * B._re + A._im * B._im;
			const im = A._im * B._re - A._re * B._im;
			const denominator = 1.0 / (B._re * B._re + B._im * B._im);
			B._re = re * denominator;
			B._im = im * denominator;
			return B;
		}
	}

	/**
	 * Modulo, positive remainder of division.
	 * - Result has same sign as the Dividend.
	 * @param {KComplexInputData} number - Divided value (real number only).
	 * @returns {Complex} A rem B
	 */
	rem(number) {
		const A = this;
		const B = new Complex(number);
		if((A._im !== 0) || (B._im !== 0)) {
			throw "calculation method is undefined.";
		}
		if(!A.isFinite() || !B.isFinite() || B.isZero()) {
			return Complex.NaN;
		}
		B._re = A._re - B._re * (Math.trunc(A._re / B._re));
		return B;
	}

	/**
	 * Modulo, positive remainder of division.
	 * - Result has same sign as the Divisor.
	 * @param {KComplexInputData} number - Divided value (real number only).
	 * @returns {Complex} A mod B
	 */
	mod(number) {
		const A = this;
		const B = new Complex(number);
		if((A._im !== 0) || (B._im !== 0)) {
			throw "calculation method is undefined.";
		}
		if(B.isZero()) {
			return A;
		}
		const ret = A.rem(B);
		if(!A.equalsState(B)) {
			return ret.add(B);
		}
		else {
			return ret;
		}
	}

	/**
	 * Inverse number of this value.
	 * @returns {Complex} 1 / A
	 */
	inv() {
		if(this._im === 0) {
			return new Complex(1.0 / this._re);
		}
		else if(this._re === 0) {
			return new Complex([0, - 1.0 / this._im]);
		}
		return Complex.ONE.div(this);
	}

	// ----------------------
	// 他の型に変換用
	// ----------------------
	
	/**
	 * boolean value.
	 * @returns {boolean}
	 */
	get booleanValue() {
		return !this.isZero() && !this.isNaN();
	}

	/**
	 * integer value.
	 * @returns {number}
	 */
	get intValue() {
		if(!this.isFinite()) {
			return this.isNaN() ? NaN : (this.isPositiveInfinity() ? Infinity : -Infinity);
		}
		const value = this._re;
		const delta = Math.abs(value - Math.trunc(value));
		if(delta < Number.EPSILON) {
			return Math.round(value);
		}
		else {
			return Math.trunc(value);
		}
	}

	/**
	 * floating point.
	 * @returns {number}
	 */
	get doubleValue() {
		if(!this.isFinite()) {
			return this.isNaN() ? NaN : (this.isPositiveInfinity() ? Infinity : -Infinity);
		}
		const value = this._re;
		const delta = Math.abs(value - Math.trunc(value));
		if(delta < Number.EPSILON) {
			return Math.round(value);
		}
		else {
			return value;
		}
	}

	// ----------------------
	// konpeito で扱う数値型へ変換
	// ----------------------
	
	/**
	 * return BigInteger.
	 * @returns {BigInteger}
	 */
	toBigInteger() {
		return new BigInteger(this.intValue);
	}
	
	/**
	 * return BigDecimal.
	 * @param {MathContext} [mc] - MathContext setting after calculation. 
	 * @returns {BigDecimal}
	 */
	toBigDecimal(mc) {
		if(mc) {
			return new BigDecimal([this.doubleValue, mc]);
		}
		else {
			return new BigDecimal(this.doubleValue);
		}
	}
	
	/**
	 * return Fraction.
	 * @returns {Fraction}
	 */
	toFraction() {
		return new Fraction(this.doubleValue);
	}
	
	/**
	 * return Complex.
	 * @returns {Complex}
	 */
	toComplex() {
		return this;
	}
	
	/**
	 * return Matrix.
	 * @returns {Matrix}
	 */
	toMatrix() {
		return new Matrix(this);
	}

	// ----------------------
	// 比較
	// ----------------------
	
	/**
	 * Equals.
	 * @param {KComplexInputData} number
	 * @param {KComplexInputData} [tolerance=Number.EPSILON] - Calculation tolerance of calculation.
	 * @returns {boolean} A === B
	 */
	equals(number, tolerance) {
		const A = this;
		const B = Complex._toComplex(number);
		// 無限大、非数の値も含めて一度確認
		if(A.isNaN() || B.isNaN()) {
			return false;
		}
		if((A._re === B._re) && (A._im === B._im)) {
			return true;
		}
		// 誤差を含んだ値の比較
		const tolerance_ = tolerance ? Complex._toDouble(tolerance) : Number.EPSILON;
		return (Math.abs(A._re - B._re) <  tolerance_) && (Math.abs(A._im - B._im) < tolerance_);
	}

	/**
	 * Numeric type match.
	 * @param {KComplexInputData} number 
	 * @returns {boolean}
	 */
	equalsState(number) {
		const A = this;
		const B = Complex._toComplex(number);
		/**
		 * @param {Complex} num
		 * @returns {number}
		 */
		const getState = function(num) {
			if(num.isZero()) {
				return 0;
			}
			if(!num.isFinite()) {
				if(num.isPositiveInfinity()) {
					return 4;
				}
				else if(num.isNegativeInfinity()) {
					return 5;
				}
				else {
					return 3;
				}
			}
			return num.isPositive() ? 1 : 2;
		};
		const A_type = getState(A);
		const B_type = getState(B);
		return A_type === B_type;
	}

	/**
	 * Compare values.
	 * @param {KComplexInputData} number
	 * @param {KComplexInputData} [tolerance=Number.EPSILON] - Calculation tolerance of calculation.
	 * @returns {number} A > B ? 1 : (A === B ? 0 : -1)
	 */
	compareTo(number, tolerance) {
		const A = this;
		const B = Complex._toComplex(number);
		if(!A.isFinite() || !B.isFinite()) {
			if(A.equals(B)) {
				return 0;
			}
			else if(
				A.isNaN() || B.isNaN() ||
				(A.real ===  Infinity && A.imag === -Infinity) ||
				(A.real === -Infinity && A.imag ===  Infinity) ||
				(B.real ===  Infinity && B.imag === -Infinity) ||
				(B.real === -Infinity && B.imag ===  Infinity) ) {
				return NaN;
			}
			else if(A.isFinite()) {
				return B.real + B.imag < 0 ? 1 : -1;
			}
			else if(B.isFinite()) {
				return A.real + A.imag > 0 ? 1 : -1;
			}
			else {
				return NaN;
			}
		}
		const tolerance_ = tolerance ? Complex._toDouble(tolerance) : Number.EPSILON;
		const a = A.real + A.imag;
		const b = B.real + B.imag;
		if((Math.abs(a - b) <= tolerance_)) {
			return 0;
		}
		return a > b ? 1 : -1;
	}
	
	/**
	 * Maximum number.
	 * @param {KComplexInputData} number
	 * @returns {Complex} max([A, B])
	 */
	max(number) {
		const x = Complex._toComplex(number);
		if(this.compareTo(x) >= 0) {
			return this;
		}
		else {
			return x;
		}
	}

	/**
	 * Minimum number.
	 * @param {KComplexInputData} number
	 * @returns {Complex} min([A, B])
	 */
	min(number) {
		const x = Complex._toComplex(number);
		if(this.compareTo(x) <= 0) {
			return this;
		}
		else {
			return x;
		}
	}

	/**
	 * Clip number within range.
	 * @param {KComplexInputData} min 
	 * @param {KComplexInputData} max
	 * @returns {Complex} min(max(x, min), max)
	 */
	clip(min, max) {
		const min_ = Complex._toComplex(min);
		const max_ = Complex._toComplex(max);
		const arg_check = min_.compareTo(max_);
		if(arg_check === 1) {
			throw "clip(min, max) error. (min > max)->(" + min_ + " > " + max_ + ")";
		}
		else if(arg_check === 0) {
			return min_;
		}
		if(this.compareTo(max_) === 1) {
			return max_;
		}
		else if(this.compareTo(min_) === -1) {
			return min_;
		}
		return this;
	}

	// ----------------------
	// 丸め
	// ----------------------
	
	/**
	 * Floor.
	 * @returns {Complex} floor(A)
	 */
	floor() {
		return new Complex([Math.floor(this._re), Math.floor(this._im)]);
	}

	/**
	 * Ceil.
	 * @returns {Complex} ceil(A)
	 */
	ceil() {
		return new Complex([Math.ceil(this._re), Math.ceil(this._im)]);
	}
	
	/**
	 * Rounding to the nearest integer.
	 * @returns {Complex} round(A)
	 */
	round() {
		return new Complex([Math.round(this._re), Math.round(this._im)]);
	}

	/**
	 * To integer rounded down to the nearest.
	 * @returns {Complex} fix(A), trunc(A)
	 */
	fix() {
		return new Complex([Math.trunc(this._re), Math.trunc(this._im)]);
	}

	/**
	 * Fraction.
	 * @returns {Complex} fract(A)
	 */
	fract() {
		return new Complex([this._re - Math.floor(this._re), this._im - Math.floor(this._im)]);
	}

	// ----------------------
	// 複素数
	// ----------------------
	
	/**
	 * Absolute value.
	 * @returns {Complex} abs(A)
	 */
	abs() {
		return new Complex(this.norm);
	}

	/**
	 * Complex conjugate.
	 * @returns {Complex} real(A) - imag(A)j
	 */
	conj() {
		if(this._im === 0) {
			return this;
		}
		// 共役複素数
		return new Complex([this._re, -this._im]);
	}

	/**
	 * this * -1
	 * @returns {Complex} -A
	 */
	negate() {
		return new Complex([-this._re, -this._im]);
	}

	// ----------------------
	// 指数
	// ----------------------
	
	/**
	 * Power function.
	 * @param {KComplexInputData} number
	 * @returns {Complex} pow(A, B)
	 */
	pow(number) {
		const A = this;
		const B = new Complex(number);
		// -2 ^ 0.5 ... 複素数
		// -2 ^ 1   ... 実数
		//  2 ^ 0.5 ... 実数
		if(B.isReal()) {
			if(A.isReal() && (A.isNotNegative() || B.isInteger())) {
				B._re = Math.pow(A._re, B._re);
				return B;
			}
			else {
				const r = Math.pow(A.norm, B._re);
				const s = A.arg * B._re;
				B._re = r * Math.cos(s);
				B._im = r * Math.sin(s);
				return B;
			}
		}
		else {
			return B.mul(A.log()).exp();
		}
	}

	/**
	 * Square.
	 * @returns {Complex} pow(A, 2)
	 */
	square() {
		if(this._im === 0.0) {
			return new Complex(this._re * this._re);
		}
		return this.mul(this);
	}

	/**
	 * Square root.
	 * @returns {Complex} sqrt(A)
	 */
	sqrt() {
		if(this.isReal()) {
			if(this.isNotNegative()) {
				return new Complex(Math.sqrt(this._re));
			}
			else {
				return new Complex([0, Math.sqrt(-this._re)]);
			}
		}
		const r = Math.sqrt(this.norm);
		const s = this.arg * 0.5;
		return new Complex([r * Math.cos(s), r * Math.sin(s)]);
	}

	/**
	 * Cube root.
	 * @param {KComplexInputData} [n=0] - Value type(0,1,2)
	 * @returns {Complex} cbrt(A)
	 */
	cbrt(n) {
		const type = Complex._toInteger(n !== undefined ? n : 0);
		const x = this.log().div(3).exp();
		if(type === 0) {
			return x;
		}
		else if(type === 1) {
			return x.mul([-0.5, Math.sqrt(3) * 0.5]);
		}
		else {
			return x.mul([-0.5, - Math.sqrt(3) * 0.5]);
		}
	}

	/**
	 * Reciprocal square root.
	 * @returns {Complex} rsqrt(A)
	 */
	rsqrt() {
		if(this.isReal()) {
			if(this.isNotNegative()) {
				return new Complex(1.0 / Math.sqrt(this._re));
			}
			else {
				return new Complex([0, - 1.0 / Math.sqrt(-this._re)]);
			}
		}
		return this.sqrt().inv();
	}

	/**
	 * Logarithmic function.
	 * @returns {Complex} log(A)
	 */
	log() {
		if(this.isReal() && this.isNotNegative()) {
			return new Complex(Math.log(this._re));
		}
		// 負の値が入っているか、もともと複素数が入っている場合は、複素対数関数
		return new Complex([Math.log(this.norm), this.arg]);
	}

	/**
	 * Exponential function.
	 * @returns {Complex} exp(A)
	 */
	exp() {
		if(this.isReal()) {
			return new Complex(Math.exp(this._re));
		}
		// 複素指数関数
		const r = Math.exp(this._re);
		return new Complex([r * Math.cos(this._im), r * Math.sin(this._im)]);
	}

	/**
	 * e^x - 1
	 * @returns {Complex} expm1(A)
	 */
	expm1() {
		return this.exp().sub(1);
	}

	/**
	 * ln(1 + x)
	 * @returns {Complex} log1p(A)
	 */
	log1p() {
		return this.add(1).log();
	}
	
	/**
	 * log_2(x)
	 * @returns {Complex} log2(A)
	 */
	log2() {
		return this.log().div(Complex.LN2);
		
	}

	/**
	 * log_10(x)
	 * @returns {Complex} log10(A)
	 */
	log10() {
		return this.log().div(Complex.LN10);
	}

	// ----------------------
	// 三角関数
	// ----------------------
	
	/**
	 * Sine function.
	 * @returns {Complex} sin(A)
	 */
	sin() {
		if(this.isReal()) {
			return new Complex(Math.sin(this._re));
		}
		// オイラーの公式より
		// sin x = (e^ix - e^-ex) / 2i
		const a = this.mul(Complex.I).exp();
		const b = this.mul(Complex.I.negate()).exp();
		return a.sub(b).div([0, 2]);
	}

	/**
	 * Cosine function.
	 * @returns {Complex} cos(A)
	 */
	cos() {
		if(this.isReal()) {
			return new Complex(Math.cos(this._re));
		}
		// オイラーの公式より
		// cos x = (e^ix + e^-ex) / 2
		const a = this.mul(Complex.I).exp();
		const b = this.mul(Complex.I.negate()).exp();
		return a.add(b).div(2);
	}

	/**
	 * Tangent function.
	 * @returns {Complex} tan(A)
	 */
	tan() {
		if(this.isReal()) {
			return new Complex(Math.tan(this._re));
		}
		// 三角関数の相互関係 tan x = sin x / cos x
		return this.sin().div(this.cos());
	}

	/**
	 * Atan (arc tangent) function.
	 * - Return the values of [-PI/2, PI/2].
	 * @returns {Complex} atan(A)
	 */
	atan() {
		if(this.isReal()) {
			return new Complex(Math.atan(this._re));
		}
		// 逆正接 tan-1 x = i/2 log( i+x / i-x )
		return Complex.I.div(Complex.TWO).mul(Complex.I.add(this).div(Complex.I.sub(this)).log());
	}

	/**
	 * Atan (arc tangent) function.
	 * Return the values of [-PI, PI] .
	 * Supports only real numbers.
	 * @param {KComplexInputData} [number] - X
	 * @returns {Complex} atan2(Y, X)
	 */
	atan2(number) {
		if(arguments.length === 0) {
			return new Complex(this.arg);
		}
		// y.atan2(x) とする。
		const y = this;
		const x = Complex._toComplex(number);
		if(y.isReal() && x.isReal()) {
			return new Complex(Math.atan2(y._re, x._re));
		}
		// 複素数のatan2は未定義である(実装不可能)
		throw "calculation method is undefined.";
	}
	
	// ----------------------
	// 双曲線関数
	// ----------------------
	
	/**
	 * Arc sine function.
	 * @returns {Complex} asin(A)
	 */
	asin() {
		// 逆正弦
		return this.mul(Complex.I).add(Complex.ONE.sub(this.square()).sqrt()).log().mul(Complex.MINUS_I);
	}

	/**
	 * Arc cosine function.
	 * @returns {Complex} acos(A)
	 */
	acos() {
		// 逆余弦
		return this.add(Complex.I.mul(Complex.ONE.sub(this.square()).sqrt())).log().mul(Complex.MINUS_I);
	}
	

	/**
	 * Hyperbolic sine function.
	 * @returns {Complex} sinh(A)
	 */
	sinh() {
		// 双曲線正弦
		const y = this.exp();
		return y.sub(y.inv()).mul(0.5);
	}

	/**
	 * Inverse hyperbolic sine function.
	 * @returns {Complex} asinh(A)
	 */
	asinh() {
		// 逆双曲線正弦 Math.log(x + Math.sqrt(x * x + 1));
		if(this.isInfinite()) {
			return this;
		}
		return this.add(this.mul(this).add(1).sqrt()).log();
	}

	/**
	 * Hyperbolic cosine function.
	 * @returns {Complex} cosh(A)
	 */
	cosh() {
		// 双曲線余弦
		return this.exp().add(this.negate().exp()).mul(0.5);
	}

	/**
	 * Inverse hyperbolic cosine function.
	 * @returns {Complex} acosh(A)
	 */
	acosh() {
		// 逆双曲線余弦 Math.log(x + Math.sqrt(x * x - 1));
		// Octave だと log(0.5+(0.5*0.5-1)^0.5) !== acosh(0.5) になる。
		// おそらく log(0.5-(0.5*0.5-1)^0.5) の式に切り替わるようになっている
		// これは2つの値を持っているためだと思われるので合わせてみる
		if(this.isZero()) {
			return new Complex([0, Math.PI * 0.5]);
		}
		if(this.compareTo(Complex.ONE) >= 1) {
			return this.add(this.square().sub(1).sqrt()).log();
		}
		else {
			return this.sub(this.square().sub(1).sqrt()).log();
		}
	}

	/**
	 * Hyperbolic tangent function.
	 * @returns {Complex} tanh(A)
	 */
	tanh() {
		// 双曲線正接
		if(this.isNaN()) {
			return Complex.NaN;
		}
		const y =  this.mul(2).exp();
		if(y.isZero()) {
			return Complex.MINUS_ONE;
		}
		else if(y.isPositiveInfinity()) {
			return Complex.ONE;
		}
		return y.sub(1).div(y.add(1));
	}
	
	/**
	 * Inverse hyperbolic tangent function.
	 * @returns {Complex} atanh(A)
	 */
	atanh() {
		// 逆双曲線正接
		if(this.isInfinite() && this.isReal()) {
			return new Complex([0, Math.PI * 0.5]);
		}
		return this.add(1).div(this.negate().add(1)).log().mul(0.5);
	}

	/**
	 * Secant function.
	 * @returns {Complex} sec(A)
	 */
	sec() {
		// 正割
		return this.cos().inv();
	}

	/**
	 * Reverse secant function.
	 * @returns {Complex} asec(A)
	 */
	asec() {
		// 逆正割
		return this.inv().acos();
	}

	/**
	 * Hyperbolic secant function.
	 * @returns {Complex} sech(A)
	 */
	sech() {
		// 双曲線正割
		return this.exp().add(this.negate().exp()).inv().mul(2);
	}

	/**
	 * Inverse hyperbolic secant function.
	 * @returns {Complex} asech(A)
	 */
	asech() {
		// 逆双曲線正割
		if(this.isInfinite() && this.isReal()) {
			return new Complex([0, Math.PI * 0.5]);
		}
		if(this.isPositive() || (this.compareTo(Complex.MINUS_ONE) == -1)) {
			return this.inv().add(this.square().inv().sub(1).sqrt()).log();
		}
		else {
			return this.inv().sub(this.square().inv().sub(1).sqrt()).log();
		}
	}

	/**
	 * Cotangent function.
	 * @returns {Complex} cot(A)
	 */
	cot() {
		// 余接
		return this.tan().inv();
	}

	/**
	 * Inverse cotangent function.
	 * @returns {Complex} acot(A)
	 */
	acot() {
		// 逆余接
		return this.inv().atan();
	}

	/**
	 * Hyperbolic cotangent function.
	 * @returns {Complex} coth(A)
	 */
	coth() {
		// 双曲線余接
		if(this.isZero()) {
			return Complex.POSITIVE_INFINITY;
		}
		return this.tanh().inv();
	}

	/**
	 * Inverse hyperbolic cotangent function.
	 * @returns {Complex} acoth(A)
	 */
	acoth() {
		// 逆双曲線余接
		if(this.isInfinite()) {
			return Complex.ZERO;
		}
		return this.add(1).div(this.sub(1)).log().mul(0.5);
	}

	/**
	 * Cosecant function.
	 * @returns {Complex} csc(A)
	 */
	csc() {
		// 余割
		return this.sin().inv();
	}

	/**
	 * Inverse cosecant function.
	 * @returns {Complex} acsc(A)
	 */
	acsc() {
		// 逆余割
		return this.inv().asin();
	}

	/**
	 * Hyperbolic cosecant function.
	 * @returns {Complex} csch(A)
	 */
	csch() {
		// 双曲線余割
		return this.exp().sub(this.negate().exp()).inv().mul(2);
	}

	/**
	 * Inverse hyperbolic cosecant function.
	 * @returns {Complex} acsch(A)
	 */
	acsch() {
		// 逆双曲線余割
		return this.inv().add(this.square().inv().add(1).sqrt()).log();
	}

	// ----------------------
	// 確率・統計系
	// ----------------------
	
	/**
	 * Logit function.
	 * @returns {Complex} logit(A)
	 */
	logit() {
		return this.log().sub(Complex.ONE.sub(this).log());
	}

	// ----------------------
	// 信号処理系
	// ----------------------
	
	/**
	 * Normalized sinc function.
	 * @returns {Complex} sinc(A)
	 */
	sinc() {
		if(this.isReal()) {
			if(this._re === 0) {
				return(Complex.ONE);
			}
			const x = Math.PI * this._re;
			return new Complex(Math.sin(x) / x);
		}
		const x = this.mul(Complex.PI);
		return new Complex( x.sin().div(x) );
	}

	// ----------------------
	// 乱数
	// ----------------------
	
	/**
	 * Create random values [0, 1) with uniform random numbers.
	 * @param {Random} [random] - Class for creating random numbers.
	 * @returns {Complex}
	 */
	static rand(random) {
		const rand = (random !== undefined && random instanceof Random) ? random : random_class;
		return new Complex(rand.nextDouble());
	}

	/**
	 * Create random values with normal distribution.
	 * @param {Random} [random] - Class for creating random numbers.
	 * @returns {Complex}
	 */
	static randn(random) {
		const rand = (random !== undefined && random instanceof Random) ? random : random_class;
		return new Complex(rand.nextGaussian());
	}

	// ----------------------
	// テスト系
	// ----------------------
	
	/**
	 * Return true if the value is integer.
	 * @param {KComplexInputData} [tolerance=Number.EPSILON] - Calculation tolerance of calculation.
	 * @returns {boolean}
	 */
	isInteger(tolerance) {
		const tolerance_ = tolerance ? Complex._toDouble(tolerance) : Number.EPSILON;
		return this.isReal() && (Math.abs(this._re - Math.trunc(this._re)) < tolerance_);
	}

	/**
	 * Returns true if the vallue is complex integer (including normal integer).
	 * @param {KComplexInputData} [tolerance=Number.EPSILON] - Calculation tolerance of calculation.
	 * @returns {boolean} real(A) === integer && imag(A) === integer
	 */
	isComplexInteger(tolerance) {
		const tolerance_ = tolerance ? Complex._toDouble(tolerance) : Number.EPSILON;
		// 複素整数
		return (Math.abs(this._re - Math.trunc(this._re)) < tolerance_) &&
				(Math.abs(this._im - Math.trunc(this._im)) < tolerance_);
	}

	/**
	 * this === 0
	 * @param {KComplexInputData} [tolerance=Number.EPSILON] - Calculation tolerance of calculation.
	 * @returns {boolean} A === 0
	 */
	isZero(tolerance) {
		const tolerance_ = tolerance ? Complex._toDouble(tolerance) : Number.EPSILON;
		return (Math.abs(this._re) < tolerance_) && (Math.abs(this._im) < tolerance_);
	}

	/**
	 * this === 1
	 * @param {KComplexInputData} [tolerance=Number.EPSILON] - Calculation tolerance of calculation.
	 * @returns {boolean} A === 1
	 */
	isOne(tolerance) {
		const tolerance_ = tolerance ? Complex._toDouble(tolerance) : Number.EPSILON;
		return (Math.abs(this._re - 1.0) < tolerance_) && (Math.abs(this._im) < tolerance_);
	}

	/**
	 * Returns true if the vallue is complex number (imaginary part is not 0).
	 * @param {KComplexInputData} [tolerance=Number.EPSILON] - Calculation tolerance of calculation.
	 * @returns {boolean} imag(A) !== 0
	 */
	isComplex(tolerance) {
		const tolerance_ = tolerance ? Complex._toDouble(tolerance) : Number.EPSILON;
		return (Math.abs(this._im) >= tolerance_);
	}
	
	/**
	 * Return true if the value is real number.
	 * @param {KComplexInputData} [tolerance=Number.EPSILON] - Calculation tolerance of calculation.
	 * @returns {boolean} imag(A) === 0
	 */
	isReal(tolerance) {
		const tolerance_ = tolerance ? Complex._toDouble(tolerance) : Number.EPSILON;
		return (Math.abs(this._im) < tolerance_);
	}

	/**
	 * this === NaN
	 * @returns {boolean} isNaN(A)
	 */
	isNaN() {
		return isNaN(this._re) || isNaN(this._im);
	}

	/**
	 * Return true if this real part of the complex positive.
	 * @returns {boolean} real(x) > 0
	 */
	isPositive() {
		// Number.EPSILONは使用しない。どちらにぶれるか不明な点及び
		// わずかな負の数だった場合に、sqrtでエラーが発生するため
		return 0.0 < this._re;
	}

	/**
	 * real(this) < 0
	 * @returns {boolean} real(x) < 0
	 */
	isNegative() {
		return 0.0 > this._re;
	}

	/**
	 * real(this) >= 0
	 * @returns {boolean} real(x) >= 0
	 */
	isNotNegative() {
		return 0.0 <= this._re;
	}

	/**
	 * this === Infinity
	 * @returns {boolean} isPositiveInfinity(A)
	 */
	isPositiveInfinity() {
		return this._re === Number.POSITIVE_INFINITY || this._im === Number.POSITIVE_INFINITY;
	}

	/**
	 * this === -Infinity
	 * @returns {boolean} isNegativeInfinity(A)
	 */
	isNegativeInfinity() {
		return this._re === Number.NEGATIVE_INFINITY || this._im === Number.NEGATIVE_INFINITY;
	}

	/**
	 * this === Infinity or -Infinity
	 * @returns {boolean} isPositiveInfinity(A) || isNegativeInfinity(A)
	 */
	isInfinite() {
		return this.isPositiveInfinity() || this.isNegativeInfinity();
	}
	
	/**
	 * Return true if the value is finite number.
	 * @returns {boolean} !isNaN(A) && !isInfinite(A)
	 */
	isFinite() {
		return !this.isNaN() && !this.isInfinite();
	}

	// ----------------------
	// 確率
	// ----------------------
	
	/**
	 * Log-gamma function.
	 * - Calculate from real values.
	 * @returns {Complex}
	 */
	gammaln() {
		return new Complex(Probability.gammaln(this._re));
	}
	
	/**
	 * Gamma function.
	 * - Calculate from real values.
	 * @returns {Complex}
	 */
	gamma() {
		return new Complex(Probability.gamma(this._re));
	}
	
	/**
	 * Incomplete gamma function.
	 * - Calculate from real values.
	 * @param {KComplexInputData} a
	 * @param {string} [tail="lower"] - lower (default) , "upper"
	 * @returns {Complex}
	 */
	gammainc(a, tail) {
		const a_ = Complex._toDouble(a);
		return new Complex(Probability.gammainc(this._re, a_, tail));
	}

	/**
	 * Probability density function (PDF) of the gamma distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} k - Shape parameter.
	 * @param {KComplexInputData} s - Scale parameter.
	 * @returns {Complex}
	 */
	gampdf(k, s) {
		const k_ = Complex._toDouble(k);
		const s_ = Complex._toDouble(s);
		return new Complex(Probability.gampdf(this._re, k_, s_));
	}

	/**
	 * Cumulative distribution function (CDF) of gamma distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} k - Shape parameter.
	 * @param {KComplexInputData} s - Scale parameter.
	 * @returns {Complex}
	 */
	gamcdf(k, s) {
		const k_ = Complex._toDouble(k);
		const s_ = Complex._toDouble(s);
		return new Complex(Probability.gamcdf(this._re, k_, s_));
	}

	/**
	 * Inverse function of cumulative distribution function (CDF) of gamma distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} k - Shape parameter.
	 * @param {KComplexInputData} s - Scale parameter.
	 * @returns {Complex}
	 */
	gaminv(k, s) {
		const k_ = Complex._toDouble(k);
		const s_ = Complex._toDouble(s);
		return new Complex(Probability.gaminv(this._re, k_, s_));
	}

	/**
	 * Beta function.
	 * - Calculate from real values.
	 * @param {KComplexInputData} y
	 * @returns {Complex}
	 */
	beta(y) {
		const y_ = Complex._toDouble(y);
		return new Complex(Probability.beta(this._re, y_));
	}

	/**
	 * Incomplete beta function.
	 * - Calculate from real values.
	 * @param {KComplexInputData} a
	 * @param {KComplexInputData} b
	 * @param {string} [tail="lower"] - lower (default) , "upper"
	 * @returns {Complex}
	 */
	betainc(a, b, tail) {
		const a_ = Complex._toDouble(a);
		const b_ = Complex._toDouble(b);
		return new Complex(Probability.betainc(this._re, a_, b_, tail));
	}

	/**
	 * Probability density function (PDF) of beta distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} a
	 * @param {KComplexInputData} b
	 * @returns {Complex}
	 */
	betapdf(a, b) {
		const a_ = Complex._toDouble(a);
		const b_ = Complex._toDouble(b);
		return new Complex(Probability.betapdf(this._re, a_, b_));
	}

	/**
	 * Cumulative distribution function (CDF) of beta distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} a
	 * @param {KComplexInputData} b
	 * @returns {Complex}
	 */
	betacdf(a, b) {
		const a_ = Complex._toDouble(a);
		const b_ = Complex._toDouble(b);
		return new Complex(Probability.betacdf(this._re, a_, b_));
	}

	/**
	 * Inverse function of cumulative distribution function (CDF) of beta distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} a
	 * @param {KComplexInputData} b
	 * @returns {Complex}
	 */
	betainv(a, b) {
		const a_ = Complex._toDouble(a);
		const b_ = Complex._toDouble(b);
		return new Complex(Probability.betainv(this._re, a_, b_));
	}

	/**
	 * Factorial function, x!.
	 * - Calculate from real values.
	 * @returns {Complex}
	 */
	factorial() {
		return new Complex(Probability.factorial(this._re));
	}

	/**
	 * Binomial coefficient, number of all combinations, nCk.
	 * - Calculate from real values.
	 * @param {KComplexInputData} k
	 * @returns {Complex}
	 */
	nchoosek(k) {
		const k_ = Complex._toDouble(k);
		return new Complex(Probability.nchoosek(this._re, k_));
	}
	
	/**
	 * Error function.
	 * - Calculate from real values.
	 * @returns {Complex}
	 */
	erf() {
		return new Complex(Probability.erf(this._re));
	}

	/**
	 * Complementary error function.
	 * - Calculate from real values.
	 * @returns {Complex}
	 */
	erfc() {
		return new Complex(Probability.erfc(this._re));
	}

	/**
	 * Inverse function of Error function.
	 * - Calculate from real values.
	 * @returns {Complex}
	 */
	erfinv() {
		return new Complex(Probability.erfinv(this._re));
	}

	/**
	 * Inverse function of Complementary error function.
	 * - Calculate from real values.
	 * @returns {Complex}
	 */
	erfcinv() {
		return new Complex(Probability.erfcinv(this._re));
	}

	/**
	 * Probability density function (PDF) of normal distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} [u=0.0] - Average value.
	 * @param {KComplexInputData} [s=1.0] - Variance value.
	 * @returns {Complex}
	 */
	normpdf(u, s) {
		const u_ = u !== undefined ? Complex._toDouble(u) : 0.0;
		const s_ = s !== undefined ? Complex._toDouble(s) : 1.0;
		return new Complex(Probability.normpdf(this._re, u_, s_));
	}

	/**
	 * Cumulative distribution function (CDF) of normal distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} [u=0.0] - Average value.
	 * @param {KComplexInputData} [s=1.0] - Variance value.
	 * @returns {Complex}
	 */
	normcdf(u, s) {
		const u_ = u !== undefined ? Complex._toDouble(u) : 0.0;
		const s_ = s !== undefined ? Complex._toDouble(s) : 1.0;
		return new Complex(Probability.normcdf(this._re, u_, s_));
	}

	/**
	 * Inverse function of cumulative distribution function (CDF) of normal distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} [u=0.0] - Average value.
	 * @param {KComplexInputData} [s=1.0] - Variance value.
	 * @returns {Complex}
	 */
	norminv(u, s) {
		const u_ = u !== undefined ? Complex._toDouble(u) : 0.0;
		const s_ = s !== undefined ? Complex._toDouble(s) : 1.0;
		return new Complex(Probability.norminv(this._re, u_, s_));
	}
	
	/**
	 * Probability density function (PDF) of binomial distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} n
	 * @param {KComplexInputData} p
	 * @returns {Complex}
	 */
	binopdf(n, p) {
		const n_ = Complex._toDouble(n);
		const p_ = Complex._toDouble(p);
		return new Complex(Probability.binopdf(this._re, n_, p_));
	}

	/**
	 * Cumulative distribution function (CDF) of binomial distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} n
	 * @param {KComplexInputData} p
	 * @param {string} [tail="lower"] - lower (default) , "upper"
	 * @returns {Complex}
	 */
	binocdf(n, p, tail) {
		const n_ = Complex._toDouble(n);
		const p_ = Complex._toDouble(p);
		return new Complex(Probability.binocdf(this._re, n_, p_, tail));
	}

	/**
	 * Inverse function of cumulative distribution function (CDF) of binomial distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} n
	 * @param {KComplexInputData} p
	 * @returns {Complex}
	 */
	binoinv(n, p) {
		const n_ = Complex._toDouble(n);
		const p_ = Complex._toDouble(p);
		return new Complex(Probability.binoinv(this._re, n_, p_));
	}

	/**
	 * Probability density function (PDF) of Poisson distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} lambda
	 * @returns {Complex}
	 */
	poisspdf(lambda) {
		const lambda_ = Complex._toDouble(lambda);
		return new Complex(Probability.poisspdf(this._re, lambda_));
	}

	/**
	 * Cumulative distribution function (CDF) of Poisson distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} lambda
	 * @returns {Complex}
	 */
	poisscdf(lambda) {
		const lambda_ = Complex._toDouble(lambda);
		return new Complex(Probability.poisscdf(this._re, lambda_));
	}

	/**
	 * Inverse function of cumulative distribution function (CDF) of Poisson distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} lambda
	 * @returns {Complex}
	 */
	poissinv(lambda) {
		const lambda_ = Complex._toDouble(lambda);
		return new Complex(Probability.poissinv(this._re, lambda_));
	}

	/**
	 * Probability density function (PDF) of Student's t-distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} v - The degrees of freedom. (DF)
	 * @returns {Complex}
	 */
	tpdf(v) {
		const v_ = Complex._toDouble(v);
		return new Complex(Probability.tpdf(this._re, v_));
	}

	/**
	 * Cumulative distribution function (CDF) of Student's t-distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} v - The degrees of freedom. (DF)
	 * @returns {Complex}
	 */
	tcdf(v) {
		const v_ = Complex._toDouble(v);
		return new Complex(Probability.tcdf(this._re, v_));
	}

	/**
	 * Inverse of cumulative distribution function (CDF) of Student's t-distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} v - The degrees of freedom. (DF)
	 * @returns {Complex}
	 */
	tinv(v) {
		const v_ = Complex._toDouble(v);
		return new Complex(Probability.tinv(this._re, v_));
	}

	/**
	 * Cumulative distribution function (CDF) of Student's t-distribution that can specify tail.
	 * - Calculate from real values.
	 * @param {KComplexInputData} v - The degrees of freedom. (DF)
	 * @param {KComplexInputData} tails - Tail. (1 = the one-tailed distribution, 2 =  the two-tailed distribution.)
	 * @returns {Complex}
	 */
	tdist(v, tails) {
		const v_ = Complex._toDouble(v);
		const tails_ = Complex._toInteger(tails);
		return new Complex(Probability.tdist(this._re, v_, tails_));
	}

	/**
	 * Inverse of cumulative distribution function (CDF) of Student's t-distribution in two-sided test.
	 * - Calculate from real values.
	 * @param {KComplexInputData} v - The degrees of freedom. (DF)
	 * @returns {Complex}
	 */
	tinv2(v) {
		const v_ = Complex._toDouble(v);
		return new Complex(Probability.tinv2(this._re, v_));
	}

	/**
	 * Probability density function (PDF) of chi-square distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} k - The degrees of freedom. (DF)
	 * @returns {Complex}
	 */
	chi2pdf(k) {
		const k_ = Complex._toDouble(k);
		return new Complex(Probability.chi2pdf(this._re, k_));
	}

	/**
	 * Cumulative distribution function (CDF) of chi-square distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} k - The degrees of freedom. (DF)
	 * @returns {Complex}
	 */
	chi2cdf(k) {
		const k_ = Complex._toDouble(k);
		return new Complex(Probability.chi2cdf(this._re, k_));
	}

	/**
	 * Inverse function of cumulative distribution function (CDF) of chi-square distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} k - The degrees of freedom. (DF)
	 * @returns {Complex}
	 */
	chi2inv(k) {
		const k_ = Complex._toDouble(k);
		return new Complex(Probability.chi2inv(this._re, k_));
	}

	/**
	 * Probability density function (PDF) of F-distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} d1 - The degree of freedom of the molecules.
	 * @param {KComplexInputData} d2 - The degree of freedom of the denominator
	 * @returns {Complex}
	 */
	fpdf(d1, d2) {
		const d1_ = Complex._toDouble(d1);
		const d2_ = Complex._toDouble(d2);
		return new Complex(Probability.fpdf(this._re, d1_, d2_));
	}

	/**
	 * Cumulative distribution function (CDF) of F-distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} d1 - The degree of freedom of the molecules.
	 * @param {KComplexInputData} d2 - The degree of freedom of the denominator
	 * @returns {Complex}
	 */
	fcdf(d1, d2) {
		const d1_ = Complex._toDouble(d1);
		const d2_ = Complex._toDouble(d2);
		return new Complex(Probability.fcdf(this._re, d1_, d2_));
	}

	/**
	 * Inverse function of cumulative distribution function (CDF) of F-distribution.
	 * - Calculate from real values.
	 * @param {KComplexInputData} d1 - The degree of freedom of the molecules.
	 * @param {KComplexInputData} d2 - The degree of freedom of the denominator
	 * @returns {Complex}
	 */
	finv(d1, d2) {
		const d1_ = Complex._toDouble(d1);
		const d2_ = Complex._toDouble(d2);
		return new Complex(Probability.finv(this._re, d1_, d2_));
	}

	// ----------------------
	// ビット演算系
	// ----------------------
	
	/**
	 * Logical AND.
	 * - Calculated as an integer.
	 * @param {KComplexInputData} number 
	 * @returns {Complex} A & B
	 */
	and(number) {
		const n_src = Math.round(this.real);
		const n_tgt = Math.round(Complex._toDouble(number));
		return new Complex(n_src & n_tgt);
	}

	/**
	 * Logical OR.
	 * - Calculated as an integer.
	 * @param {KComplexInputData} number 
	 * @returns {Complex} A | B
	 */
	or(number) {
		const n_src = Math.round(this.real);
		const n_tgt = Math.round(Complex._toDouble(number));
		return new Complex(n_src | n_tgt);
	}

	/**
	 * Logical Exclusive-OR.
	 * - Calculated as an integer.
	 * @param {KComplexInputData} number 
	 * @returns {Complex} A ^ B
	 */
	xor(number) {
		const n_src = Math.round(this.real);
		const n_tgt = Math.round(Complex._toDouble(number));
		return new Complex(n_src ^ n_tgt);
	}

	/**
	 * Logical Not. (mutable)
	 * - Calculated as an integer.
	 * @returns {Complex} !A
	 */
	not() {
		const n_src = Math.round(this.real);
		return new Complex(!n_src);
	}
	
	/**
	 * this << n
	 * - Calculated as an integer.
	 * @param {KComplexInputData} n
	 * @returns {Complex} A << n
	 */
	shift(n) {
		const src = Math.round(this.real);
		const number = Math.round(Complex._toDouble(n));
		return new Complex(src << number);
	}

	// ----------------------
	// factor
	// ----------------------

	/**
	 * Factorization.
	 * - Calculated as an integer.
	 * - Calculate up to `9007199254740991`.
	 * @returns {Complex[]} factor
	 */
	factor() {
		const x = this.round().toBigInteger().factor();
		const y = [];
		for(let i = 0; i < x.length; i++) {
			y.push(new Complex(x[i]));
		}
		return y;
	}

	// ----------------------
	// gcd, lcm
	// ----------------------
	
	/**
	 * Euclidean algorithm.
	 * - Calculated as an integer.
	 * @param {KComplexInputData} number 
	 * @returns {Complex} gcd(x, y)
	 */
	gcd(number) {
		const x = Math.round(this.real);
		const y = Math.round(Complex._toDouble(number));
		const result = new BigInteger(x).gcd(y);
		return new Complex(result);
	}

	/**
	 * Extended Euclidean algorithm.
	 * - Calculated as an integer.
	 * @param {KComplexInputData} number 
	 * @returns {Array<Complex>} [a, b, gcd(x, y)], Result of calculating a*x + b*y = gcd(x, y).
	 */
	extgcd(number) {
		const x = Math.round(this.real);
		const y = Math.round(Complex._toDouble(number));
		const result = new BigInteger(x).extgcd(y);
		return [new Complex(result[0]), new Complex(result[1]), new Complex(result[2])];
	}

	/**
	 * Least common multiple.
	 * - Calculated as an integer.
	 * @param {KComplexInputData} number 
	 * @returns {Complex} lcm(x, y)
	 */
	lcm(number) {
		const x = Math.round(this.real);
		const y = Math.round(Complex._toDouble(number));
		const result = new BigInteger(x).lcm(y);
		return new Complex(result);
	}

	// ----------------------
	// mod
	// ----------------------

	/**
	 * Modular exponentiation.
	 * - Calculated as an integer.
	 * @param {KComplexInputData} exponent
	 * @param {KComplexInputData} m 
	 * @returns {Complex} A^B mod m
	 */
	modPow(exponent, m) {
		const A = Math.round(this.real);
		const B = Math.round(Complex._toDouble(exponent));
		const m_ = Math.round(Complex._toDouble(m));
		const result = new BigInteger(A).modPow(B, m_);
		return new Complex(result);
	}

	/**
	 * Modular multiplicative inverse.
	 * - Calculated as an integer.
	 * @param {KComplexInputData} m
	 * @returns {Complex} A^(-1) mod m
	 */
	modInverse(m) {
		const A = Math.round(this.real);
		const m_ = Math.round(Complex._toDouble(m));
		const result = new BigInteger(A).modInverse(m_);
		return new Complex(result);
	}
	
	// ----------------------
	// その他の演算
	// ----------------------
	
	/**
	 * Multiply a multiple of ten.
	 * @param {KComplexInputData} n
	 * @returns {Complex} x * 10^n
	 */
	scaleByPowerOfTen(n) {
		return this.mul(Complex.TEN.pow(n));
	}

	// ----------------------
	// 素数
	// ----------------------
	
	/**
	 * Return true if the value is prime number.
	 * - Calculated as an integer.
	 * - Calculate up to `9007199254740991`.
	 * @returns {boolean} - If the calculation range is exceeded, null is returned.
	 */
	isPrime() {
		const src = new BigInteger(Math.round(this.real));
		return src.isPrime();
	}
	
	/**
	 * Return true if the value is prime number by Miller-Labin prime number determination method.
	 * 
	 * Attention : it takes a very long time to process.
	 * - Calculated as an integer.
	 * @param {KComplexInputData} [certainty=100] - Repeat count (prime precision).
	 * @returns {boolean}
	 */
	isProbablePrime(certainty) {
		const src = new BigInteger(Math.round(this.real));
		return src.isProbablePrime(certainty !== undefined ? Math.round(Complex._toDouble(certainty)) : undefined);
	}

	/**
	 * Next prime.
	 * @param {KComplexInputData} [certainty=100] - Repeat count (prime precision).
	 * @param {KComplexInputData} [search_max=100000] - Search range of next prime.
	 * @returns {Complex}
	 */
	nextProbablePrime(certainty, search_max) {
		const src = new BigInteger(Math.round(this.real));
		const p1 = certainty !== undefined ? Math.round(Complex._toDouble(certainty)) : undefined;
		const p2 = search_max !== undefined ? Math.round(Complex._toDouble(search_max)) : undefined;
		return new Complex(src.nextProbablePrime(p1, p2));
	}

	// ----------------------
	// 定数
	// ----------------------
	
	/**
	 * 1
	 * @returns {Complex} 1
	 */
	static get ONE() {
		return DEFINE.ONE;
	}
	
	/**
	 * 2
	 * @returns {Complex} 2
	 */
	static get TWO() {
		return DEFINE.TWO;
	}
	
	/**
	 * 10
	 * @returns {Complex} 10
	 */
	static get TEN() {
		return DEFINE.TEN;
	}
	
	/**
	 * 0
	 * @returns {Complex} 0
	 */
	static get ZERO() {
		return DEFINE.ZERO;
	}

	/**
	 * -1
	 * @returns {Complex} -1
	 */
	static get MINUS_ONE() {
		return DEFINE.MINUS_ONE;
	}

	/**
	 * i, j
	 * @returns {Complex} i
	 */
	static get I() {
		return DEFINE.I;
	}

	/**
	 * - i, - j
	 * @returns {Complex} - i
	 */
	static get MINUS_I() {
		return DEFINE.MINUS_I;
	}

	/**
	 * PI.
	 * @returns {Complex} 3.14...
	 */
	static get PI() {
		return DEFINE.PI;
	}

	/**
	 * 0.25 * PI.
	 * @returns {Complex} 0.78...
	 */
	static get QUARTER_PI() {
		return DEFINE.QUARTER_PI;
	}

	/**
	 * 0.5 * PI.
	 * @returns {Complex} 1.57...
	 */
	static get HALF_PI() {
		return DEFINE.HALF_PI;
	}

	/**
	 * 2 * PI.
	 * @returns {Complex} 6.28...
	 */
	static get TWO_PI() {
		return DEFINE.TWO_PI;
	}

	/**
	 * E, Napier's constant.
	 * @returns {Complex} 2.71...
	 */
	static get E() {
		return DEFINE.E;
	}

	/**
	 * log_e(2)
	 * @returns {Complex} ln(2)
	 */
	static get LN2() {
		return DEFINE.LN2;
	}

	/**
	 * log_e(10)
	 * @returns {Complex} ln(10)
	 */
	static get LN10() {
		return DEFINE.LN10;
	}

	/**
	 * log_2(e)
	 * @returns {Complex} log_2(e)
	 */
	static get LOG2E() {
		return DEFINE.LOG2E;
	}
	
	/**
	 * log_10(e)
	 * @returns {Complex} log_10(e)
	 */
	static get LOG10E() {
		return DEFINE.LOG10E;
	}
	
	/**
	 * sqrt(2)
	 * @returns {Complex} sqrt(2)
	 */
	static get SQRT2() {
		return DEFINE.SQRT2;
	}
	
	/**
	 * sqrt(0.5)
	 * @returns {Complex} sqrt(0.5)
	 */
	static get SQRT1_2() {
		return DEFINE.SQRT1_2;
	}
	
	/**
	 * 0.5
	 * @returns {Complex} 0.5
	 */
	static get HALF() {
		return DEFINE.HALF;
	}

	/**
	 * Positive infinity.
	 * @returns {Complex} Infinity
	 */
	static get POSITIVE_INFINITY() {
		return DEFINE.POSITIVE_INFINITY;
	}
	
	/**
	 * Negative Infinity.
	 * @returns {Complex} -Infinity
	 */
	static get NEGATIVE_INFINITY() {
		return DEFINE.NEGATIVE_INFINITY;
	}

	/**
	 * Not a Number.
	 * @returns {Complex} NaN
	 */
	static get NaN() {
		return DEFINE.NaN;
	}

	// ----------------------
	// 互換性
	// ----------------------
	
	/**
	 * The positive or negative sign of this number.
	 * - +1 if positive, -1 if negative, 0 if 0.
	 * @returns {Complex}
	 */
	signum() {
		return this.sign();
	}

	/**
	 * Subtract.
	 * @param {KComplexInputData} number
	 * @returns {Complex} A - B
	 */
	subtract(number) {
		return this.sub(number);
	}

	/**
	 * Multiply.
	 * @param {KComplexInputData} number
	 * @returns {Complex} A * B
	 */
	multiply(number) {
		return this.mul(number);
	}

	/**
	 * Divide.
	 * @param {KComplexInputData} number
	 * @returns {Complex} fix(A / B)
	 */
	divide(number) {
		return this.div(number);
	}

	/**
	 * Remainder of division.
	 * - Result has same sign as the Dividend.
	 * @param {KComplexInputData} number
	 * @returns {Complex} A % B
	 */
	remainder(number) {
		return this.rem(number);
	}
	
	/**
	 * To integer rounded down to the nearest.
	 * @returns {Complex} fix(A), trunc(A)
	 */
	trunc() {
		return this.fix();
	}
	
}

/**
 * Collection of constant values used in the class.
 * @ignore
 */
const DEFINE = {

	/**
	 * 0
	 */
	ZERO : new Complex(0),

	/**
	 * 1
	 */
	ONE : new Complex(1),

	/**
	 * 2
	 */
	TWO : new Complex(2),

	/**
	 * 10
	 */
	TEN : new Complex(10),

	/**
	 * -1
	 */
	MINUS_ONE : new Complex(-1),

	/**
	 * i, j
	 */
	I : new Complex([0, 1]),

	/**
	 * - i, - j
	 */
	MINUS_I : new Complex([0, -1]),

	/**
	 * PI.
	 */
	PI : new Complex(Math.PI),

	/**
	 * 0.25 * PI.
	 */
	QUARTER_PI : new Complex(0.25 * Math.PI),

	/**
	 * 0.5 * PI.
	 */
	HALF_PI : new Complex(0.5 * Math.PI),

	/**
	 * 2 * PI.
	 */
	TWO_PI : new Complex(2.0 * Math.PI),

	/**
	 * E, Napier's constant.
	 */
	E : new Complex(Math.E),

	/**
	 * log_e(2)
	 */
	LN2 : new Complex(Math.LN2),

	/**
	 * log_e(10)
	 */
	LN10 : new Complex(Math.LN10),

	/**
	 * log_2(e)
	 */
	LOG2E : new Complex(Math.LOG2E),

	/**
	 * log_10(e)
	 */
	LOG10E : new Complex(Math.LOG10E),

	/**
	 * sqrt(2)
	 */
	SQRT2 : new Complex(Math.SQRT2),

	/**
	 * sqrt(0.5)
	 */
	SQRT1_2 : new Complex(Math.SQRT1_2),

	/**
	 * 0.5
	 */
	HALF : new Complex(0.5),

	/**
	 * Positive infinity.
	 */
	POSITIVE_INFINITY : new Complex(Number.POSITIVE_INFINITY),

	/**
	 * Negative Infinity.
	 */
	NEGATIVE_INFINITY : new Complex(Number.NEGATIVE_INFINITY),

	/**
	 * Not a Number.
	 */
	NaN : new Complex(Number.NaN)
};