mirror of
				https://scm.univ-tours.fr/22107988t/rappaurio-sae501_502.git
				synced 2025-11-04 05:25:22 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			647 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			647 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
 | 
						||
/**
 | 
						||
 * @name	CeL quadratic irrational function
 | 
						||
 * @fileoverview
 | 
						||
 * 本檔案包含了二次無理數 (quadratic irrational, quadratic irquadratic, also known as a quadratic irquadraticity or quadratic surd) 的 functions。<br />
 | 
						||
 * TODO: 可充作 Gaussian rational (簡易 complex number)、Gaussian integer、Eisenstein integer、dual number、split-complex numbers。<br />
 | 
						||
 * 在純 javascript 的環境下,藉由原生計算功能,盡可能提供高效的大數計算。<br />
 | 
						||
 *
 | 
						||
 * @example
 | 
						||
 * <code>
 | 
						||
 * CeL.run('data.math.quadratic');
 | 
						||
 * </code>
 | 
						||
 *
 | 
						||
 * @since	2013/11/8 18:16:52
 | 
						||
 * @see
 | 
						||
 * https://en.wikipedia.org/wiki/Quadratic_irrational
 | 
						||
 */
 | 
						||
 | 
						||
 | 
						||
/*
 | 
						||
TODO:
 | 
						||
 | 
						||
https://en.wikipedia.org/wiki/Quadratic_integer
 | 
						||
https://en.wikipedia.org/wiki/Quadratic_field
 | 
						||
 | 
						||
√∛∜
 | 
						||
 | 
						||
*/
 | 
						||
 | 
						||
 | 
						||
'use strict';
 | 
						||
if (typeof CeL === 'function')
 | 
						||
	CeL.run(
 | 
						||
	{
 | 
						||
		name: 'data.math.quadratic',
 | 
						||
		require: 'data.code.compatibility.|data.native.|data.math.quadratic_to_continued_fraction|data.math.integer.',
 | 
						||
		no_extend: 'random,compare',
 | 
						||
		code: function (library_namespace) {
 | 
						||
 | 
						||
			//	requiring
 | 
						||
			var quadratic_to_continued_fraction = this.r('quadratic_to_continued_fraction'),
 | 
						||
			//
 | 
						||
			Integer = library_namespace.data.math.integer;
 | 
						||
 | 
						||
			// ---------------------------------------------------------------------//
 | 
						||
			// basic constants. 定義基本常數。
 | 
						||
 | 
						||
			var
 | 
						||
 | 
						||
			// copy from data.math
 | 
						||
			MULTIPLICATIVE_IDENTITY = library_namespace.MULTIPLICATIVE_IDENTITY,
 | 
						||
			// copy from data.math
 | 
						||
			ZERO_EXPONENT = library_namespace.ZERO_EXPONENT,
 | 
						||
 | 
						||
			// copy from data.math.integer, data.math.rational.
 | 
						||
 | 
						||
			// Quadratic = (integer + multiplier × √radicand) / denominator
 | 
						||
			//{Integer}square-free integer
 | 
						||
			KEY_RADICAND = 'radicand',
 | 
						||
			//{Integer}
 | 
						||
			KEY_MULTIPLIER = 'multiplier',
 | 
						||
			//{Integer}
 | 
						||
			KEY_INTEGER = 'integer',
 | 
						||
			//{Integer|Undefined}integer > 0
 | 
						||
			KEY_DENOMINATOR = 'denominator',
 | 
						||
			//{Boolean|Undefined}最簡, GCD(multiplier, integer, denominator) = 1
 | 
						||
			KEY_IRREDUCIBLE = 'irreducible'
 | 
						||
			;
 | 
						||
 | 
						||
			// ---------------------------------------------------------------------//
 | 
						||
			// 初始調整並規範基本常數。
 | 
						||
 | 
						||
 | 
						||
			// ---------------------------------------------------------------------//
 | 
						||
			// 工具函數
 | 
						||
 | 
						||
			function do_modified(quadratic, not_amount) {
 | 
						||
				if (!not_amount)
 | 
						||
					delete quadratic[KEY_IRREDUCIBLE];
 | 
						||
			}
 | 
						||
 | 
						||
 | 
						||
			// ---------------------------------------------------------------------//
 | 
						||
			//	definition of module integer
 | 
						||
 | 
						||
			/**
 | 
						||
			 * 任意大小、帶正負號的有理數。quadratic irrational number instance.<br />
 | 
						||
			 *
 | 
						||
			 * @example
 | 
						||
			 * <code>
 | 
						||
			 * </code>
 | 
						||
			 *
 | 
						||
			 * @class	Quadratic 的 constructor
 | 
						||
			 * @constructor
 | 
						||
			 */
 | 
						||
			function Quadratic(number) {
 | 
						||
				if (!(this instanceof Quadratic))
 | 
						||
					return 1 === arguments.length && is_Quadratic(number) ? number
 | 
						||
					//
 | 
						||
					: assignment.apply(new Quadratic, 1 === arguments.length && (typeof number === 'number' || Integer.is_Integer(number)) ? [1, 0, number] : arguments);
 | 
						||
 | 
						||
				if (arguments.length > 0)
 | 
						||
					assignment.apply(this, arguments);
 | 
						||
				else
 | 
						||
					;
 | 
						||
			}
 | 
						||
 | 
						||
			//	instance public interface	-------------------
 | 
						||
 | 
						||
			// https://en.wikipedia.org/wiki/Operation_(mathematics)
 | 
						||
			var OP_REFERENCE = {
 | 
						||
				'+': add,
 | 
						||
				'-': subtract,
 | 
						||
				'*': multiply,
 | 
						||
				'/': divide,
 | 
						||
				'^': power,
 | 
						||
				'=': assignment,
 | 
						||
				'==': compare
 | 
						||
			};
 | 
						||
 | 
						||
			Object.assign(Quadratic.prototype, OP_REFERENCE, {
 | 
						||
				reduce_factor: reduce_factor,
 | 
						||
				// 下面全部皆為 assignment,例如 '+' 實為 '+='。
 | 
						||
				assignment: assignment,
 | 
						||
 | 
						||
				// add_assignment
 | 
						||
				add: add,
 | 
						||
				// subtract_assignment
 | 
						||
				subtract: subtract,
 | 
						||
				// multiply_assignment
 | 
						||
				multiply: multiply,
 | 
						||
				// divide_assignment
 | 
						||
				divide: divide,
 | 
						||
				div: divide,
 | 
						||
 | 
						||
				power: power,
 | 
						||
				pow: power,
 | 
						||
				square: square,
 | 
						||
 | 
						||
				conjugate: conjugate,
 | 
						||
				reciprocal: reciprocal,
 | 
						||
				// 至此為 assignment。
 | 
						||
 | 
						||
				clone: clone,
 | 
						||
 | 
						||
				abs: abs,
 | 
						||
				// 變換正負號。
 | 
						||
				negate: function () {
 | 
						||
					do_modified(this, true);
 | 
						||
					this[KEY_INTEGER].negate();
 | 
						||
					this[KEY_MULTIPLIER].negate();
 | 
						||
					return this;
 | 
						||
				},
 | 
						||
				is_positive: function () {
 | 
						||
					return this.sign(0) > 0;
 | 
						||
				},
 | 
						||
				is_negative: function () {
 | 
						||
					return this.sign(0) < 0;
 | 
						||
				},
 | 
						||
				sign: sign,
 | 
						||
 | 
						||
				to_continued_fraction: to_continued_fraction,
 | 
						||
				integer_part: function () {
 | 
						||
					return this[KEY_RADICAND].clone().square_root().multiply(this[KEY_MULTIPLIER]).add(this[KEY_INTEGER]).division(this[KEY_DENOMINATOR]);
 | 
						||
				},
 | 
						||
				toPrecision: toPrecision,
 | 
						||
				minimal_polynomial: minimal_polynomial,
 | 
						||
 | 
						||
				is_0: function (little_natural) {
 | 
						||
					return is_0(this, little_natural);
 | 
						||
				},
 | 
						||
				//compare_amount: compare_amount,
 | 
						||
				compare: compare,
 | 
						||
				equals: function (number) {
 | 
						||
					//	虛數無法比較大小。
 | 
						||
					return this.compare(number) === 0;
 | 
						||
				},
 | 
						||
 | 
						||
				op: Integer.set_operate(OP_REFERENCE),
 | 
						||
				valueOf: valueOf,
 | 
						||
				toString: toString
 | 
						||
			});
 | 
						||
 | 
						||
			//	class public interface	---------------------------
 | 
						||
			function is_Quadratic(value) {
 | 
						||
				return value instanceof Quadratic;
 | 
						||
			}
 | 
						||
 | 
						||
			function is_0(value, little_natural) {
 | 
						||
				return value == (little_natural || 0)
 | 
						||
				//
 | 
						||
				|| value[KEY_INTEGER].is_0(little_natural) && (value[KEY_RADICAND].is_0(0) || value[KEY_MULTIPLIER].is_0(0))
 | 
						||
				//
 | 
						||
				|| value[KEY_RADICAND].is_0(1) && value[KEY_INTEGER].clone().add(value[KEY_MULTIPLIER]).is_0(little_natural);
 | 
						||
			}
 | 
						||
 | 
						||
			// 正負符號。
 | 
						||
			// https://en.wikipedia.org/wiki/Sign_(mathematics)
 | 
						||
			// https://en.wikipedia.org/wiki/Sign_function
 | 
						||
			function sign(negative) {
 | 
						||
				if (this[KEY_RADICAND].is_positive()) {
 | 
						||
					var si = this[KEY_INTEGER].sign(), sm = this[KEY_MULTIPLIER].sign();
 | 
						||
					if (si * sm < 0)
 | 
						||
						// KEY_MULTIPLIER, KEY_INTEGER 正負相異時須比較大小。
 | 
						||
						return this[KEY_INTEGER].compare_amount(this[KEY_MULTIPLIER]) < 0
 | 
						||
						//
 | 
						||
						|| this[KEY_INTEGER].clone().square().compare_amount(this[KEY_MULTIPLIER].clone().square().multiply(this[KEY_RADICAND])) < 0
 | 
						||
						//
 | 
						||
						? sm : si;
 | 
						||
					return si || sm;
 | 
						||
				}
 | 
						||
				if (this[KEY_RADICAND].is_0())
 | 
						||
					return this[KEY_MULTIPLIER].sign();
 | 
						||
			}
 | 
						||
 | 
						||
			/**
 | 
						||
			 * 測試大小/比大小
 | 
						||
			 * @param number	the number to compare
 | 
						||
			 * @return	{Number}	0:==, <0:<, >0:>
 | 
						||
			 * @_name	_module_.prototype.compare_to
 | 
						||
			 */
 | 
						||
			function compare(number) {
 | 
						||
				if (!this[KEY_RADICAND].is_negative() && !number[KEY_RADICAND].is_negative()) {
 | 
						||
					TODO;
 | 
						||
				}
 | 
						||
			}
 | 
						||
 | 
						||
			// 整係數一元二次方程式 ax^2+bx+c=0 的兩根公式解。
 | 
						||
			// solve quadratic equation
 | 
						||
			function solve_quadratic(c, b, a) {
 | 
						||
				if (!a)
 | 
						||
					a = 1;
 | 
						||
				if (!b)
 | 
						||
					b = 0;
 | 
						||
				// discriminant = b^2 - 4ac
 | 
						||
				var discriminant = (new Integer(b)).square().add((new Integer(a)).multiply(c || 0).multiply(-4));
 | 
						||
				a = (new Integer(a)).multiply(2);
 | 
						||
				b = (new Integer(b)).negate();
 | 
						||
				if (discriminant.is_0())
 | 
						||
					return [(new Quadratic(1, 0, b, a)).reduce_factor()];
 | 
						||
 | 
						||
				a = (new Quadratic(discriminant, 1, b, a)).reduce_factor();
 | 
						||
				b = a.clone();
 | 
						||
				b[KEY_MULTIPLIER].negate();
 | 
						||
				return [a, b];
 | 
						||
			}
 | 
						||
 | 
						||
			function from_continued_fraction(sequence, length, base) {
 | 
						||
				TODO;
 | 
						||
			}
 | 
						||
 | 
						||
			// Get the first to NO-th solutions of Pell's equation: x^2 - d y^2 = n (n=+1 or -1).
 | 
						||
			// https://en.wikipedia.org/wiki/Pell%27s_equation
 | 
						||
			// Rosen, Kenneth H. (2005). Elementary Number Theory and its Applications (5th edition). Boston: Pearson Addison-Wesley. pp. 542-545.
 | 
						||
			// TODO: [[en:chakravala method]]
 | 
						||
			// TODO: https://www.alpertron.com.ar/METHODS.HTM Solve the equation: a x2 + b xy + c y2 + dx + ey + f = 0 圓錐曲線/二元二次方程
 | 
						||
			// [[en:Conic_section#General Cartesian form]]
 | 
						||
			function solve_Pell(d, n, limit, return_Integer) {
 | 
						||
				if (!(d >= 1) || !((d | 0) === d)) {
 | 
						||
					// 錯誤參數
 | 
						||
					throw 'Invalid parameter: ' + d;
 | 
						||
				}
 | 
						||
				if (typeof n !== 'number')
 | 
						||
					n = 1;
 | 
						||
				else if (n !== 1 && n !== -1)
 | 
						||
					return;
 | 
						||
				library_namespace.debug("Solve Pell's equation: x^2 - " + (-d) + ' y^2 = ' + n);
 | 
						||
				var cf = (new Quadratic(d)).to_continued_fraction(),
 | 
						||
				// 漸進連分數表示
 | 
						||
				period = cf.pop(), solutions = [];
 | 
						||
				if (!Array.isArray(period)) {
 | 
						||
					// e.g., d is a perfect square integer
 | 
						||
					// 若 d 是完全平方數,則這個方程式只有平凡解
 | 
						||
					return n === 1 && [1, 0];
 | 
						||
				}
 | 
						||
				Array.prototype.push.apply(cf, period);
 | 
						||
				if (period.length % 2 === 0) {
 | 
						||
					if (n !== 1)
 | 
						||
						// n = -1: no solution
 | 
						||
						return;
 | 
						||
				} else if (n === 1)
 | 
						||
					// 2*l - 1
 | 
						||
					Array.prototype.push.apply(cf, period);
 | 
						||
				cf.pop();
 | 
						||
				cf = Integer.convergent_of(cf);
 | 
						||
				if (limit !== undefined && !(limit > 0) && typeof limit !== 'function') {
 | 
						||
					library_namespace.error('Invalid limit: ' + limit);
 | 
						||
					limit = undefined;
 | 
						||
				}
 | 
						||
				if (limit === undefined) {
 | 
						||
					limit = n === 1 ? 2 : 1;
 | 
						||
				}
 | 
						||
				// [1, 0]: trivial solution
 | 
						||
				n = n === 1 ? [new Integer(1), new Integer(0)] : [cf[0].clone(), cf[1].clone()];
 | 
						||
				solutions.push([n[0].clone(!return_Integer), n[1].clone(!return_Integer)]);
 | 
						||
 | 
						||
				// limit() return true if 到達界限 / reach the limit / out of valid range.
 | 
						||
				while (limit > 0 ? --limit : !limit(n[0].clone(!return_Integer))) {
 | 
						||
					period = n[0].clone();
 | 
						||
					n[0].multiply(cf[0]).add(n[1].clone().multiply(d).multiply(cf[1]));
 | 
						||
					n[1].multiply(cf[0]).add(period.multiply(cf[1]));
 | 
						||
					solutions.push([n[0].clone(!return_Integer), n[1].clone(!return_Integer)]);
 | 
						||
				}
 | 
						||
 | 
						||
				return solutions;
 | 
						||
			}
 | 
						||
 | 
						||
			Object.assign(Quadratic, {
 | 
						||
				solve_quadratic: solve_quadratic,
 | 
						||
 | 
						||
				from_continued_fraction: from_continued_fraction,
 | 
						||
				solve_Pell: solve_Pell,
 | 
						||
 | 
						||
				// little_natural: little natural number, e.g., 1
 | 
						||
				is_0: is_0,
 | 
						||
 | 
						||
				is_Quadratic: is_Quadratic
 | 
						||
			});
 | 
						||
 | 
						||
 | 
						||
			// ---------------------------------------------------------------------//
 | 
						||
 | 
						||
			// 因 clone 頗為常用,作特殊處置以增進效率。
 | 
						||
			function clone(convert_to_Number_if_possible) {
 | 
						||
				var quadratic = new Quadratic;
 | 
						||
				[KEY_RADICAND, KEY_MULTIPLIER, KEY_INTEGER, KEY_DENOMINATOR].forEach(function (key) {
 | 
						||
					if (key in this)
 | 
						||
						quadratic[key] = this[key].clone();
 | 
						||
					else
 | 
						||
						delete quadratic[key];
 | 
						||
				}, this);
 | 
						||
				if (KEY_IRREDUCIBLE in this)
 | 
						||
					quadratic[KEY_IRREDUCIBLE] = this[KEY_IRREDUCIBLE];
 | 
						||
				return quadratic;
 | 
						||
			}
 | 
						||
 | 
						||
			function assignment(radicand, multiplier, integer, denominator) {
 | 
						||
				do_modified(this);
 | 
						||
 | 
						||
				this[KEY_INTEGER] = new Integer(integer || 0);
 | 
						||
				this[KEY_DENOMINATOR] = new Integer(denominator || 1);
 | 
						||
 | 
						||
				this[KEY_MULTIPLIER] = multiplier = new Integer(multiplier === undefined ? 1 : multiplier);
 | 
						||
				radicand = new Integer(radicand || 0);
 | 
						||
 | 
						||
				//	為了允許 二元數/dual numbers,因此不對 radicand.is_0() 時作特殊處置,而當作 ε = √0。
 | 
						||
				//	http://en.wikipedia.org/wiki/Dual_number
 | 
						||
 | 
						||
				// make radicand square-free
 | 
						||
				var factors = radicand.factorize(), power;
 | 
						||
				for (var factor in factors)
 | 
						||
					if (factors[factor] > 1) {
 | 
						||
						multiplier.multiply((power = new Integer(factor)).power(factors[factor] / 2 | 0));
 | 
						||
						radicand = radicand.division(power.square());
 | 
						||
					}
 | 
						||
				this[KEY_RADICAND] = radicand;
 | 
						||
 | 
						||
				if (this[KEY_DENOMINATOR].is_negative()) {
 | 
						||
					// 保證分母為正。
 | 
						||
					this[KEY_MULTIPLIER].negate();
 | 
						||
					this[KEY_INTEGER].negate();
 | 
						||
					this[KEY_DENOMINATOR].negate();
 | 
						||
				}
 | 
						||
 | 
						||
				return this.reduce_factor();
 | 
						||
			}
 | 
						||
 | 
						||
			function reduce_factor() {
 | 
						||
				if (!this[KEY_IRREDUCIBLE] && !this[KEY_DENOMINATOR].is_0(1)) {
 | 
						||
					var gcd = new Integer(Integer.GCD(this[KEY_MULTIPLIER].clone(), this[KEY_INTEGER].clone(), this[KEY_DENOMINATOR].clone()));
 | 
						||
					if (!(gcd.compare(2) < 0)) {
 | 
						||
						this[KEY_MULTIPLIER].divide(gcd);
 | 
						||
						this[KEY_INTEGER].divide(gcd);
 | 
						||
						this[KEY_DENOMINATOR].divide(gcd);
 | 
						||
					}
 | 
						||
					this[KEY_IRREDUCIBLE] = true;
 | 
						||
				}
 | 
						||
 | 
						||
				return this;
 | 
						||
			}
 | 
						||
 | 
						||
			// 調整 field,使兩數成為相同 field。
 | 
						||
			// return: operand with the same field.
 | 
						||
			function adapt_field(_this, operand) {
 | 
						||
				operand = Quadratic(operand);
 | 
						||
				if (!_this[KEY_RADICAND].equals(operand[KEY_RADICAND]))
 | 
						||
					if (_this[KEY_MULTIPLIER].is_0())
 | 
						||
						_this[KEY_RADICAND] = operand[KEY_RADICAND].clone();
 | 
						||
					else if (operand[KEY_MULTIPLIER].is_0())
 | 
						||
						(operand = operand.clone())[KEY_RADICAND] = _this[KEY_RADICAND].clone();
 | 
						||
					else
 | 
						||
						throw new Error('Different field: ' + _this[KEY_RADICAND] + ' != ' + operand[KEY_RADICAND]);
 | 
						||
				return operand;
 | 
						||
			}
 | 
						||
 | 
						||
			// ---------------------------------------------------------------------//
 | 
						||
			//四則運算,即加減乘除, + - * / (+-×÷)**[=]
 | 
						||
			//https://en.wikipedia.org/wiki/Elementary_arithmetic
 | 
						||
 | 
						||
			// Addition 和: addend + addend = sum
 | 
						||
			function add(addend, is_subtract) {
 | 
						||
				addend = adapt_field(this, addend);
 | 
						||
 | 
						||
				do_modified(this);
 | 
						||
				if (this[KEY_DENOMINATOR].compare(addend[KEY_DENOMINATOR]) !== 0) {
 | 
						||
					// n1/d1 ± n2/d2 = (n1d2 ± n2d1)/d1d2
 | 
						||
					// assert: d1 != d2
 | 
						||
					var multiplier = this[KEY_DENOMINATOR], tmp = addend[KEY_DENOMINATOR];
 | 
						||
					if (multiplier.is_0(MULTIPLICATIVE_IDENTITY))
 | 
						||
						tmp = tmp.clone();
 | 
						||
					else {
 | 
						||
						addend = addend.clone();
 | 
						||
						addend[KEY_INTEGER].multiply(multiplier);
 | 
						||
						addend[KEY_MULTIPLIER].multiply(multiplier);
 | 
						||
						addend[KEY_DENOMINATOR].multiply(multiplier);
 | 
						||
					}
 | 
						||
 | 
						||
					if (!tmp.is_0(MULTIPLICATIVE_IDENTITY)) {
 | 
						||
						this[KEY_INTEGER].multiply(tmp);
 | 
						||
						this[KEY_MULTIPLIER].multiply(tmp);
 | 
						||
						this[KEY_DENOMINATOR].multiply(tmp);
 | 
						||
					}
 | 
						||
				}
 | 
						||
 | 
						||
				this[KEY_INTEGER].add(addend[KEY_INTEGER], is_subtract);
 | 
						||
				this[KEY_MULTIPLIER].add(addend[KEY_MULTIPLIER], is_subtract);
 | 
						||
				return this.reduce_factor();
 | 
						||
			}
 | 
						||
 | 
						||
			// Subtraction 差: minuend − subtrahend = difference
 | 
						||
			function subtract(subtrahend) {
 | 
						||
				return this.add(subtrahend, true);
 | 
						||
			}
 | 
						||
 | 
						||
			// Multiplication 乘: multiplicand × multiplier = product
 | 
						||
			function multiply(multiplier) {
 | 
						||
				multiplier = adapt_field(this, multiplier);
 | 
						||
 | 
						||
				do_modified(this);
 | 
						||
				this[KEY_DENOMINATOR].multiply(multiplier[KEY_DENOMINATOR]);
 | 
						||
				var i = this[KEY_INTEGER].clone();
 | 
						||
				this[KEY_INTEGER].multiply(multiplier[KEY_INTEGER]).add(this[KEY_MULTIPLIER].clone().multiply(multiplier[KEY_MULTIPLIER]).multiply(this[KEY_RADICAND]));
 | 
						||
				this[KEY_MULTIPLIER].multiply(multiplier[KEY_INTEGER]).add(i.multiply(multiplier[KEY_MULTIPLIER]));
 | 
						||
 | 
						||
				return this.reduce_factor();
 | 
						||
			}
 | 
						||
 | 
						||
			// 共軛
 | 
						||
			function conjugate() {
 | 
						||
				do_modified(this);
 | 
						||
				this[KEY_MULTIPLIER].negate();
 | 
						||
 | 
						||
				return this.reduce_factor();
 | 
						||
			}
 | 
						||
 | 
						||
			// 倒數, multiplicative inverse or reciprocal
 | 
						||
			function reciprocal() {
 | 
						||
				do_modified(this.reduce_factor());
 | 
						||
				var d = this[KEY_DENOMINATOR];
 | 
						||
				if ((this[KEY_DENOMINATOR] = this[KEY_INTEGER].clone().square().add(this[KEY_MULTIPLIER].clone().square().multiply(this[KEY_RADICAND]), true)).is_negative())
 | 
						||
					this[KEY_DENOMINATOR].negate(), d.negate();
 | 
						||
				this[KEY_INTEGER].multiply(d);
 | 
						||
				this[KEY_MULTIPLIER].multiply(d.negate());
 | 
						||
 | 
						||
				return this.reduce_factor();
 | 
						||
			}
 | 
						||
 | 
						||
			// Division 除: dividend ÷ divisor = quotient
 | 
						||
			function divide(denominator) {
 | 
						||
				denominator = adapt_field(this, denominator);
 | 
						||
 | 
						||
				do_modified(this);
 | 
						||
				return this.multiply(denominator.clone().reciprocal());
 | 
						||
			}
 | 
						||
 | 
						||
 | 
						||
			// ---------------------------------------------------------------------//
 | 
						||
 | 
						||
			// absolute value/絕對值/模
 | 
						||
			// https://en.wikipedia.org/wiki/Absolute_value
 | 
						||
			function abs() {
 | 
						||
				var v = this, i2, r2 = function () {
 | 
						||
					i2 = v[KEY_INTEGER].clone().square();
 | 
						||
					return r2 = v[KEY_MULTIPLIER].clone().square().multiply(v[KEY_RADICAND]);
 | 
						||
				};
 | 
						||
 | 
						||
				// test: (this) 為實數或複數。
 | 
						||
				if (v[KEY_RADICAND].is_negative())
 | 
						||
					// 複數一般方法: abs() = √(i^2 - r m^2) / d
 | 
						||
					return new Quadratic(r2().negate().add(i2), 1, 0, v[KEY_DENOMINATOR]);
 | 
						||
 | 
						||
				v = v.clone();
 | 
						||
				// KEY_MULTIPLIER, KEY_INTEGER 正負相異時須比較大小。
 | 
						||
				if (v[KEY_MULTIPLIER].is_negative() && (!v[KEY_INTEGER].is_positive() || r2().compare(i2) > 0)
 | 
						||
					//
 | 
						||
					|| v[KEY_INTEGER].is_negative() && (v[KEY_MULTIPLIER].is_0() || r2().compare(i2) < 0)) {
 | 
						||
					v[KEY_MULTIPLIER].negate();
 | 
						||
					v[KEY_INTEGER].negate();
 | 
						||
				}
 | 
						||
 | 
						||
				return v;
 | 
						||
			}
 | 
						||
 | 
						||
			function is_pure() {
 | 
						||
				var D = this[KEY_RADICAND].clone().square_root(1).multiply(this[KEY_MULTIPLIER]);
 | 
						||
				return D.clone().add(this[KEY_INTEGER]).compare(this[KEY_DENOMINATOR]) > 0
 | 
						||
					&& D.add(this[KEY_INTEGER], true).compare(0) > 0 && D.compare(this[KEY_DENOMINATOR]) < 0;
 | 
						||
			}
 | 
						||
 | 
						||
			function continued_fraction_toString() {
 | 
						||
				return '[' + this.join(',').replace(/,/, ';') + ']';
 | 
						||
			}
 | 
						||
 | 
						||
			function to_continued_fraction() {
 | 
						||
 | 
						||
				return quadratic_to_continued_fraction(this[KEY_RADICAND].valueOf(), this[KEY_MULTIPLIER].valueOf(), this[KEY_INTEGER].valueOf(), this[KEY_DENOMINATOR].valueOf());
 | 
						||
 | 
						||
				// TODO: for large arguments
 | 
						||
 | 
						||
				// (m√r + i) / d
 | 
						||
				// = (√(r m^2) + i) / d
 | 
						||
				// = (√(d in book) + P0) / Q0
 | 
						||
				var d = this[KEY_MULTIPLIER].clone().square().multiply(this[KEY_RADICAND]),
 | 
						||
				//
 | 
						||
				P = this[KEY_INTEGER].clone(), Q = this[KEY_DENOMINATOR].clone(),
 | 
						||
				// A: α in book.
 | 
						||
				A, a;
 | 
						||
 | 
						||
				return;
 | 
						||
			}
 | 
						||
 | 
						||
 | 
						||
			// precision: 不包含小數點,共取 precision 位,precision > 0。
 | 
						||
			function toPrecision(precision) {
 | 
						||
				return this.valueOf(precision).toString();
 | 
						||
			}
 | 
						||
 | 
						||
			// ---------------------------------------------------------------------//
 | 
						||
			// advanced functions
 | 
						||
 | 
						||
			// Exponentiation 冪/乘方: base ^ exponent = power
 | 
						||
			// https://en.wikipedia.org/wiki/Exponentiation
 | 
						||
			// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
 | 
						||
			// TODO: use matrix?
 | 
						||
			// http://en.wikipedia.org/wiki/2_%C3%97_2_real_matrices
 | 
						||
			function power(exponent) {
 | 
						||
				if (exponent == 0) {
 | 
						||
					if (!this.is_0(ZERO_EXPONENT)) {
 | 
						||
						do_modified(this);
 | 
						||
						this[KEY_DENOMINATOR] = new Integer(1);
 | 
						||
						this[KEY_INTEGER] = new Integer(1);
 | 
						||
						this[KEY_MULTIPLIER] = new Integer(0);
 | 
						||
					}
 | 
						||
 | 
						||
				} else if (1 < (exponent |= 0)) {
 | 
						||
					do_modified(this.reduce_factor());
 | 
						||
 | 
						||
					var power = new Quadratic, r, _m = exponent % 2 === 1, m, i,
 | 
						||
					//
 | 
						||
					d = this[KEY_DENOMINATOR].power(exponent);
 | 
						||
 | 
						||
					power[KEY_RADICAND] = r = this[KEY_RADICAND];
 | 
						||
					power[KEY_MULTIPLIER] = m = this[KEY_MULTIPLIER];
 | 
						||
					power[KEY_INTEGER] = i = this[KEY_INTEGER];
 | 
						||
					power[KEY_DENOMINATOR] = new Integer(MULTIPLICATIVE_IDENTITY);
 | 
						||
 | 
						||
					this[KEY_MULTIPLIER] = _m ? m.clone() : new Integer(0);
 | 
						||
					this[KEY_INTEGER] = _m ? i.clone() : new Integer(MULTIPLICATIVE_IDENTITY);
 | 
						||
					this[KEY_DENOMINATOR] = new Integer(MULTIPLICATIVE_IDENTITY);
 | 
						||
 | 
						||
					while (exponent >>= 1) {
 | 
						||
						// numerator := square of numerator
 | 
						||
						_m = m.clone();
 | 
						||
						m.multiply(2).multiply(i);
 | 
						||
						i.square().add(_m.square().multiply(r));
 | 
						||
						if (exponent % 2 === 1)
 | 
						||
							// this *= power
 | 
						||
							this.multiply(power);
 | 
						||
					}
 | 
						||
					this[KEY_DENOMINATOR] = d;
 | 
						||
				}
 | 
						||
				return this;
 | 
						||
			}
 | 
						||
 | 
						||
			/*
 | 
						||
			https://en.wikipedia.org/wiki/Square_(algebra)
 | 
						||
			*/
 | 
						||
			function square() {
 | 
						||
				return this.power(2);
 | 
						||
			}
 | 
						||
 | 
						||
			// https://en.wikipedia.org/wiki/Minimal_polynomial_(field_theory)
 | 
						||
			// return p[{Integer}], p[0] + p[1]*this + p[1]*this^2 = 0
 | 
						||
			function minimal_polynomial() {
 | 
						||
				this.reduce_factor();
 | 
						||
				// TODO: need GCD()?
 | 
						||
				var value, polynomial = [this[KEY_INTEGER].clone().square().add(this[KEY_MULTIPLIER].clone().square().multiply(this[KEY_RADICAND]), true),
 | 
						||
					//
 | 
						||
					this[KEY_INTEGER].clone().multiply(-2).multiply(this[KEY_DENOMINATOR]),
 | 
						||
					//
 | 
						||
					this[KEY_DENOMINATOR].clone().square()];
 | 
						||
				// translate to {Number} if possible.
 | 
						||
				polynomial.forEach(function (coefficient, index) {
 | 
						||
					if (Number.isSafeInteger(value = coefficient.valueOf()))
 | 
						||
						polynomial[index] = value;
 | 
						||
				});
 | 
						||
				return polynomial;
 | 
						||
			}
 | 
						||
 | 
						||
 | 
						||
			// ---------------------------------------------------------------------//
 | 
						||
 | 
						||
			// WARNING 注意: 若回傳非 Number.isSafeInteger(),則會有誤差,不能等於最佳近似值。
 | 
						||
			function valueOf(precision) {
 | 
						||
				// 2: (default base of Integer) ^ 2 > JavaScript 內定 precision.
 | 
						||
				var value = Math.max(2, precision || 0);
 | 
						||
				value = this[KEY_INTEGER].clone().add(this[KEY_RADICAND].clone().square_root(value).multiply(this[KEY_MULTIPLIER])).divide(this[KEY_DENOMINATOR], value);
 | 
						||
				return precision && value || value.valueOf();
 | 
						||
			}
 | 
						||
 | 
						||
			function toString(type) {
 | 
						||
				var string = this[KEY_MULTIPLIER].is_0() ? []
 | 
						||
				: [(this[KEY_MULTIPLIER].is_0(MULTIPLICATIVE_IDENTITY)
 | 
						||
					? '' : this[KEY_MULTIPLIER].toString()) + '√' + this[KEY_RADICAND].toString()];
 | 
						||
				// assert: (string) is now {Array}
 | 
						||
				if (!this[KEY_INTEGER].is_0())
 | 
						||
					string.unshift(this[KEY_INTEGER].toString());
 | 
						||
				if (string.length > 1) {
 | 
						||
					if (!/^-/.test(string[1]))
 | 
						||
						string[1] = '+' + string[1];
 | 
						||
					string = string.join('');
 | 
						||
				} else
 | 
						||
					string = string[0] || '';
 | 
						||
				// assert: (string) is now {String}
 | 
						||
				if (!this[KEY_DENOMINATOR].is_0(MULTIPLICATIVE_IDENTITY))
 | 
						||
					string = '(' + string + ')/' + this[KEY_DENOMINATOR].toString();
 | 
						||
				return string;
 | 
						||
			}
 | 
						||
 | 
						||
 | 
						||
			// ---------------------------------------------------------------------//
 | 
						||
 | 
						||
			return Quadratic;
 | 
						||
		}
 | 
						||
 | 
						||
	});
 |