/**
* @name CeL integer function
* @fileoverview
* 本檔案包含了整數 (integer) 暨小數的 functions,相當/類似於 BigInteger, bigint, Large number。
* 在純 javascript 的環境下,藉由原生計算功能,盡可能提供高效的大數計算。
* integer 大數基本上即為 Integer.BASE 進位制之數字系統(Positional notation or place-value notation)。
*
* @example
*
* CeL.run('data.math.integer');
* var integer = new CeL.integer('654561264556287547824234523');
* CeL.log(integer.add('096527893048039647894'));
*
*
* @since 2013/9/8 13:42:58
* @see
* https://zh.wikipedia.org/wiki/%E9%80%B2%E4%BD%8D%E5%88%B6
*/
/*
TODO:
在 ECMAScript 6 之後,或可以繼承重寫。
為了減輕負擔,有些屬性可以不放在 Integer.prototype。
http://reference.wolfram.com/mathematica/tutorial/SomeNotesOnInternalImplementation.html
http://gmplib.org/
http://www.craig-wood.com/nick/articles/pi-chudnovsky/
Arbitrary-precision arithmetic / 高精度計算
https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic
http://msdn.microsoft.com/zh-tw/library/system.numerics.biginteger.aspx
http://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html
https://github.com/silentmatt/javascript-biginteger
https://github.com/peterolson/BigInteger.js
https://github.com/peterolson/BigRational.js
https://github.com/cwacek/bigint-node/blob/master/lib/bigint.js
http://www.leemon.com/crypto/BigInt.html
http://www-cs-students.stanford.edu/~tjw/jsbn/
http://java.sun.com/javase/6/docs/api/java/math/BigInteger.html
規格書:
integer = new Integer(number, do not set fraction = false, base = default base);
integer = new Integer(number String, base of String, base = default base);
integer = new Integer(Integer, (ignored), base = default base);
// digit Array
integer[{integer}digit index] = the digit of base ^ (index + exponent)
integer[KEY_NEGATIVE] = {Undefined|Boolean}this integer is negative
integer[KEY_BASE] = {natural number}base of this integer
integer[KEY_EXPONENT] = {integer}exponent of this integer
integer[KEY_CACHE] = {Undefined|Array}cache String of value
integer[KEY_CACHE][base] = {String}value in base
integer[KEY_TYPE] = {Undefined|Number}NaN / Infinity
integer[KEY_FACTORS] = {Undefined|Array}factors / 因數
integer[KEY_FACTORS].sort(function(a,b){var na=Array.isArray(a),nb=Array.isArray(b);return na^nb?na^0:na&&nb?a.length-b.length||a[a.length-1]-b[b.length-1]:a-b;});
*/
if (typeof CeL === 'function')
CeL.run(
{
name: 'data.math.integer',
require: 'data.code.compatibility.|data.native.|data.math.GCD',
no_extend: 'random,compare',
code: function (library_namespace) {
'use strict';
// requiring
var GCD = this.r('GCD');
// ---------------------------------------------------------------------//
// basic constants. 定義基本常數。
var
// assert: isNaN(KEY_*)
// {safe integer} MIN_BASE <= instance[KEY_BASE] <= MAX_BASE
// instance[KEY_BASE] 基數/底數初始設定完後,除非歸零,否則不可再改變!
KEY_BASE = 'base',
// sign. true: *this* is negative, false/undefined: positive.
KEY_NEGATIVE = 'negative',
//{integer|Undefined}[exponent] 輸入數值標記之科學記數法指數 in instance[KEY_BASE]。default 0.
KEY_EXPONENT = 'exponent',
//僅為大數整數分解(因數分解, integer factorization)存在。
// this[KEY_FACTORS] = [ {safe integer}scalar純量, Integer, ..]
KEY_FACTORS = 'factors',
// instance[KEY_CACHE][base] = string in base;
KEY_CACHE = 'cache',
//instance[KEY_TYPE] = NaN / Infinity; unset: instance is normal number.
// 指示/存儲特殊值。 ** instance[\d] 本身僅存儲純數字。
KEY_TYPE = 'type',
// 本 library 所允許之最大可安全計算整數。MAX_SAFE_INTEGER <= Number.MAX_SAFE_INTEGER。
MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER,
// see for_each_digit()
//之後再作初始化。
// assert: 1 < MIN_BASE <= MAX_BASE
MIN_BASE = 0,
// assert: MAX_BASE * MAX_BASE < MAX_SAFE_INTEGER + 2
// see change_base_to(), for_each_digit()
// 為方便乘法處理,因此取自乘不致 overflow ( > MAX_SAFE_INTEGER) 之值,預防 overflow 用。
MAX_BASE = Math.floor(Math.sqrt(MAX_SAFE_INTEGER)),
// 可辨認之數字字串。
// [ full , sign, integer part 整數部分, fractional part 小數部分, exponent 指數, percent ]
PATTERN_NUMBER = /([+\-]?)([\d]*)(?:\.([\d]+))?(?:[eE]([+\-]?\d+))?\s*([%‰‱])?/,
// hex 用。
// [ full , sign, integer part 整數部分, fractional part 小數部分, exponent 指數, percent ]
PATTERN_NUMBER_HEX = /([+\-]?)([\da-z]*)(?:\.([\da-z]+))?(?:[eE]([+\-]?\d+))?\s*([%‰‱])?/,
// https://en.wikipedia.org/wiki/Parts-per_notation
exponent_parts_per = {
// percentage (%), 百分比, %(全形百分號)
'%' : -2,
// permille (‰), 千分率
'‰' : -3,
// permyriad (‱) (Basis point), 萬分率
'‱' : -4
// ppm (parts-per-million, 10–6), ppb (parts-per-billion, 10–9), ppt (parts-per-trillion, 10–12) and ppq (parts-per-quadrillion, 10-15).
},
//當展現十進位數字時,若非無窮小數,則最多可展現之位數。
MAX_TRUNCATED = get_precision(1 / 3) - 1,
DECIMAL_BASE_LENGTH = Math.log10(MAX_SAFE_INTEGER) >> 1,
DECIMAL_BASE = (1 + '0'.repeat(DECIMAL_BASE_LENGTH)) | 0,
// default base.
DEFAULT_BASE = DECIMAL_BASE,
MULTIPLICATION_BOUNDARY = multiplication_boundary(DEFAULT_BASE),
/**
* parseInt( , radix) 可處理之最大 radix,
* 與 Number.prototype.toString ( [ radix ] )
* 可用之最大基數 (radix, base)。
* 10 Arabic numerals + 26 Latin alphabet.
* 之後再作初始化。
*
* @inner
* @see
* Hexadecimal
*/
MAX_RADIX = 0,
// 之後再作初始化。
MIN_RADIX = 0,
// 應與 parseInt() 一致。
DEFAULT_RADIX = parseInt('10'),
HEX_RADIX = parseInt('0x10'),
PATTERN_HEX = new RegExp('^0x([0-9a-f]{' + Number.MAX_SAFE_INTEGER.toString(HEX_RADIX).length + ',})$', 'i'),
// 數字過大,parseInt() 無法獲得精密數值時使用 DEFAULT_DIGITS。不分大小寫。應與 parseInt() 一致。
// assert: DEFAULT_DIGITS.length === MAX_RADIX
// assert: DEFAULT_DIGITS.toLowerCase() === DEFAULT_DIGITS
DEFAULT_DIGITS = '',
DEFAULT_DIGITS_CACHE,
// copy from data.math
MULTIPLICATIVE_IDENTITY = library_namespace.MULTIPLICATIVE_IDENTITY,
// copy from data.math
ZERO_EXPONENT = library_namespace.ZERO_EXPONENT,
// copy from data.math
ABSORBING_ELEMENT = library_namespace.ABSORBING_ELEMENT,
trim_0,
// radix point / radix character / decimal mark 小數點
radix_point = '.',
// Array 或 Uint32Array。
array_type = Array,
// array_clone(from, to[, assignment]): 在不改變 to 之 reference 下,將 to 之陣列內容改為與 from 相同。
array_clone,
//reset digits of (this)
array_reset,
//
shift_digits;
// ---------------------------------------------------------------------//
/**
* front end of operation(運算)
* @param {String}operator operator
* @param number the second integer
* @return 計算後的結果
* @see
* https://en.wikipedia.org/wiki/Operation_(mathematics)
* JavaWorld@TW Java論壇 - post.view
* @_name _module_.prototype.op
*/
function operate(OP_SET, target, operator, operand, flag) {
if (operator.slice(-1) === '=') {
if (operator === '===')
return target === operand;
if (operator !== '=' && operator !== '==')
operator = operator.slice(0, -1);
// 避免 target +-×÷ target
if (target === operand)
target = target.clone();
} else
target = target.clone();
if (operator in OP_SET)
OP_SET[operator].call(target, operand, flag);
else
library_namespace.error('operate: Invalid operator [' + operator + ']!');
return target;
}
function set_operate(OP_SET) {
return function (operator, operand, flag) {
return operate(OP_SET, this, operator, operand, flag);
};
}
// ---------------------------------------------------------------------//
// 初始調整並規範基本常數。
/**
* 工具函數:轉換 ['a','b','c'] → {a:0,b:1,c:2}。
*
* @param {Array}[base] 輸入數值採用之進位制基底/數字 digit 字集。
*
* @return 回傳 cache 物件。
*
* @inner
*/
function digit_cache(base) {
var digits = Object.create(null);
base.forEach(function (digit, index) {
if (digit.length !== 1)
library_namespace.error('digit_cache: Invalid digit: [' + digit + '].');
else if (digit in digits)
library_namespace.error('Digit already exists: [' + digit + '] = ' + digits[digit]);
else
digits[digit] = index;
});
return digits;
}
// 工具函數
//truncation: truncate array to length
function Array_reset(array, to_length) {
// 或可參考:
// http://stackoverflow.com/questions/1232040/how-to-empty-an-array-in-javascript
to_length = array.length - (to_length | 0);
while (0 < to_length--)
array.pop();
return array;
}
function General_reset(array, to_length) {
var i = array.length;
to_length |= 0;
while (to_length < i--)
array[i] = 0;
return [];
}
function Array_clone(from, to) {
if (from !== to) {
Array_reset(to);
array_type.prototype.push.apply(to, from);
}
}
function General_clone(from, to) {
if (from !== to) {
var index = to.length, l = from.length;
if (index < l) {
library_namespace.warn('General_clone: Target array has a shorter length!');
//index = l;
} else
while (l < index)
//高位補 0。
to[--index] = 0;
// assert: index <= from.length, should be (from.length).
while (0 < index--)
to[index] = from[index];
}
}
// 清理高數位的 0。
function Array_trim_0(integer, preserve) {
var index = integer.length;
// 1 < index: 直接保留最後一個,省得麻煩。
if (preserve === undefined)
preserve = 1;
// assert: integer[index] is integer
while (preserve < index-- && integer[index] === 0);
integer.length = index + 1;
return integer;
}
//exponent > 0 時,會去掉尾數 exponent 個 digits。
//exponent < 0 時,會補上尾數 exponent 個 digits。
function Array_shift_digits(integer, exponent, no_set_exponent) {
if (exponent |= 0) {
if (!no_set_exponent)
integer[KEY_EXPONENT] += exponent;
if (0 < exponent)
integer.splice(0, exponent);
else {
//當 exponent 量過大(e.g., 在 .precise_divide() 中,循環節 period = 71687),Chrome 32 用
//Array.prototype.unshift.apply(integer, new Array(-exponent));
//會出現 RangeError: Maximum call stack size exceeded
var a = integer.slice();
integer.length = -exponent;
integer.fill(0);
Array.prototype.push.apply(integer, a);
}
}
}
function General_shift_digits(integer, exponent) {
if (exponent |= 0) {
if (!no_set_exponent)
integer[KEY_EXPONENT] += exponent;
if (0 < exponent)
for (var i = 0, l = integer.length; i < l; i++)
integer[i] = i + exponent < l ? integer[i + exponent] : 0;
else
for (var i = integer.length - 1; 0 <= i; i--)
integer[i] = i + exponent < 0 ? 0 : integer[i + exponent];
}
}
//找出最小可用之 radix。
while (Number.isNaN(parseInt('1', ++MIN_RADIX)));
try {
for (; ; MAX_RADIX++)
// console.log(MAX_RADIX + ' ' + DEFAULT_DIGITS);
// will be '0123456789abcdefghijklmnopqrstuvwxyz'
DEFAULT_DIGITS += MAX_RADIX < DEFAULT_RADIX ? MAX_RADIX.toString() : MAX_RADIX.toString(MAX_RADIX + 1);
} catch (e) { }
// 將 DEFAULT_DIGITS 轉成小寫。
DEFAULT_DIGITS = DEFAULT_DIGITS.toLowerCase();
DEFAULT_DIGITS_CACHE = digit_cache(DEFAULT_DIGITS.split(''));
//規範 MAX_SAFE_INTEGER
if (MAX_SAFE_INTEGER > Number.MAX_SAFE_INTEGER)
MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER;
//決定 determines thie MIN_BASE
while ((MAX_SAFE_INTEGER / ++MIN_BASE | 0) < 0);
(function () {
// 測試 array_type 可存取 attributes。
var a = array_type && new array_type(2), b;
if (a)
a[KEY_BASE] = 9;
if (!a || a[KEY_BASE] !== 9)
// assert: Array 可存取 attributes。
a = new (array_type = Array);
else if (0 < a.BYTES_PER_ELEMENT) {
// for TypedArray, 決定 MAX_BASE。
// 1 byte = 8 bits
b = Math.floor(Math.sqrt(1 << 8 * a.BYTES_PER_ELEMENT));
if (b < MAX_BASE) {
if (a.BYTES_PER_ELEMENT < 4)
library_namespace.warn('所使用之 array type 能存放之值過小,將影響效能!');
MAX_BASE = b;
} else if (MAX_BASE < b)
// 一般說來,TypedArray 不可能存放超過 Number.MAX_SAFE_INTEGER 之整數值,因此不應該執行到這!
library_namespace.error('所使用之 array type 能存放超過最大可安全計算整數 Number.MAX_SAFE_INTEGER 之值,恐造成錯誤計算結果!');
}
// 決定可用的 .push() 等 array 工具函數。
if (array_type.prototype.push) {
array_type.prototype.push.apply(a = new array_type, [4, 3]);
if (a[1] === 3 && a.length === 2) {
a.length = 0;
if (a.length === 0) {
//可設定 .length
array_clone = Array_clone;
array_reset = Array_reset;
trim_0 = Array_trim_0;
shift_digits = Array_shift_digits;
}
}
}
if (!array_clone) {
array_clone = General_clone;
//無法設定 .length
array_reset = General_reset;
trim_0 = function (integer) {
return integer;
};
shift_digits = General_shift_digits;
}
})();
// ---------------------------------------------------------------------//
// 工具函數
// 為正規 base。
function valid_base(base, force_change_base) {
// assert: MAX_BASE === MAX_BASE | 0
if (base === (base | 0)
//
&& (force_change_base ? MIN_RADIX <= base : MIN_BASE <= base)
&& base <= MAX_BASE
//&& base !== Integer.prototype[KEY_BASE]
)
return base;
}
// 為正規 radix。
function valid_radix(radix) {
// assert: MIN_RADIX === MIN_RADIX | 0
if (radix === (radix | 0)
&& MIN_RADIX <= radix && radix <= MAX_BASE
)
return radix;
}
// 超過此界限,與元素(Integer digit)相乘時即有可能超過 Number.MAX_SAFE_INTEGER。
// boundary(base+2) 1
return valid_base(base) ? Math.floor(MAX_SAFE_INTEGER / base) : MULTIPLICATION_BOUNDARY;
}
// 若為準確次方,則回傳次方數。
// number = base ^ count_exponent(number, base)
function count_exponent(number, base) {
if (number < base)
return -count_exponent(base, number);
var exponent = 0;
while (number !== 0 && 0 === number % base)
number /= base, exponent++;
if (number === ZERO_EXPONENT)
return exponent;
}
function do_modified(integer) {
delete integer[KEY_CACHE];
}
// ---------------------------------------------------------------------//
// definition of module integer
/**
* 任意大小、帶正負號的整數。integer instance.
*
* @example
*
* CeL.log((new CeL.integer('876567896')).op('*','6456789976545678'));
*
*
* @class Integer 的 constructor
* @constructor
*/
function Integer(number, base, to_base, force_change_base) {
if (1 === arguments.length && is_Integer(number))
// number = Integer(number)
// 當純粹只是為了轉換型別時使用。
return this instanceof Integer ? number.clone() : number;
var integer = new_instance();
if (number !== undefined || 1 < arguments.length)
if (Number.isSafeInteger(number)) {
if (MIN_RADIX <= base && !to_base || typeof to_base === 'boolean')
// shift arguments
force_change_base = to_base, to_base = base;
// 快速處理常用功能。
if (to_base = valid_base(to_base, force_change_base))
integer[KEY_BASE] = to_base;
else
// assert: integer[KEY_BASE] === DEFAULT_BASE
to_base = DEFAULT_BASE;
if (number === 0)
integer[0] = 0;
else {
if (number < 0)
integer[KEY_NEGATIVE] = true, number = -number;
for (var index = 0; 0 < number; number = number / to_base | 0)
integer[index++] = number % to_base;
}
} else
assignment.apply(integer, arguments);
return integer;
}
// instance public interface -------------------
// 每個位數存放 {safe integer} 0 – 此數-1,大於等於 此數 即須進位。
//read-only
Integer.prototype[KEY_BASE] = DEFAULT_BASE;
// 預設為 0 次方。
Integer.prototype[KEY_EXPONENT] = 0;
// https://en.wikipedia.org/wiki/Operation_(mathematics)
var OP_REFERENCE = {
'+': add,
'-': subtract,
'*': multiply,
'/': divide,
'%': modulo,
'^': power,
'=': assignment,
'==': compare
};
Object.assign(Integer.prototype, OP_REFERENCE, {
forEach: Array.prototype.forEach,
// 下面全部皆為 assignment,例如 '+' 實為 '+='。
assignment: assignment,
assign: assignment,
// add_assignment
add: add,
// subtract_assignment
subtract: subtract,
// multiply_assignment
multiply: multiply,
// divide_assignment
division: division,
divide: divide,
div: divide,
modulo: modulo,
mod: modulo,
power: power,
pow: power,
square: square,
square_root: square_root,
sqrt: square_root,
// 至此為 assignment。
precise_divide: precise_divide,
clone: clone,
// 偶數的
is_even: function (test_odd) {
return !(KEY_TYPE in this) && this[KEY_EXPONENT] === 0
//
&& this.modulo(2) === (test_odd ? 1 : 0);
},
// 奇數的,單數的
is_odd: function () {
return this.is_odd(true);
},
// absolute value/絕對值/模
// https://en.wikipedia.org/wiki/Absolute_value
abs: function (negative) {
if ((negative = !!negative) !== !!this[KEY_NEGATIVE])
do_modified(this), this[KEY_NEGATIVE] = negative;
return this;
},
// 變換正負號。
negate: function () {
do_modified(this);
if (this[KEY_NEGATIVE])
delete this[KEY_NEGATIVE];
else if (!this.is_0())
this[KEY_NEGATIVE] = true;
return this;
},
is_positive: function () {
return this.compare(0) > 0;
},
is_negative: function () {
return !!this[KEY_NEGATIVE];
},
// 正負符號。
// https://en.wikipedia.org/wiki/Sign_(mathematics)
// https://en.wikipedia.org/wiki/Sign_function
sign: function (negative) {
// NaN: 0
return this[KEY_NEGATIVE] ? -1 : this.is_0() ? 0 : Number.isNaN(this[KEY_TYPE]) ? undefined : 1;
},
get_base: function () {
return this[KEY_BASE];
},
get_exponent: function (exp) {
if (Number.isSafeInteger(exp) && exp !== this[KEY_EXPONENT]) {
do_modified(this);
// WARNING 注意: 除非有正當理由,否則不應直接修改 exponent!
if (!(this[KEY_EXPONENT] = exp))
// Can't use delete @ IE8.
//delete this[KEY_EXPONENT];
this[KEY_EXPONENT] = 0;
}
return this[KEY_EXPONENT];
},
expand_exponent: function () {
//直接展開指數。直接作位元操作,以求效率。
shift_digits(this, -this[KEY_EXPONENT], true);
// assert: this[KEY_EXPONENT] === 0
//去除 exponent 設定。
// Can't use delete @ IE8.
//delete this[KEY_EXPONENT];
this[KEY_EXPONENT] = 0;
return this;
},
Euclidean_algorithm: Euclidean_algorithm,
to_precision: to_precision,
round: round,
floor: function (digits) {
return this.round(digits, -Infinity);
},
ceil: function (digits) {
return this.round(digits, Infinity);
},
log: log,
is_0: is_0,
compare_amount: compare_amount,
compare: compare,
equals: function (number) {
return this.compare(number) === 0;
},
isFinite: function () {
return !(KEY_TYPE in this);
},
isNaN: function () {
return (KEY_TYPE in this) && isNaN(this[KEY_TYPE]);
},
power_modulo: power_modulo,
Miller_Rabin: Miller_Rabin,
not_prime: not_prime,
Pollards_rho: Pollards_rho_1980,
factorize: factorize,
op: set_operate(OP_REFERENCE),
for_each_digit: for_each_digit,
ratio_to: ratio_to,
valueOf: valueOf,
digits: digits,
digit_sum: digit_sum,
toString: toString
});
// setup Integer constructor after Integer.prototype configured.
var new_instance = Array.derive(Integer, array_type);
// class public interface ---------------------------
var is_Integer = (new Integer) instanceof Integer ? function (number) {
return number instanceof Integer;
} : array_type === Array ? Array.isArray
//
: library_namespace.type_tester(library_namespace.is_type(new array_type));
function Integer_compare(number1, number2) {
if (typeof number1 === 'number' && typeof number2 === 'number')
return number1 - number2;
if (!is_Integer(number1))
number1 = new Integer(number1, null, is_Integer(number2) && number2[KEY_BASE]);
return number1.compare(number2);
}
// get the extreme value (極端值: maximum/min) of input values
function extreme(values, get_minima) {
var index = values.length, extreme_value, value, compare;
if (!index)
// ES6: Math.max: If no arguments are given, the result is −∞.
return get_minima ? Infinity : -Infinity;
extreme_value = values[--index];
while (0 < index--) {
// WARNING 注意: 當碰上許多大數時,會出現需要多次轉換 extreme_value 成 Integer 的效能低下情形!
// 但若許多數字不同底,而最大的是 String,則可能獲得部分效能。
if (Number.isNaN(compare = Integer_compare(extreme_value, value = values[index])))
// ES6: Math.max: If any value is NaN, the result is NaN.
return NaN;
if (get_minima ? compare > 0 : compare < 0)
extreme_value = value;
// 依規範,必須掃描一次,確定沒 NaN。不可中途跳出。
if (false && (get_minima ? compare > 0 : compare < 0)
//當有改變時才偵測。
&& typeof (extreme_value = value) === 'number' && !Number.isFinite(extreme_value = value))
break;
}
return extreme_value;
}
// range:
// 1 – Number.MAX_SAFE_INTEGER 當作 digits
// Number.MAX_SAFE_INTEGER + 1 – Number.MAX_VALUE || (is_Integer(range) && !(KEY_TYPE in range)) 當作 maximum value
// 其他採預設值 digits = 2
function random(range, base) {
var r, i;
if (0 < range && isFinite(range))
if (!Number.isSafeInteger(range = +range))
range = new Integer(range, null, base);
if (is_Integer(range) && !(KEY_TYPE in range)) {
//求極值之最大位元
for (i = range.length; 0 < i && range[--i] < 2 ;);
if (range[i] < 2)
range = 0;
else {
r = new Integer(0, base);
r[i] = Math.floor(range[i] * Math.random());
range = i;
}
}
// 其他情況採預設值 digits = 2
if (!(0 < range) || !Number.isSafeInteger(range))
range = 2;
// assert: range = {natural number}digits
if (!r)
r = new Integer(0, base);
for (base = r[KEY_BASE]; 0 < range;)
r[--range] = Math.floor(base * Math.random());
return r;
}
// WARNING 注意: this operation will modify arguments!
// https://en.wikipedia.org/wiki/Lehmer%27s_GCD_algorithm
function Integer_GCD(number_array) {
if (arguments.length > 1)
// Array.from()
number_array = Array.prototype.slice.call(arguments);
// 盡可能先挑小的,增加效率。
number_array.sort();
var index = 0, length = number_array.length, number, n,
//
use_Number, Integer_Array = [], gcd = undefined;
// 先嘗試是否可能找出較小的 gcd 以提升效能。
for (; index < length;) {
number = number_array[index++];
if (typeof number === 'string')
number = Number.isSafeInteger(n = parseInt(number)) ? n : new Integer(number);
if (is_Integer(number))
Integer_Array.push(number);
else if (number && !(1 < (gcd = gcd === undefined ? number : GCD([number, gcd]))))
return gcd;
}
for (use_Number = gcd !== undefined, index = 0, length = Integer_Array.length; index < length;) {
number = Integer_Array[index++];
if ((KEY_TYPE in number) || number.is_0())
continue;
if (gcd === undefined) {
gcd = number;
continue;
}
if (use_Number) {
// number = number % gcd
// assert: number.valueOf() is not Infinity
if (number = number.modulo(gcd).valueOf()) {
gcd = GCD([gcd, number]);
if (gcd === 1)
break;
}
//else: 整除,GCD 不變,跳過此數。
} else {
//if (typeof (gcd = number.Euclidean_algorithm(gcd)[1]) === 'number') use_Number = true;
// 使用 .modulo() 以增進效率,不使用 .Euclidean_algorithm()。
while (!number.modulo(gcd).is_0())
//swap gcd, number.
n = gcd, gcd = number, number = n;
if (gcd.is_0(1)) {
gcd = 1;
break;
}
if (Number.isSafeInteger(n = gcd.valueOf()))
gcd = n, use_Number = true;
}
};
return gcd;
}
// https://en.wikipedia.org/wiki/Least_common_multiple
function Integer_LCM(number_array) {
if (arguments.length > 1)
// Array.from()
number_array = Array.prototype.slice.call(arguments);
var lcm = new Integer(number_array[0]),
//index = 1: [0] → lcm
index = 1, length = number_array.length, number;
// TODO: 增進效率。
for (; index < length && lcm.compare(0) > 0 ;)
lcm = lcm.division(lcm.clone().Euclidean_algorithm(
// lcm = lcm / GCD * number
is_Integer(number = number_array[index++]) ? number.clone() : number)[1])
//
.multiply(number);
return lcm;
}
// factorial_cache[ n ] = n!
// factorial_cache = [ 0! = 1, 1!, 2!, .. ]
var factorial_cache = [1],
// maximum cache length.
// assert: (factorial_cache_limit!) 已逾越 SafeInteger 範圍, 約為 18。
factorial_cache_limit = 80,
factorial_SafeInteger_limit;
/**
* Get the factorial (階乘) of (integer).
*
* @param {integer}integer
* safe integer.
* @returns n的階乘.
* @see https://en.wikipedia.org/wiki/Factorial
*/
function factorial(integer) {
if ((integer !== integer | 0) || !Number.isSafeInteger(integer)
|| !(integer >= 0)) {
library_namespace.error('factorial: invalid number: '
+ integer);
return NaN;
}
var length = factorial_cache.length;
if (integer < length) {
if (is_Integer(integer = factorial_cache[integer]))
integer = integer.clone();
return integer;
}
var f = factorial_cache[--length];
if (!factorial_SafeInteger_limit) {
while (length < integer)
if (Number.isSafeInteger(f *= ++length))
factorial_cache.push(f);
else {
f = factorial_cache[--length];
factorial_SafeInteger_limit = length;
break;
}
if (integer === length)
return f;
}
f = new Integer(f);
for (var l = Math.min(factorial_cache_limit, integer) ; length < l;)
factorial_cache.push(f.multiply(++length).clone());
while (length < integer)
f.multiply(++length);
return f;
}
// 組合數學
/**
* Get the permutation (排列的可能方式數量) of (n).
* = n! / (n - k)!
* TODO: precision
*
* @param {safe
* integer}n: 排列的元素數量
* @param {safe
* integer}k 排列的長度
* @param {safe
* integer}precision
*
* @returns {safe integer} permutation (排列的可能方式數量) of
* (n).
* @see https://en.wikipedia.org/wiki/Permutation
*/
function permutation(n, k, precision) {
if ((n !== n | 0) || !Number.isSafeInteger(n)
|| !(n >= 0)) {
library_namespace.error('permutation: invalid number: '
+ n);
return NaN;
}
if (isNaN(k))
return factorial(n);
if (!k)
return factorial_cache[0];
k = n - (k | 0);
if (!(0 <= k && k < n)) {
library_namespace.error('permutation: invalid number: '
+ k);
return NaN;
}
if (k < 2)
return factorial(n);
if (n <= factorial_cache_limit) {
n = factorial(n);
k = factorial_cache[k];
if (is_Integer(n))
n = n.division(k);
else
n /= k;
return n;
}
var m, p;
if (factorial_cache_limit < k)
p = new Integer(++k);
else
m = factorial(factorial_cache_limit).division(factorial_cache[k]), p = new Integer(k = factorial_cache_limit + 1);
while (++k <= n)
p.multiply(k);
if (m)
p.multiply(m);
return p;
}
// 多項式定理係數/multinomial coefficients
// https://en.wikipedia.org/wiki/Multinomial_theorem#Multinomial_coefficients
function multinomial_coefficient(count_array) {
if (!Array.isArray(count_array))
count_array = Array.prototype.slice.apply(arguments);
// small → big
count_array.sort();
var c = new Integer(MULTIPLICATIVE_IDENTITY),
//
n = count_array.pop(), i = 0, l = count_array.length, k, p, f;
while (i < l) {
k = count_array[i++];
p = permutation(n += k, k);
f = factorial(k);
c.multiply(typeof p !== 'number' || factorial_SafeInteger_limit < k ? Integer(p).division(f) : p / f);
}
return c;
}
// 二項式係數/組合
// (1 + x)^n 的多項式展式中,x^k 項的係數。
// combination(n, k) = n!/k!/(n-k)!
// https://en.wikipedia.org/wiki/Combination
function combination(n, k) {
return multinomial_coefficient([k, n - k]);
}
// get the ratio of (length) th convergent of continued fraction.
// 取得連分數序列(sequence)至第(length)個逼近的比例值
// modified from data.math.continued_fraction
// TODO: {Integer|Array}partial_numerator, {Boolean}get_coefficients, to quadratic
function convergent_of(sequence, length, base, partial_numerator, get_coefficients) {
if (!Array.isArray(sequence) || !sequence.length || sequence.length < 1)
return sequence;
if (length < 0)
length += sequence.length;
if (!(0 < length) || sequence.length < length)
length = sequence.length;
var numerator = new Integer(1), denominator = new Integer(0), i;
if (length % 2)
i = numerator, numerator = denominator, denominator = i;
while (length--) {
i = new Integer(sequence[length], base);
if (length % 2)
denominator.add(i.multiply(numerator));
else
numerator.add(i.multiply(denominator));
}
return [numerator, denominator];
}
Object.assign(Integer, {
radix_point: function (p) {
if (p)
radix_point = p;
return radix_point;
},
DEFAULT_BASE: DEFAULT_BASE,
valid_radix: valid_radix,
set_operate: set_operate,
random: random,
// maximum
max: function Integer_max() {
// get max()
return extreme(arguments);
},
min: function Integer_min() {
// get min()
return extreme(arguments, true);
},
compare: Integer_compare,
// WARNING 注意: this operation will modify both dividend and divisor!
Euclidean_algorithm: function (dividend, divisor, get_coefficients) {
if (!is_Integer(dividend))
dividend = new Integer(dividend, is_Integer(divisor) && divisor[KEY_BASE]);
return dividend.Euclidean_algorithm(divisor, get_coefficients);
},
GCD: Integer_GCD,
LCM: Integer_LCM,
// TODO: precision
square_root: function (number, negative_exponent) {
return (new Integer(number)).square_root(negative_exponent);
},
E: Integer_E,
exp: Integer_exp,
LN2: Integer_LN2,
LN10: Integer_LN10,
PI: Integer_PI,
factorial: factorial,
permutation: permutation,
combination: combination,
multinomial_coefficient: multinomial_coefficient,
convergent_of: convergent_of,
is_Integer: is_Integer
});
// ---------------------------------------------------------------------//
// 因 clone 頗為常用,作特殊處置以增進效率。
function clone(convert_to_Number_if_possible, target_Integer, include_cache) {
if (convert_to_Number_if_possible === true) {
var value = this.valueOf();
if (value <= Number.MAX_SAFE_INTEGER) {
return value;
}
} else if (typeof convert_to_Number_if_possible !== 'boolean' && include_cache === undefined) {
// shift arguments
include_cache = target_Integer;
target_Integer = convert_to_Number_if_possible;
}
if (!is_Integer(target_Integer)) {
target_Integer = new_instance();
}
[KEY_BASE, KEY_NEGATIVE, KEY_TYPE in this ? KEY_TYPE : KEY_EXPONENT].forEach(function (key) {
if (key in this)
target_Integer[key] = this[key];
}, this);
if (!(KEY_TYPE in this)) {
array_clone(this, target_Integer);
if (include_cache) {
if (KEY_CACHE in this)
// clone Array
target_Integer[KEY_CACHE] = this[KEY_CACHE].slice();
if (KEY_FACTORS in this)
target_Integer[KEY_FACTORS] = this[KEY_FACTORS].slice();
}
}
return target_Integer;
}
function get_precision(number) {
var matched = String(number).match(/^-?(\d*)\.(\d+)$/);
if (matched)
return (matched[1] === '0' ? 0 : matched[1].length) + matched[2].length;
}
/**
* assignment value of integer instance.
* 僅設定單一值。
*
* @param {Number|String|Integer}number 輸入數值(value/number)大小。
* @param {natural number|String|Array}[base] 輸入字串採用之進位制基底/數字 digit 字集。區分大小寫。僅於輸入字串時有用。
* @param {natural number}[to_base] 內採基底/進位制。
*
* @example
*
* CeL.log((new CeL.integer('876567896')).op('*','6456789976545678'));
*
*
* @return 回傳 integer 物件。
*/
function assignment(number, base, to_base, force_change_base) {
if (typeof number === 'number' && get_precision(number) < MAX_TRUNCATED) {
//當可能以十進位為底做截斷時,採用十進位之值。
//e.g., 輸入 3423.3451242354,則取 '3423.3451242354',而非 3423.34512423539990778081119060516357421875。
number = number.toString();
// shift arguments
force_change_base = to_base;
to_base = base;
base = DEFAULT_RADIX;
}
/**
* 前期處理: String → Number / Integer
* 轉換指定進位的數字文字,成為{Number}純量或 {Integer} 物件。
* treat arguments as: (number_String, base, to_base)
*
* @see
* Numerical digit
*/
if (typeof number === 'string' && (number = number.trim())) {
// 正規化(normalize) base
// {Array}base → {String}base
if (Array.isArray(base)) {
base.forEach(function (digit) {
if (digit.length !== 1)
library_namespace.error('assignment: Invalid digit of base: [' + digit + '].');
});
base = base.join('');
}
if (typeof base === 'string' && DEFAULT_DIGITS.startsWith(base.toLowerCase()))
// 使用 DEFAULT_DIGITS。
base = base.length;
if (typeof base === 'string' ? base.length < 2
//base is number
: !valid_radix(base)) {
if (base)
library_namespace.error('assignment: Invalid base: [' + base + ']');
base = undefined;
}
var digits, value;
if (value = number.match(PATTERN_HEX))
number = value[1], base = HEX_RADIX;
if (typeof base === 'string') {
digits = digit_cache(base.split(''));
value = number.split('');
number = new Integer(0, base = base.length);
// 使用 DEFAULT_DIGITS。不分大小寫(將轉成小寫)。基本上應與 parseInt() 一致。
// [ full , sign, integer part 整數部分, fractional part 小數部分, decimal exponent 指數, percent ]
} else if (value = (value = number.toLowerCase()).match(PATTERN_NUMBER)
//
|| value.match(PATTERN_NUMBER_HEX)) {
if (!base)
base = DEFAULT_RADIX;
number = new Integer(0, base);
//處理 minus sign
if (value[1] === '-')
number[KEY_NEGATIVE] = true;
//處理指數
value[4] |= 0;
if (value[3]) {
//處理掉 fractional part 小數部分
value[4] -= value[3].length;
value[2] += value[3];
}
if ((digits = value[2].match(/^(.*)(0+)$/))
//1e4: 若是 exponent 不大,則基本上無須處理,直接展開即可。
&& (value[4] < 0 || 1e4 < value[4] + digits[2].length)) {
//去掉最後的 0
value[4] += digits[2].length;
value[2] = digits[1];
}
if (value[5])
value[4] += exponent_parts_per[value[5]];
if (value[4])
//1e4: 若是 exponent 不大,則基本上無須處理,直接展開即可。
if (value[4] < 0 || 1e4 < value[4])
number[KEY_EXPONENT] = value[4];
else
value[2] += '0'.repeat(value[4]);
//去掉起頭的 '0'。
value = value[2].replace(/^0+/, '').split('');
digits = DEFAULT_DIGITS_CACHE;
// 死馬當活馬醫,嘗試以 native method 取得。
// 若非十進位又包含 radix_point,則跳過。
} else if (//(!base || base !== DEFAULT_RADIX || number.indexOf(radix_point) === -1) &&
Number.isSafeInteger(value = base ? parseInt(number, base) : parseFloat(number)))
number = value;
else {
library_namespace.error('assignment: Invalid number string: [' + number + '].');
number = NaN;
}
if (Array.isArray(value)) {
//base: {natural number}length of base.
//digits: {Object}base cache.
//value: {Array}digits of specified base
// number: 欲轉換 base 之 {Integer}。
value.reverse();
// Array.map()
value.forEach(function (digit, index) {
if (digit in digits)
number[index] = digits[digit];
else
library_namespace.error('assignment: Invalid number digit: [' + digit + '].');
});
if (!to_base && count_exponent(DEFAULT_BASE, base))
to_base = DEFAULT_BASE;
}
} else if (MIN_RADIX <= base && !to_base || typeof to_base === 'boolean')
// shift arguments
force_change_base = to_base, to_base = base, base = undefined;
// ---------------------------------------
if (is_Integer(number)) {
// 已經是 Integer 了。
// clone, deep_copy。
//let to_base === this[KEY_BASE], base === number[KEY_BASE]
// 無設定 to_base 時,將 base 視作 to_base。
// assert: number[KEY_BASE] 為正規 base。
to_base = valid_base(to_base, force_change_base) || number[KEY_BASE];
base = number[KEY_BASE];
if (this !== number || base !== to_base) {
if (this === number)
number = number.clone();
else {
// copy attributes.
this[KEY_NEGATIVE] = number[KEY_NEGATIVE];
if (KEY_CACHE in number) {
var array = this[KEY_CACHE] = [];
number[KEY_CACHE].forEach(function (string, radix) {
array[radix] = string;
});
} else
delete this[KEY_CACHE];
if (KEY_FACTORS in number) {
var array = this[KEY_FACTORS] = [];
number[KEY_FACTORS].forEach(function (factor) {
if (factor)
array.push(is_Integer(factor) ? factor.clone() : factor);
});
} else
delete this[KEY_FACTORS];
}
do_modified(this);
this[KEY_BASE] = to_base;
if (KEY_TYPE in number) {
//處理特殊值。
this[KEY_TYPE] = number[KEY_TYPE];
// Can't use delete @ IE8.
//delete this[KEY_EXPONENT];
this[KEY_EXPONENT] = 0;
array_reset(this);
} else if (to_base === base || number.length < 2 && !(to_base <= number[0])) {
//處理簡易數值。
if (number[KEY_EXPONENT])
this[KEY_EXPONENT] = number[KEY_EXPONENT];
else
// Can't use delete @ IE8.
//delete this[KEY_EXPONENT];
this[KEY_EXPONENT] = 0;
array_clone(number, this);
} else {
// change base to / set base / 數字基底的轉換。
// https://en.wikipedia.org/wiki/Change_of_base
// https://en.wikipedia.org/wiki/Base_conversion
var exponent = count_exponent(to_base, base), to_digit_Array = array_reset(this),
scalar = 0,
base_now = ZERO_EXPONENT;
// 對 exponent 做特殊處置,增進效率。
if (0 < exponent) {
// e.g., base 10 → to_base 100
if (number[KEY_EXPONENT]) {
//因為會改變 number,因此新造一個。
number = number.clone();
if (0 < number[KEY_EXPONENT]) {
// e.g., base=1e1, to_base=1e7, 23e(+17*1) = 23000e(+2*7)
this[KEY_EXPONENT] = number[KEY_EXPONENT] / exponent | 0;
shift_digits(number, -number[KEY_EXPONENT] % exponent);
} else {
// e.g., base=1e1, to_base=1e7, 23e(-17*1) = 230000e(-3*7)
this[KEY_EXPONENT] = (number[KEY_EXPONENT] / exponent | 0) - 1;
shift_digits(number, -(number[KEY_EXPONENT] % exponent) - exponent);
}
}
number.forEach(function (digit, index) {
scalar += digit * base_now;
if ((index + 1) % exponent === 0)
to_digit_Array.push(scalar), scalar = 0, base_now = ZERO_EXPONENT;
else
base_now *= base;
});
if (scalar)
to_digit_Array.push(scalar);
array_clone(to_digit_Array, this);
} else if (exponent < 0) {
// e.g., base 100 → to_base 10
exponent = -exponent;
if (number[KEY_EXPONENT])
// e.g., base=1e7, to_base=1e1, 2300e(+2*7) = 2300e(+14*1)
// e.g., base=1e7, to_base=1e1, 2300e(-2*7) = 2300e(-14*1)
this[KEY_EXPONENT] = exponent * number[KEY_EXPONENT];
number.forEach(function (digit, index) {
for (var i = 0; i < exponent; i++)
to_digit_Array.push(digit % to_base), digit = digit / to_base | 0;
});
trim_0(to_digit_Array);
array_clone(to_digit_Array, this);
} else if (1 === (exponent = Math.log(MAX_BASE) / Math.log(to_base) | 0)) {
//無法做特殊處置時之一般性處理。
var fraction = 0, index, boundary = multiplication_boundary(to_base);
if (number[KEY_EXPONENT]) {
//因為會改變 number,因此新造一個。
number = number.clone();
if (0 < number[KEY_EXPONENT])
//直接展開指數。
number.expand_exponent();
else {
library_namespace.error('assignment: Unable to convert from base ' + base + ' to base ' + to_base + ' with exponent ' + number[KEY_EXPONENT] + ' without loss of significance.');
//計算 fraction。
index = -number[KEY_EXPONENT];
for (var fraction_base = ZERO_EXPONENT; fraction_base && index;)
fraction += number[--index] * (fraction_base /= base);
//直接展開指數。去掉 fraction。
number.expand_exponent();
}
}
//reset (this)
array_clone([0], this);
index = number.length;
while (0 < index--) {
base_now *= base;
scalar = scalar * base + number[index];
if (boundary < base_now * base || index === 0) {
this.for_each_digit(function (digit, carry, index) {
// 除了積本身,這邊可能出現 scalar<=(boundary-1), carry<=(base-1)。
// (base-1)*boundary+(boundary-1)+(base-1) <= Number.MAX_SAFE_INTEGER
// This is also the limit of (base), therefore:
// MAX_BASE<=Math.sqrt(Number.MAX_SAFE_INTEGER+2),
// boundary<=(Number.MAX_SAFE_INTEGER+2)/base-1,
return digit * base_now + carry + (index ? 0 : scalar);
});
//reset
scalar = 0, base_now = ZERO_EXPONENT;
}
}
if (fraction)
this.add(fraction, this[KEY_NEGATIVE]);
if (0 === number.length)
// assert: Array.(number)
number.push(0);
} else
//盡可能把 to_base 加大,減少 call .for_each_digit() 的次數,以增進效率。
this.assignment(new Integer(number, Math.pow(to_base, exponent)), to_base, force_change_base);
}
}
// ---------------------------------------
} else {
if (typeof number !== 'number') {
library_namespace.error('assignment: Invalid value to assignment: [' + number + '].');
number = NaN;
}
if (base !== to_base
//
|| this.compare(number) !== 0) {
do_modified(this);
// value/scalar純量 to digit Array.
// treat arguments as: (number, do not set fraction = false, to_base)
// 對於非數字,無法斷定。
if (number < 0)
number = -number,
this[KEY_NEGATIVE] = true;
else
delete this[KEY_NEGATIVE];
delete this[KEY_FACTORS];
// Can't use delete @ IE8.
//delete this[KEY_EXPONENT];
this[KEY_EXPONENT] = 0;
if (!isFinite(number)) {
//NaN, Infinity, -Infinity
this[KEY_TYPE] = number;
array_reset(this);
} else {
delete this[KEY_TYPE];
//to_base 實為欲轉換之標的 base。
if (to_base = valid_base(to_base, force_change_base))
this[KEY_BASE] = to_base;
else
to_base = this[KEY_BASE];
//base 實為是否不轉換小數部分。
if (base && number !== Math.floor(number)) {
//number 有小數部分。
library_namespace.warn('assignment: Number has a fractional part: [' + number + '].');
number = Math.floor(number);
}
if (number < to_base && number === (number | 0))
// 僅設定scalar純量部份。
array_clone([number], this);
else {
var digit_Array = array_reset(this);
// assert: 1 < to_base
if (number !== Math.floor(number)) {
// 當 base_now === 0,表示系統已無法處理較這更小的數字,再保留這之下的數值已無意義。
for (var base_now = ZERO_EXPONENT, remainder = number % 1; remainder && (base_now /= to_base) ;)
digit_Array.unshift((remainder *= to_base) | 0), remainder %= 1;
this[KEY_EXPONENT] = -digit_Array.length;
number = Math.floor(number);
} else if (!Number.isSafeInteger(number))
//test only
library_namespace.warn('assignment: Number is too large: [' + number + '].');
while (0 < number) {
digit_Array.push(number % to_base);
number = Math.floor(number / to_base);
}
array_clone(digit_Array, this);
}
}
}
}
return this;
}
function get_test_value(number) {
return is_Integer(number) ? number.valueOf(TYPE_TEST) : +number;
}
// little_natural: little natural number < MIN_RADIX, e.g., 1
function is_0(little_natural) {
return !(KEY_TYPE in this) && this.length < 2 && (little_natural ? !this[KEY_EXPONENT] && this[0] === little_natural : !this[0]);
}
/**
* 測試大小/比大小。僅比較量之大小,忽略符號。
* @param number the number to compare
* @return {Number} 0:==, <0:<, >0:>
* @_name _module_.prototype.compare_to
*/
// return < 0 : this < number
// return === 0 : this === number
// return > 0 : this > number
// return others : invalid number
function compare_amount(number) {
if (this === number)
return 0;
var i = typeof number === 'string' ? 0 : get_test_value(number), l, d;
if ((KEY_TYPE in this) || !isFinite(i))
// NaN 等極端數字的情形。
return Math.floor(this[KEY_TYPE]) - Math.floor(i);
// 強制轉成同底的 Integer 再處理。
if (!is_Integer(number) || this[KEY_BASE] !== number[KEY_BASE])
number = new Integer(number, null, this[KEY_BASE]);
i = this.length;
// 處理 [KEY_EXPONENT]
d = this[KEY_EXPONENT] - number[KEY_EXPONENT];
l = i + d - number.length;
if (!l)
//找到第一個兩者不同的位數。
while (0 < i-- && !(l = (this[i] || 0) - (number[i + d] || 0)));
return l;
}
/**
* 測試大小/比大小
* @param number the number to compare
* @return {Number} 0:==, <0:<, >0:>
* @_name _module_.prototype.compare_to
*/
function compare(number) {
var c = typeof number === 'string' ? 0 : get_test_value(number);
if ((KEY_TYPE in this) || !isFinite(c))
// NaN 等極端數字的情形。
return this[KEY_TYPE] - c;
if (!is_Integer(number)) {
if (typeof number === 'number' && this.length < 3
//2: Math.min(-Math.floor(Math.log(Number.EPSILON) / Math.log(MAX_BASE), Math.floor(Math.log(Number.MAX_VALUE) / Math.log(MAX_BASE)) + 1))
//預防 overflow or underflow.
&& Math.abs(this[KEY_EXPONENT]) < 2)
return this.valueOf() - number;
number = new Integer(number, null, this[KEY_BASE]);
}
if (this[KEY_NEGATIVE] ^ number[KEY_NEGATIVE])
return this[KEY_NEGATIVE] ? -1 : 1;
c = this.compare_amount(number);
return this[KEY_NEGATIVE] ? -c : c;
}
// 工具函數
// 將有問題的數字全部作正確進位。
// e.g., [10, 11].base = 10 → [0, 2, 1]
function normalize_handle(digit, carry) {
return digit + carry;
}
function normalize_digits(integer) {
integer.for_each_digit(normalize_handle);
}
// 工具函數
// 將 this integer instance 自低位依 callcack() 處理至高位,
// 結果存至 target_Integer[跳過 target_shift 個] || this。
// 可自動處理進退位。無法處理 overflow 問題。
// assert: callcack() 任一回傳,皆 isSafeInteger() === true。
function for_each_digit(callcack, target_Integer, target_shift) {
if (!target_Integer)
target_Integer = this;
target_shift |= 0;
var base = target_Integer[KEY_BASE], carry = 0, length = this.length, index = 0, digit;
if (!Number.isSafeInteger(base))
library_namespace.error('for_each_digit: Invalid base: [' + base + '].');
for (; index < length || carry !== 0 ; index++, target_shift++)
// 當 index >= length,僅作進位處理。
if (typeof (digit = index < length ? callcack(this[index] || 0, carry, index)
// 當 this 皆 callcack() 過後,僅處理進退位。
: carry + (target_Integer[target_shift] || 0)) === 'number') {
if (base <= digit) {
// 處理進位。
// assert: 0 < (digit / base | 0)
// MIN_BASE: 因為用 `|0`,故 base < 5 會出現問題:
// (Number.MAX_SAFE_INTEGER / 4 | 0) < 0, 0 < (Number.MAX_SAFE_INTEGER / 5 | 0)
carry = digit / base | 0;
digit %= base;
} else if (digit < 0 && (index < length || target_shift < target_Integer.length)) {
// 處理退位。
carry = digit / base | 0;
//確保 digit >=0
if ((digit %= base) < 0)
carry--, digit += base;
} else
carry = 0;
target_Integer[target_shift] = digit;
} else
carry = 0;
trim_0(target_Integer);
if (carry)
library_namespace.error('for_each_digit: carry [' + carry + '] left.');
return carry;
}
// ---------------------------------------------------------------------//
//四則運算,即加減乘除, + - * / (+-×÷)**[=]
// https://en.wikipedia.org/wiki/Elementary_arithmetic
// Addition 和: addend + addend = sum
function add(addend, is_subtract) {
// test if addend is zero.
if (Number.isNaN(this[KEY_TYPE]) || get_test_value(addend) === 0)
return this;
// 強制轉成同底的 Integer 再處理。
if (!is_Integer(addend) || this[KEY_BASE] !== addend[KEY_BASE])
addend = new Integer(addend, null, this[KEY_BASE]);
// assert: is_Integer(addend)
if ((KEY_TYPE in this) || (KEY_TYPE in addend)) {
addend = addend.valueOf(TYPE_TEST);
// do simulation: 模擬與 NaN 等極端數字作運算。
addend = this.valueOf(TYPE_TEST) + (is_subtract ? -addend : addend)
if (addend !== this.valueOf(TYPE_TEST))
this.assignment(addend);
return this;
}
// 至此特殊值處理完畢。
do_modified(this);
var reverse = (is_subtract ^= this[KEY_NEGATIVE] ^ addend[KEY_NEGATIVE])
//當兩數正負不同,且 abs(this) < abs(addend) 時,即需要反向,
//將 addend 放在前項,改成 this = (addend - this)。
&& this.compare_amount(addend) < 0,
//
shift = addend[KEY_EXPONENT] - this[KEY_EXPONENT];
if (reverse)
this[KEY_NEGATIVE] = !this[KEY_NEGATIVE];
if (shift < 0)
//為了位數對齊,須補足不足的位數。
shift_digits(this, shift), shift = 0;
addend.for_each_digit(
// (addend digit, carry, index of addend)
(reverse ? function (d, c, i) { return c + d - (this[i + shift] || 0); }
: is_subtract ? function (d, c, i) { return c + (this[i + shift] || 0) - d; }
: function (d, c, i) { return c + (this[i + shift] || 0) + d; }).bind(this)
, this,
//位數對齊。
shift);
if (this[KEY_NEGATIVE] && !this.valueOf(TYPE_TEST))
//0, NaN
delete this[KEY_NEGATIVE];
return this;
}
// Subtraction 差: minuend − subtrahend = difference
function subtract(subtrahend) {
return this.add(subtrahend, true);
}
// 乘除法之先期處理。
//@inner
function multiply_preprocess(integer, number, is_division) {
if (integer === number)
throw new Error('multiply_preprocess: Same operand!');
var value = get_test_value(number);
// NaN (+-×÷) number = NaN
if (Number.isNaN(integer[KEY_TYPE])
// test if number is MULTIPLICATIVE_IDENTITY.
|| value === MULTIPLICATIVE_IDENTITY && (!is_division || !integer[KEY_EXPONENT]))
return;
if (value === -MULTIPLICATIVE_IDENTITY && (!is_division || !integer[KEY_EXPONENT])) {
//Be sure not 0, NaN.
if (integer.valueOf(TYPE_TEST))
integer.negate();
return;
}
if (!is_Integer(number) || integer[KEY_BASE] !== number[KEY_BASE])
// 強制轉成同底的 Integer 再處理。
number = new Integer(number, null, integer[KEY_BASE]);
if (value === ABSORBING_ELEMENT
//
|| (KEY_TYPE in integer) || (KEY_TYPE in number)
//
|| integer.is_0(ABSORBING_ELEMENT)) {
// do simulation: 模擬與 NaN 等極端數字作運算。
var v = integer.valueOf(TYPE_TEST), r;
if (is_division) {
r = v / value;
value = v % value;
} else
value = v * value;
if (value !== v)
integer.assignment(value);
return r;
}
// 至此特殊值處理完畢。
do_modified(integer);
return number;
}
// test:
// check base & value: Integer (test if .is_safe_integer(true)===0, ±1, NaN)
// show error and exit: NaN, ±Infinity
// exit: 1
// set sign and exit: -1
// set value and exit: 0
// translate to Integer: safe integer(e.g., 123), 1.23e123, '123'+'4'.repeat(400), '123'+'4'.repeat(16); the string type & negative
// has a fractional part (有小數部分): .123, 1.123, 1903719924734991.36479887; the string type & negative; '123'+'4'.repeat(16)+'.1234'
// 在前兩位數以上皆相同時,方可考慮採用 a × b = ((a+b)/2)^2 - ((a-b)/2)^2。
// Multiplication 乘: multiplicand × multiplier = product
// TODO: https://en.wikipedia.org/wiki/F%C3%BCrer%27s_algorithm
// TODO: precision
function multiply(multiplier, /* TODO */ precision) {
if (multiplier = multiply_preprocess(this, multiplier)) {
//特殊值已於 multiply_preprocess() 處理過。
// copy factors, cache 用
if (!(KEY_FACTORS in this))
this[KEY_FACTORS] = [];
this[KEY_FACTORS].push(multiplier);
this[KEY_EXPONENT] += multiplier[KEY_EXPONENT];
//一般乘法
// scalar * this,結果放在 target_digit_Array。
var target_digit_Array = [];
target_digit_Array[KEY_BASE] = this[KEY_BASE];
// assert: multiplier 任一元素與 this 任一元素相乘,皆 isSafeInteger() === true。
multiplier.forEach(function (scalar, shift) {
if (scalar)
this.for_each_digit(function (digit, carry, index) {
// assert: target_digit_Array[] is natural number < base
// 除了積本身,這邊可能出現 carry<=(base-2), target_digit_Array[]<=(base-1), 共 (2*base-3)。
// assert: Number.isSafeInteger(base*base-2)
// therefore: base<=Math.sqrt(Number.MAX_SAFE_INTEGER+2)
return digit * scalar + carry + (target_digit_Array[index + shift] || 0);
}, target_digit_Array, shift);
}, this);
//回存。
array_clone(target_digit_Array, this);
//預防中空跳號。
if (Array.isArray(this)) {
var index = this.length;
while (0 < index--)
if (this[index] === undefined)
this[index] = 0;
}
if (multiplier[KEY_NEGATIVE])
this.negate();
}
return this;
}
var REVERSE_REMAINDER = -2;
// this → remainder。
// return {digit Array}quotient
// https://en.wikipedia.org/wiki/Euclidean_division
// https://en.wikipedia.org/wiki/Division_algorithm
function division(denominator, negative_exponent, get_nearest) {
if (!is_Integer(denominator = multiply_preprocess(this, denominator, true))) {
if (denominator === undefined)
// denominator == ±1
if (Number.isNaN(this[KEY_TYPE]))
// NaN (+-×÷) number = NaN
denominator = NaN;
else if (get_test_value(this)) {
// integer / ±1 = ±d, remainder 0.
denominator = this.clone();
this.assignment(0);
} else
denominator = 0;
return denominator;
}
if (Number.isSafeInteger(negative_exponent |= 0)
&& 0 < (negative_exponent -= denominator[KEY_EXPONENT])
// 不減低精度,因此不處理負數。
&& 0 < (negative_exponent += this[KEY_EXPONENT]))
shift_digits(this, -negative_exponent);
// (dividend or numerator) ÷ (divisor or denominator) = quotient + remainder / denominator
var numerator = this, base = this[KEY_BASE], quotient = new Integer(0, base),
// N: the highest digits of numerator.
// D: the highest digits of denominator.
N, NI, D, DI, Q, next_N, next_D;
quotient[KEY_EXPONENT] = this[KEY_EXPONENT] - denominator[KEY_EXPONENT];
// When denominator is bigger than numerator, the quotient will be 0 and the remainder will be numerator itself.
while (0 < (DI = denominator.length) && DI <= (NI = numerator.length)) {
// Get ths first non zero digit D of denominator.
// 使用 while 的原因:對 Uint32Array 之類無法保證前幾位不為 0。
while (!(D = denominator[--DI]) && 0 < DI);
// Get ths first non zero digit N of numerator.
while (!(N = numerator[--NI]) && 0 < NI);
// 多取一位 numerator,確保 N > D。
if (N <= D && 0 < NI && DI < NI)
N = N * base + numerator[--NI];
if (NI < DI || N < D)
break;
// assert: N >= D, NI >= DI
//決定 determines Q = thie next digit of quotient
// assert: (N + 1) / D === (Math.floor((N + 1) / D) | 0)
if (DI === 0)
//There is no digits of denominator lefting. The quotient digit has no other possibility.
Q = N / D | 0;
else
//考慮兩個因素:
//N, D 將在 Number.isSafeInteger() 的範圍內,一直乘到 N/(D+.99999~)|0===(N+.99999~)/D|0 為止。此兩數為當前 quotient 最高位數之可能值範圍。
while (((Q = N / (D + 1) | 0) < ((N + 1) / D | 0))
//
&& 0 < DI
&& Number.isSafeInteger(next_N = N * base + numerator[NI - 1])
&& Number.isSafeInteger(next_D = D * base + denominator[DI - 1])) {
N = next_N; NI--;
D = next_D; DI--;
}
// 通常發生在 numerator 極為接近 denominator 之 Q 或 Q+1 倍時,會無法判別應該用 Q 或 Q+1。
if (Q === 0) {
// assert: numerator, denominator 前面幾位大小相同。
// assert: index of quotient Array === NI - DI,尚未 borrowed。
// 確認 numerator, denominator 孰大孰小。
if (N === D)
while (0 < DI && numerator[--NI] === denominator[--DI]);
if (N < D || numerator[NI] < denominator[DI])
if (--NI < DI)
// numerator now (= remainder) < denominator
break;
else
Q = base - 1;
else
// 剛好足夠減一。
Q = 1;
}
//NI → index of quotient Array, the diff of numerator and denominator.
NI -= DI;
quotient[NI] = (quotient[NI] || 0) + Q;
//numerator → remainder
// numerator -= Q * denominator * base ^ (index of quotient Array = NI)
denominator.for_each_digit(function (digit, carry, index) {
// assert: numerator[index + NI] >= 0, carry <= 0, digit <= 0, Q > 0
return carry + (numerator[index + NI] || 0) - Q * digit;
}, numerator, NI);
// assert: numerator >= 0
}
if (get_nearest && base <= 2 * this.at(-1)) {
quotient[0]++;
if (get_nearest === REVERSE_REMAINDER) {
N = base;
this.for_each_digit(function (digit, carry, index) {
return (index ? N : N--) - digit + carry;
});
}
}
//處理需要進位的情況。雖然不常見,偶爾還是會發生,甚至連續進位,因此到最後才一次處理。
normalize_digits(quotient);
// remainder 不受 denominator 正負影響。
// quotient 受 denominator 正負影響。
if (quotient.valueOf(TYPE_TEST))
// quotient is not 0 or NaN
//e.g., 4/-5
quotient[KEY_NEGATIVE] = this[KEY_NEGATIVE] ^ denominator[KEY_NEGATIVE];
if (!this.valueOf(TYPE_TEST))
// remainder is not 0 or NaN
delete this[KEY_NEGATIVE];
// this → remainder,
// return {digit Array}quotient
return quotient;
}
// Division 除: dividend ÷ divisor = quotient
function divide() {
return this.assignment(division.apply(this, arguments));
}
function modulo(modulus) {
//if (KEY_TYPE in this) this.assignment(NaN); else
if (Number.isSafeInteger(modulus) && !(KEY_TYPE in this) && !this[KEY_EXPONENT]) {
// https://zh.wikipedia.org/wiki/%E6%95%B4%E9%99%A4%E8%A7%84%E5%88%99
var base = this[KEY_BASE] % modulus,
base_remainder = ZERO_EXPONENT, remainder = 0, index = 0;
do {
// 可於最後幾位判別。
if (this[index]) {
remainder += this[index] * base_remainder;
remainder %= modulus;
}
if (base !== 1)
base_remainder = base_remainder * base % modulus;
} while (++index < this.length && 0 !== base_remainder);
this.assignment(this[KEY_NEGATIVE] ? -remainder : remainder);
} else
division.apply(this, arguments);
return this;
}
// 模反元素, modular multiplicative inverse
// https://en.wikipedia.org/wiki/Modular_multiplicative_inverse
function modular_inverse(modulus) {
return result = this.clone().Euclidean_algorithm(modulus, true);
if (result[1] === MULTIPLICATIVE_IDENTITY)
return result[2];
}
// assert: GET_OBJECT 並非正規 radix.
var GET_OBJECT = 1;
// precise divide, to repeating decimal
// radix === GET_OBJECT: get {Integer} object instead of {String}
// return [ integer part, non-repeating fractional part, period (repeating decimal part) ]
// https://en.wikipedia.org/wiki/Repeating_decimal
function precise_divide(DENOMINATOR, radix, period_limit) {
if (!DENOMINATOR)
return [NaN, '', ''];
if (radix !== GET_OBJECT && !valid_radix(radix))
radix = DEFAULT_RADIX;
if (DENOMINATOR == MULTIPLICATIVE_IDENTITY)
return [radix === GET_OBJECT ? this : this.toString(radix), '', ''];
// 不改變 this, DENOMINATOR
DENOMINATOR = (new Integer(DENOMINATOR, null, this[KEY_BASE])).expand_exponent();
var REMAINDER = this.clone().expand_exponent(), return_Array, gcd;
if (DENOMINATOR[KEY_NEGATIVE]) {
delete DENOMINATOR[KEY_NEGATIVE];
REMAINDER[KEY_NEGATIVE] = !REMAINDER[KEY_NEGATIVE];
}
return_Array = REMAINDER.division(DENOMINATOR);
if (radix !== GET_OBJECT)
return_Array = return_Array.toString(radix);
return_Array = [return_Array];
if (REMAINDER.is_0()) {
return_Array.push('', '');
return return_Array;
}
if ((gcd = Integer_GCD(REMAINDER.abs().clone(), DENOMINATOR.clone())) !== 1)
REMAINDER = REMAINDER.division(gcd), DENOMINATOR = DENOMINATOR.division(gcd);
// assert: GCD(REMAINDER, DENOMINATOR) = 1, 0 < REMAINDER < DENOMINATOR, DENOMINATOR[KEY_EXPONENT] = 0.
// e.g., 67/300 = 0.2233333...
//radix: 10
//F: non-repeating fractional part, '22'
//f: digits of F, 2
//R: 循環節 period (repeating decimal part), '3'
//r: digits of R, 1
//[FR]: the concatenation of F and R, '223'
// 原理:
// REMAINDER / DENOMINATOR = F / radix^f + R / (radix^f (radix^r - 1)) = ([FR] - F) / (radix^f (radix^r - 1))
// radix^f (radix^r - 1) REMAINDER = ([FR] - F) DENOMINATOR
// radix^(f+r) * REMAINDER / DENOMINATOR = [FR] + R / (radix^r - 1)
// floor(radix^(f+r) * REMAINDER / DENOMINATOR) = [FR] = radix^r * F + R
// 找出 f:
// 因 GCD( DENOMINATOR, radix^f ) == GCD( DENOMINATOR, radix^(f+1) ) * d,可以此找出 f。
// 令 d = DENOMINATOR / GCD( DENOMINATOR, radix^f ),為去掉所有 radix 因數之 DENOMINATOR。
// 找出 r:
// 再測試得 d | 99..9 (共 r 位)
// 計算出 F, R:
// 令 remainder = floor(radix^(f+r) * REMAINDER / DENOMINATOR) = [FR] = radix^r * F + R,則
// F = remainder.slice(r),
// R = remainder.slice(0, r).
DENOMINATOR = new Integer(DENOMINATOR, radix);
var d = DENOMINATOR.clone(), f = 0, r = new Integer(0, radix);
//r → (10) in radix
r[1] = 1;
// 找出 f:
// TODO: 增進效率。
while ((gcd = Integer_GCD(d.clone(), r.clone())) !== 1)
f++, d = d.division(gcd);
// 找出 r:
if (d.is_0(1))
//is terminating decimal
r = 0;
else {
// 測得 d | (remainder = 99..9) (共 r 位)
//得先取與 d 相同之位數,保證 d <= remainder
var remainder = new Integer(0, radix), highest = parseInt('10', radix) - 1;
if (Array.isArray(d)) {
//快捷方法。
remainder.length = r = d.length;
//fill up with highest digit
remainder.fill(highest);
} else {
r = d.length;
//確認 nonzero 之最高位。
while (0 < r && d[--r] === 0);
gcd = r;
while (0 < gcd)
//fill up with highest digit
remainder[--gcd] = highest;
}
//若可能,嘗試簡化計算:將 d 轉成 {Number}。
if (Number.isSafeInteger((gcd = d.valueOf()) * radix)) {
remainder = remainder.modulo(d = gcd).valueOf();
var limit = period_limit || 1e6;
while ((remainder %= d) !== 0) {
//未能整除。
if (++r > limit) {
// TODO: 盡量取得可得位數。
library_namespace.error('precise_divide: The period of repeating decimal is too long (large than ' + limit + ')!');
return;
}
//remainder + 1 <= d
remainder = (remainder + 1) * radix - 1;
}
} else {
var limit = period_limit || 1e4;
while (!remainder.modulo(d).is_0()) {
//未能整除。
if (++r > limit) {
// TODO: 盡量取得可得位數。
library_namespace.error('precise_divide: The period of repeating decimal is too long (large than ' + limit + ')!');
return;
}
shift_digits(remainder, -1, true);
//fill up with highest digit
remainder[0] = highest;
}
}
}
// 計算出 F, R:
// assert: -f -r < 0, =0 的已在之前處理完畢。
shift_digits(REMAINDER = new Integer(REMAINDER, radix), -f - r, true);
REMAINDER = REMAINDER.division(DENOMINATOR);
// assert: REMAINDER.length === f + r
if (f) {
if (r) {
//作截斷處理。
shift_digits(f = REMAINDER.clone(), r, true);
} else
f = REMAINDER;
if (radix !== GET_OBJECT)
f = f.toString(radix);
}
if (r) {
if (f)
//作截斷處理。
if (Array.isArray(REMAINDER))
REMAINDER.length = r;
else
while (r < REMAINDER.length)
REMAINDER[r++] = 0;
r = REMAINDER;
if (radix !== GET_OBJECT)
r = r.toString(radix);
}
return_Array.push(f || '', r || '');
return return_Array;
}
// ---------------------------------------------------------------------//
//最後會保留 digits 位數(in this.base)。
//若 digits < 0,則會當作自尾端數起位數。
//direct: directed rounding: undefined, 0, Infinity, -Infinity
// https://en.wikipedia.org/wiki/Rounding
//可視為 shift_digits() 之 frontend。
function to_precision(digits, direct) {
if ((digits = (digits < 0 ? 0 : this.length) - digits | 0)
//長度相同: 毋須更動。
&& digits !== this.length) {
do_modified(this);
var add_1;
if (0 < digits) {
var index = digits - 1, value, base = this[KEY_BASE];
if (isNaN(direct)) {
//nearest
// http://mathworld.wolfram.com/NearestIntegerFunction.html
if (base === (value = 2 * (this[index] || 0))) {
for (--index; ;)
if (--index < 0) {
//四捨六入五成雙/best fraction
//NOT 四捨五入
add_1 = this[digits] % 2;
break;
} else if (0 < this[index]) {
add_1 = true;
break;
}
} else
add_1 = base < value;
} else if (!isFinite(direct)) {
//floor, ceil
//無條件捨去法/無條件進位法
while (0 < --index)
if (0 < this[index]) {
add_1 = (0 < direct) ^ this[KEY_NEGATIVE];
break;
}
}
//else: treat as direct = 0, just truncate
}
shift_digits(this, digits);
if (add_1 && base === ++this[0])
//need to normalize
normalize_digits(this);
}
return this;
}
//negative_exponent: 小數點後第 negative_exponent 位數(in this.base),可為負數。
//direct: directed rounding: undefined, 0, Infinity, -Infinity
// https://en.wikipedia.org/wiki/Rounding
function round(negative_exponent, direct) {
if (0 < (negative_exponent = (negative_exponent | 0) + this[KEY_EXPONENT] + this.length))
this.to_precision(negative_exponent, direct);
return this;
}
// ---------------------------------------------------------------------//
// advanced functions
// WARNING 注意: this operation will modify both dividend and divisor!
// return [ [ quotient Array ], remainder, Bézout coefficient for (dividend = this), Bézout coefficient for (divisor) ]
// https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
// https://en.wikipedia.org/wiki/Euclidean_algorithm
// https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity
function Euclidean_algorithm(divisor, get_coefficients) {
var dividend = this, base = dividend[KEY_BASE],
//
quotient_Array = [], quotient, q, last_q,
// coefficients
// 前前group [dividend 應乘的倍數, divisor 應乘的倍數]
c0 = [1, 0],
// 前一group [dividend 應乘的倍數, divisor 應乘的倍數]
c1 = [0, 1], c,
// [dividend 採用 Integer, divisor 採用 Integer]
is_i = [];
function set_coefficient(i) {
// 現 group = remainder = 前前group - quotient * 前一group
if (!is_i[i]) {
if (q && Number.isSafeInteger(c = c0[i] - c1[i] * last_q))
return c;
is_i[i] = true;
c0[i] = new Integer(c0[i], base);
c1[i] = new Integer(c1[i], base);
}
// TODO: 增進效率。
return c0[i].add((new Integer(c1[i], base)).multiply(last_q), true);
}
do_modified(dividend);
if (is_Integer(divisor))
do_modified(divisor);
else
divisor = (new Integer(divisor, null, base)).abs();
if ((KEY_TYPE in divisor) || divisor.compare(2) < 0)
return [quotient_Array];
for (; ;) {
quotient = dividend.division(divisor);
q = Number.isSafeInteger(last_q = quotient.valueOf(TYPE_TEST));
if (!q)
last_q = quotient;
quotient_Array.push(last_q);
if (dividend.is_0()) {
q = [quotient_Array, Number.isSafeInteger(q = divisor.valueOf(TYPE_TEST)) ? q : divisor];
if (get_coefficients)
q.push(c1[0], c1[1]);
return q;
}
if (get_coefficients)
c = [set_coefficient(0), set_coefficient(1)],
// shift
c0 = c1, c1 = c;
// swap (dividend, divisor)
c = dividend;
dividend = divisor;
divisor = c;
}
}
/*
https://en.wikipedia.org/wiki/Square_(algebra)
(please copy to a plain text)
自乘時,乘法截圖: (下列數字皆為序號 index)
5 4 3 2 1 0
× 5 4 3 2 1 0
-----------------------------------------------------------------------------------------------
5×0 4×0 3×0 2×0 1×0 0×0
5×1 4×1 3×1 2×1 1×1 1×0
5×2 4×2 3×2 2×2 2×1 2×0
5×3 4×3 3×3 3×2 3×1 3×0
5×4 4×4 4×3 4×2 4×1 4×0
5×5 5×4 5×3 5×2 5×1 5×0
-----------------------------------------------------------------------------------------------
注:加起來為序號 n 的組合:
10 9 8 7 6 5 4 3 2 1 0
** 除了自乘1倍外,皆為兩倍積。
i:
10 9 8 7 6 5 4 3 2 1 0
i + 1 - this_length(6):
5 4 3 2 1 0 1 -2 -3 -4 -5
j start:
5 4 3 2 1 0 0 0 0 0 0
j end:
5 4 4 3 3 2 2 1 1 0 0
*/
function square() {
if ((KEY_TYPE in this) || this.is_0() || this.is_0(1))
// 不處理虛數與複數。
// do simulation: 模擬與 NaN 等極端數字作運算。
return this;
// 至此特殊值處理完畢。
do_modified(this);
delete this[KEY_NEGATIVE];
this[KEY_EXPONENT] *= 2;
var i = 0, j, this_length = this.length, length = 2 * this_length, product, value,
//初始化。
result = new Array(length--).fill(0);
for (; i < length ; i++)
for (j = Math.max(0, i + 1 - this_length) ; 2 * j <= i; j++)
if (product = this[j] * this[i - j]) {
if (2 * j < i)
product *= 2;
if (Number.isSafeInteger(value = result[i] + product))
result[i] = value;
else
//手動進位。
result[i + 1]++, result[i] -= Number.MAX_SAFE_INTEGER - product;
}
//將 {Array}result → this,順便作正規化。
for_each_digit.call(result, normalize_handle, this);
return this;
}
//9741
//var square_root_base = Math.floor(Math.sqrt(Math.sqrt(MAX_SAFE_INTEGER)));
//for debug
//square_root_base = 1000;
/*
https://en.wikipedia.org/wiki/Square_root
https://en.wikipedia.org/wiki/Methods_of_computing_square_roots
slow method (don't use this):
(please copy to a plain text)
精準/準確直式開方 以 BASE = 100^2 = 10000 為例,sqrt(294565622121) = 542739:
accumulate 54 27 39 remainder
54 2945 6562 2121
+54 2916 ① q=Math.sqrt(2945)|0 = 54, 54×54 = 2916
10827 29 6562 ② remainder=296562, accumulate=10800, q=remainder/accumulate|0 = 27, 自 q 起找尋 (accumulate+q)×q <= remainder 之最大數 q (if(remainder-accumulate*q 0
var index = this.length, index_sr = --index / 2 | 0, base = this[KEY_BASE];
if (!index_sr)
// assert: this.length <= 2
return this.assignment(Math.floor(Math.sqrt((this[1] || 0) * base + (this[0] || 0))));
/*
use Newton's method: x1 = (x0 + number / x0) / 2
即使兩數僅差 1,亦不可直接回傳,有可能為 (準確值+1) & (準確值+2) 之類的。
initial sqrt 取值迭代變化: sr → _sr
n^2 - 1 n-1 n+1 → n → n-1 → n ** NG: 反轉了。
n^2 n n+1 → n → n → n
n^2 n n-1 → n+ → n → n
n^2 + 1 n n+2 → n → n → n
n^2 + 1 n n-1 → n+ → n → n
故:
1. 取 initial value >= sqrt
2. 當 _sr - sr = 0 or 1, 反轉時取較小的 sr 即為可回傳 sqrt。
*/
//決定 determines the initial value。
//sr: square root value
// TODO: 取更多位數。
var sr, _sr = this[index--];
if (index % 2 === 0)
//e.g., √1024 = 32
//取2位數
_sr = _sr * base + this[index];
else
//e.g., √10000 = 100
//取3位數
_sr += (this[index] + this[index - 1] / base) / base;
_sr = Math.sqrt(_sr);
sr = new Integer(0, base);
sr[KEY_EXPONENT] = -negative_exponent;
//初始化 the initial value。
sr[index_sr] = _sr | 0;
//+1: 保證 initial value >= sqrt(this)
sr[--index_sr] = ((_sr % 1) * base | 0) + 1;
//sr[0] 已被設定過。
while (0 < index_sr)
sr[--index_sr] = 0;
for (base--; ; sr = _sr) {
//use Newton's method: x1 = (number / x0 + x0) / 2
//_sr: next sr
_sr = this.clone().division(sr).add(sr).division(2);
/*
check if 反轉: _sr - sr = 1
possible condition:
part: 1 2 3
_sr = (the same digits) n (00000)
sr = (the same digits) (n-1) (99999)
part 1, 3 may not exist, the part 2 is the keypoint.
e.g.,
sr = 9999 19999 32999 42342
_sr = 10000 20000 33000 42343
*/
for (index_sr = 0; index_sr < _sr.length;)
if (_sr[index_sr] === 0 && sr[index_sr] === base)
//skip part 3.
index_sr++;
else {
// check part 2.
index = _sr[index_sr] - (sr[index_sr] || 0);
if (index_sr === 0 && index === 0 || index === 1)
//skip part 1.
for (; ;)
if (++index_sr === _sr.length)
// assert: _sr - sr = 0 or 1
return this.assignment(sr);
else if (sr[index_sr] !== _sr[index_sr])
break;
break;
}
}
}
// https://en.wikipedia.org/wiki/Nth_root
// https://en.wikipedia.org/wiki/Nth_root_algorithm
//nth root (surds): degree √radicand = root
function root(degree, negative_exponent) {
if (!Number.isSafeInteger(degree) || degree < 3) {
if (degree === 0)
return this.assignment(1);
if (degree === 2)
//square_root() is faster
return this.square_root(negative_exponent);
if (degree !== 1)
library_namespace.error('root: Invalid degree: [' + degree + '].');
return this;
}
if (this[KEY_NEGATIVE])
// 不處理虛數與複數。
return this.assignment(NaN);
if (KEY_TYPE in this)
return this[KEY_TYPE];
// 至此特殊值處理完畢。
do_modified(this);
if (0 < (negative_exponent |= 0) && Number.isSafeInteger(negative_exponent))
shift_digits(this, -negative_exponent * 2 - this[KEY_EXPONENT]);
// assert: this.at(-1) > 0
var index = this.length, index_sr = --index / 2 | 0, base = this[KEY_BASE];
if (!index_sr)
// assert: this.length <= 2
return this.assignment(Math.floor(Math.sqrt((this[1] || 0) * base + (this[0] || 0))));
TODO;
var r, delta;
//+1: 保證 initial value >= root(this)
for (; ;) {
//use Newton's method
delta = this.clone().division(r.clone().power(degree - 1)).add(r, true).division(2);
if (delta.compare(0) >= 0)
return this.assignment(r);
r.add(delta.derive(degree));
}
}
// ---------------------------------------------------------------------//
// return {Number} = antecedent(=this) : consequent = N / D
function ratio_to(consequent) {
if (!consequent)
// do simulation: 模擬與 NaN 等極端數字作運算。
return (this[KEY_NEGATIVE] ? -1 : 1) / 0;
if (typeof consequent === 'number')
return this.valueOf() / consequent;
// 至此特殊值處理完畢。
//以下操作目的:當 this, consequent 個別過大或過小,但比例可表示時,嘗試表現之。
var base = this[KEY_BASE], n = this.valueOf(TYPE_info_for_large), exponent_base = 0, next_n;
if (Array.isArray(n))
exponent_base = n[1], n = n[0];
if (Array.isArray(consequent = (new Integer(consequent, null, base)).valueOf(TYPE_info_for_large)))
exponent_base -= consequent[1], consequent = consequent[0];
exponent_base = Math.pow(base, exponent_base);
next_n = n / consequent;
if (next_n === 0 || !isFinite(next_n))
n = n * exponent_base / consequent;
else
n = next_n * exponent_base;
return n;
}
//max_digits[base]={integer}, min_digits[base]={integer}
var max_digits = Object.create(null), min_digits = Object.create(null),
//
LOG_MAX = Math.log(Number.MAX_VALUE), LOG_MIN = Math.log(Number.EPSILON);
function max_digits_of(base) {
if (!(base in max_digits))
max_digits[base] = (LOG_MAX / Math.log(base) | 0) + 1;
return max_digits[base];
}
function min_digits_of(base) {
if (!(base in min_digits))
min_digits[base] = LOG_MIN / Math.log(base) | 0;
return min_digits[base];
}
// 當數字過大,轉回傳 {String}
var TYPE_String_for_large = 1,
// return [value, exponent]: this = value * base ^ exponent,value 已為可計算之極端值(最大或最小)
TYPE_info_for_large = 2,
// 與 NaN 等極端數字作運算用。僅回傳 NaN, ±Infinity, ±1, 0, ±是否在 Number.isSafeInteger() 內。
TYPE_TEST = 3;
// WARNING 注意: 若回傳非 Number.isSafeInteger(),則會有誤差,不能等於最佳近似值。
function valueOf(type) {
var value;
//由消費最少,且必須先檢測的開始檢測。
if (KEY_TYPE in this) {
value = this[KEY_TYPE];
return this[KEY_NEGATIVE] ? -value : value;
}
var v, base = this[KEY_BASE], exponent = this[KEY_EXPONENT],
//實際應為首個 nonzero 之位置。
index = this.length, e0, next_value, base_now = ZERO_EXPONENT;
//先檢測是否為 {Number} 可表示之範圍。
if (!type && (value = index + exponent) <= min_digits_of(base))
value = 0;
else if (!type && max_digits_of(base) < value)
value = Infinity;
else if (type === TYPE_TEST && this.length < 2) {
if ((value = this[0] || 0) && exponent)
value *= Math.pow(base, exponent);
} else {
// 這邊將處理3種情況:
// F: first digit 首位.
// e0: digit of base^0.
// L: last digit that can presented.
// F---L---e0 : 直接在過程 phase 1 即解決掉。
// F---L=e0 : 直接在過程 phase 1 即解決掉。
// F---e0--L : phase 1 + 2。
// F=e0----L : phase 1 + 2。
// e0--F---L : 在過程 phase 2 解決掉。
//分為整數與小數兩階段處理,是為了盡可能保持精度。
//至此,除非是 TYPE_info_for_large,否則就算最後值應為 Infinity 或是 0,也應該會作到最後一個 loop 才發現。
// phase 1: 整數
for (value = 0, e0 = Math.max(0, -exponent) ; e0 < index; value = next_value)
if ((next_value = (v = value * base) + (this[--index] || 0)) === Infinity
//已經無法造成影響。
|| this[index] && next_value === v) {
//+1: 因為這邊取用 value,而非 next_value。
index += exponent + 1;
if (this[index])
//彌補差值。
value += this[index] / base;
if (type === TYPE_info_for_large)
return [this[KEY_NEGATIVE] ? -value : value, index];
else if (type === TYPE_String_for_large) {
//轉成 log_10(this)
value = Math.log10(value) + Math.log10(base) * index;
value = Math.pow(10, value % 1) + 'e+' + (value | 0);
} else if (type !== TYPE_TEST) {
// normal: 強迫回傳 {Number}
value = next_value;
index--;
if (value !== Infinity && index)
value *= Math.pow(base, index);
}
//TYPE_TEST: 與 NaN 等極端數字相較,再大的 Integer 都只是小兒科。因為不在乎精度,無須再處理。
//但須注意 assignment() 之使用。
//不需再處理小數了。
index = 0;
break;
}
// phase 2: 小數
if (0 < index) {
// 在 [length=12].exponent=-10 之類的情況下保持精度。
for (; 0 < index;) {
base_now /= base;
if (this[--index]) {
next_value = value + this[index] * base_now;
if (next_value === value)
//已經無法造成影響。
break;
if (0 === base_now / base) {
value += this[index] / base * base_now;
break;
}
value = next_value;
}
}
//基本上,上面算法假設 index 在 E0 之前。因此需要對 index 在 E0 之後,即首位已在 E0 之後的情況作修正。
if (this.length + exponent < 0) {
if (type === TYPE_info_for_large)
return [this[KEY_NEGATIVE] ? -value : value, this.length + exponent];
next_value = value * Math.pow(base, index + exponent);
if (next_value === 0) {
//轉成 log_10(this)
value = Math.log10(value) + Math.log10(base) * (this.length + exponent);
value = value + 'e+' + (value | 0);
} else
value = next_value;
}
}
}
// minus sign
return this[KEY_NEGATIVE] ? typeof value === 'number' ? -value : '-' + value : value;
}
function toString(radix) {
var base;
if (radix && isNaN(radix))
radix = (base = Array.isArray(radix) ? radix : String(radix).split('')).length;
else if (!valid_radix(radix))
radix = DEFAULT_RADIX;
if (!base && this[KEY_CACHE] && this[KEY_CACHE][radix])
return this[KEY_CACHE][radix];
var digits, value, zero;
if (KEY_TYPE in this)
digits = [this[KEY_TYPE]];
else {
if (!base)
base = DEFAULT_DIGITS;
if (typeof base === 'string')
// IE8 不能用 string[index]。'ab'[1] === undefined, 'ab'[1] !== 'b'。
// base.chars()
base = base.split('');
// assert: Array.isArray(base)
zero = base[0];
digits = [];
value = new Integer(this, radix, true);
value.forEach(function (digit) {
digits.push(base[digit]);
});
if (value = value[KEY_EXPONENT])
if (0 < value)
digits.unshift(zero.repeat(value));
else {
if (digits.length < (value = -value))
// 補足長度。
if (digits.fill) {
// Array.prototype.fill() 只會作用於 0~原先的 length 範圍內!
var i = digits.length;
digits.length = value;
digits.fill(zero, i);
} else
for (var i = digits.length; i < value;)
digits[i++] = zero;
// add 小數點
digits.splice(value, 0, radix_point);
while (digits[0] == zero)
// 去除末端的 '0'。
digits.shift();
if (digits[0] === radix_point)
digits.shift();
}
}
// 去除前導的 '0'。
if (value = digits.length)
while (0 < --value && digits[value] === zero)
digits.pop();
else
digits = [zero];
if (digits.at(-1) === radix_point)
digits.push(zero);
if (this[KEY_NEGATIVE])
// minus sign
digits.push('-');
digits.reverse();
if (!Array.isArray(this[KEY_CACHE]))
this[KEY_CACHE] = [];
return this[KEY_CACHE][radix] = digits.join('');
}
// assert: {ℕ⁰:Natural+0}this
// TODO: 處理小數/負數
function digits(radix) {
if (!valid_radix(radix))
radix = DEFAULT_RADIX;
var count = count_exponent(this[KEY_BASE], radix);
if (!(count > 0))
return this.toString(radix).split('').map(function(digit) {
return parseInt(digit, radix);
});
var digits = [];
this.forEach(function(value) {
for (var index = 0; index < count; index++) {
digits.unshift(value % radix);
value = value / radix | 0;
}
});
while (!digits[0])
digits.shift();
return digits;
}
function digit_sum(radix) {
return this.digits(radix).sum();
}
// ---------------------------------------------------------------------//
//初等數論函數/數學常數
// https://zh.wikipedia.org/wiki/%E6%95%B0%E5%AD%A6%E5%B8%B8%E6%95%B0
// return this ^ {Integer}exponent % {Integer}modulus
function power_modulo(exponent, modulus) {
if ((KEY_TYPE in this) || this[KEY_EXPONENT] < 0
//得允許 {Integer}exponent。
//|| !Number.isSafeInteger(exponent) || exponent < 0
)
return;
exponent = new Integer(exponent, null, 2, true);
exponent[KEY_EXPONENT] && exponent.expand_exponent();
if ((KEY_TYPE in exponent) || exponent[KEY_EXPONENT] || exponent[KEY_NEGATIVE])
return;
modulus = new Integer(modulus, null, this[KEY_BASE]);
var remainder = new Integer(ZERO_EXPONENT, this[KEY_BASE]), power = this.clone().abs();
for (power.division(modulus) ; ;) {
if (exponent[0] === 1)
remainder.multiply(power).division(modulus);
if (exponent.length === 1)
return remainder;
power.square().division(modulus);
if (power.is_0(1))
return remainder;
shift_digits(exponent, 1, true);
}
}
// Miller–Rabin primality test
// return true: is composite, undefined: probable prime (PRP) / invalid number
// https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
function Miller_Rabin(times) {
if ((KEY_TYPE in this) || this[KEY_EXPONENT] < 0
//得允許 {Integer}exponent。
//|| !Number.isSafeInteger(exponent) || exponent < 0
)
return;
// assert: (this) is integer, (this) % 2 = 1, (this) > 4
var n_1 = (new Integer(this, DECIMAL_BASE)).add(-1), d = n_1.clone(), s = 0, a, x;
while (d[0] % 2 === 0)
s++, d = d.division(2);
// assert: s > 0
if (!(times |= 0))
times = 2;
for (var prime_index = 0; prime_index < times;) {
// 3rd 起應該用大數( > 307) 偵測。
a = new Integer(get_prime(++prime_index + (prime_index < 3 ? 0 : 60)));
x = a.power_modulo(d, this);
if (x.is_0(1) || x.compare_amount(n_1) === 0)
continue;
var i = 1, j = 1;
for (; i < s; i++) {
x.square().division(this);
if (x.is_0(1))
return true;
if (x.compare_amount(n_1) === 0) {
j = 0;
break;
}
}
if (j)
// composite
return true;
}
// probable prime to base 2, 3.
// probable prime (PRP), probably prime
// https://en.wikipedia.org/wiki/Probable_prime
}
var get_prime = library_namespace.data.math.prime,
math_not_prime = library_namespace.data.math.not_prime,
math_factorize = library_namespace.data.math.factorize,
// copy from data.math
sqrt_max_integer = Math.sqrt(Number.MAX_SAFE_INTEGER) | 0;
// return false: number: min factor, is prime, true: not prime, undefined: maybe prime (unknown)
// ** modified from data.math.not_prime()
function not_prime(limit) {
var integer = this.valueOf();
if (Number.isSafeInteger(integer) && !(sqrt_max_integer < integer))
return math_not_prime(integer);
if ((KEY_TYPE in this) || this[KEY_EXPONENT] < 0)
return;
// 可先檢測此數是否在質數列表中。
if (!limit)
//迫於未能使用好的演算法,只好限制使用時間。
limit = 1e5;
// 採用試除法, trial division 檢測小質數整除性。
var prime, index = 1;
while (prime = get_prime(index++, limit))
if (this.clone().modulo(prime).is_0())
return this.compare_amount(prime) !== 0 && prime;
library_namespace.debug('not_prime: 由於所測試的質數 '
+ prime + ' 已大於 limit ' + limit
+ ',因此不再試除 [' + this.toString() + ']。', 3);
return this.Miller_Rabin();
// TODO: https://en.wikipedia.org/wiki/Baillie%E2%80%93PSW_primality_test
// TODO: https://en.wikipedia.org/wiki/Lucas_pseudoprime
}
// Pollard's rho algorithm is a general-purpose integer factorization algorithm.
// https://en.wikipedia.org/wiki/Pollard's_rho_algorithm
// The first rho method used random walks to find factors
// https://sites.google.com/site/jmptidcott2/nthy
function Pollards_rho_1975() {
for (var x = new Integer(2), y = x.clone(), d; ;) {
// f(x) = (x^2 + 1) % N
x.square().add(1).division(this);
y.square().add(1).division(this);
y.square().add(1).division(this);
//when n is a prime number, d will be always 1.
d = Integer_GCD(y.clone().add(x, true).abs(), this.clone());
if (d !== 1)
return this.compare_amount(d) !== 0 && d;
}
}
// http://maths-people.anu.edu.au/~brent/pub/pub051.html
// https://github.com/search?q=Pollard+rho+Brent+factor&type=Code
// http://comeoncodeon.wordpress.com/2010/09/18/pollard-rho-brent-integer-factorization/
// WARNING: 雖然此演算法或可得到因子,但對於過大因子,將耗費大量時間!例如為十位數以上之質數時,恐得使用五分鐘以分解!
// WARNING: Note that this algorithm may not find the factors and will return failure for composite n. In that case, use a different f(x) and try again.
function Pollards_rho_1980() {
if ((KEY_TYPE in this) || this[KEY_EXPONENT] < 0)
// Invalid integer to factorize
return;
if (this.clone().modulo(2) === 0 || this.clone().modulo(3) === 0)
return false;
// reset initial value
// assert: this > max(y, m, c)
var y = new Integer(get_prime(2 + Math.random() * 1e3 | 0)),
m = get_prime(2 + Math.random() * 1e3 | 0),
c = get_prime(2 + Math.random() * 1e3 | 0),
r = 1, q = new Integer(1), x, i, k, ys, G;
do {
for (x = y.clone(), i = r; i--;)
// f(x) = (x^2 + c) % N
y.square().add(c).division(this);
k = 0;
do {
for (ys = y, i = Math.min(m, r - k) ; i-- ;) {
// f(x) = (x^2 + c) % N
y.square().add(c).division(this);
q.multiply(x.clone().add(y, true).abs()).division(this);
}
G = Integer_GCD(q.clone(), this.clone());
k += m;
} while (k < r && G === 1);
r *= 2;
// TODO: 當 r 過大,例如為十位數以上之質數時,過於消耗時間。
} while (G === 1);
if (this.compare_amount(G) === 0)
do {
// f(x) = (x^2 + c) % N
ys.square().add(c).division(this);
G = Integer_GCD(x.clone().add(ys, true).abs(), this.clone());
} while (G === 1);
return this.compare_amount(G) !== 0 && G;
}
// TODO: the elliptic curve method (ECM)
/**
* 取得某數的質因數分解,整數分解/因式分解/素因子分解, prime factorization, get floor factor.
* 唯一分解定理(The Unique Factorization Theorem)告訴我們素因子分解是唯一的,這即是稱為算術基本定理 (The
* Fundamental Theorem of Arithmeric) 的數學金科玉律。
*
* ** modified from data.math.factorize()
*
* @param {Number}radix
* output radix
* @param {Number}limit
* maximum prime to test
*
* @return {Object}factor {prime1:power1, prime2:power2, ..}
*
* @see Factorizations of 100...001
* https://en.wikipedia.org/wiki/Integer_factorization
*/
function factorize(radix, limit) {
var integer = this.valueOf();
if (Number.isSafeInteger(integer))
return math_factorize(integer, radix);
if ((KEY_TYPE in this) || this[KEY_EXPONENT] < 0) {
library_namespace.error('factorize: Invalid integer: [' + this.toString() + '].');
return;
}
if (!limit)
//迫於未能使用好的演算法,只好限制使用時間。
limit = 1e6;
if (!valid_radix(radix))
// IE8 中,無法使用 Number.toString(undefined)。
//radix = undefined;
radix = DEFAULT_RADIX
integer = this.clone();
delete integer[KEY_NEGATIVE];
var prime, index = 1, factors = Object.create(null), power,
get_sqrt = function () {
sqrt = Math.floor(integer.clone().square_root().valueOf());
}, sqrt = get_sqrt();
Object.defineProperty(factors, 'toString', {
enumerable: false,
value: math_factorize._toString
});
for (; ;) {
// 採用試除法, trial division。
if (integer.clone().modulo(prime = get_prime(index++)).is_0()) {
for (power = 1; (integer = integer.division(prime)).clone().modulo(prime).is_0() ;)
power++;
factors[prime.toString(radix)] = power;
if (integer.is_0(ZERO_EXPONENT))
return factors;
if (Number.isSafeInteger(sqrt = integer.valueOf())) {
//use data.math.factorize();
sqrt = math_factorize(sqrt, radix, index);
for (prime in sqrt)
factors[prime] = sqrt[prime];
return factors;
}
get_sqrt();
}
if (sqrt < prime) {
// assert: integer is now prime.
factors[integer.toString(radix)] = 1;
return factors;
}
if (limit < prime) {
if (false) {
if (integer.Miller_Rabin())
library_namespace.warn('factorize: 由於所測試的質數 ' + prime + ' 已大於 limit ' + limit
+ ',因此不再試除餘下之合數因子 [' + integer.toString() + '];您有必要自行質因數分解此數!');
factors[integer.toString(radix)] = 1;
}
prime = [];
power = function (i) {
if (i.not_prime()) {
var p, count = 3;
while (count-- && !(p = i.Pollards_rho()));
if (p) {
power(p = Integer(p));
power(i.clone().division(p));
return;
} else
library_namespace.warn('factorize: 無法分解'
+ (library_namespace.is_debug() && i.Miller_Rabin() ? '合數' : '') + '因子 [' + i.toString() + '];您或許有必要自行質因數分解此數!');
}
prime.push(i);
};
power(integer);
prime.sort(Integer_compare);
prime.forEach(function (p) {
p = p.toString(radix);
if (p in factors)
factors[p]++;
else
factors[p] = 1;
});
return factors;
}
}
}
var summation_cache = {
// cache of mathematical constant ℯ
E: new Integer(Math.E.toString(), DEFAULT_RADIX, DEFAULT_RADIX),
// cache of mathematical constant ln 2
LN2: new Integer(Math.LN2.toString(), DEFAULT_RADIX, DEFAULT_RADIX),
// cache of mathematical constant ln 10
LN10: new Integer(Math.LN10.toString(), DEFAULT_RADIX, DEFAULT_RADIX),
// cache of mathematical constant π
PI: new Integer(Math.PI.toString(), DEFAULT_RADIX, DEFAULT_RADIX)
};
//@inner
// https://en.wikipedia.org/wiki/Summation#Capital-sigma_notation
function summation(name, operation, precision, initial_value, error_digits) {
if (Number.isSafeInteger(precision |= 0) && (!name || summation_cache[name].length < precision)) {
var sum = new Integer(isNaN(initial_value) ? 1 : initial_value);
if (!error_digits)
error_digits = 1;
//欲取的位數。
shift_digits(sum, -Math.ceil(precision / DECIMAL_BASE_LENGTH) - error_digits);
// operation(sum): main loop of summation
sum = new Integer((operation(sum) || sum).to_precision(-error_digits), DEFAULT_RADIX);
if (name)
summation_cache[name] = sum;
name = sum;
} else
name = summation_cache[name];
return name.clone().to_precision(precision);
}
//自然對數函數的底數
// https://en.wikipedia.org/wiki/E_(mathematical_constant)
// calculate mathematical constant ℯ ≈
// TODO: 誤差範圍評估/估計
// https://en.wikipedia.org/wiki/Errors_and_residuals_in_statistics
function Integer_E(precision) {
return summation('E', function (E) {
for (var index = 0, addend = E.clone() ;
!(addend = addend.division(++index)).is_0() ;)
E.add(addend);
}, precision);
}
//return ℯ^exponent
//Integer_exp({Number}real number exponent, precision)
// https://en.wikipedia.org/wiki/Exponential_function
function Integer_exp(exponent, precision) {
var l, error_digits = 2,
//
integer_part = is_Integer(exponent) && exponent[KEY_BASE] === DEFAULT_BASE;
if (!integer_part)
exponent = new Integer(exponent, null, DEFAULT_BASE);
if ((KEY_TYPE in exponent) || exponent.is_0())
// 不處理虛數與複數。
// do simulation: 模擬與 NaN 等極端數字作運算。
return Math.exp(exponent.valueOf(TYPE_TEST));
if (exponent[KEY_NEGATIVE]) {
// negative exponent.
delete exponent[KEY_NEGATIVE];
shift_digits(l = new Integer(1), -precision - error_digits);
return l.division(Integer_exp(exponent, precision + error_digits)).to_precision(precision);
}
if (exponent.is_0(1))
return Integer_E(precision);
// 至此特殊值處理完畢。
if (exponent[KEY_EXPONENT] < 0)
if (0 < exponent.length + exponent[KEY_EXPONENT] && 9 < (l = exponent.valueOf())) {
//分成兩部分處理以加快速度: exp(40.3) = exp(40) * exp(.3)。
if (integer_part)
exponent = exponent.clone();
return Integer_exp(integer_part = l | 0, precision + error_digits)
//fractional part 分數/小數部分
.multiply(Integer_exp(exponent.add(-integer_part), precision + error_digits))
.to_precision(precision);
} else if (0 < (l = exponent.length - Math.ceil(precision / DECIMAL_BASE_LENGTH) - error_digits)) {
//過精細的 exponent 無用。
if (integer_part)
exponent = exponent.clone();
shift_digits(exponent, l);
}
return summation(null, function (exp) {
//1 - exp[KEY_EXPONENT] for precision
for (var index = 0, addend = exp.clone(), digits = error_digits - exp[KEY_EXPONENT];
//截斷 addend 以加速運算。
digits < addend.length && shift_digits(addend, addend.length - digits),
!(addend = addend.multiply(exponent).division(++index)).is_0()
//當數值過小,即使非 0 亦無意義。
&& exp[KEY_EXPONENT] < addend.length + addend[KEY_EXPONENT];)
digits < exp.add(addend).length && shift_digits(exp, exp.length - digits);
}, precision, undefined, error_digits);
}
// https://en.wikipedia.org/wiki/Natural_logarithm_of_2#Series_representations
// https://en.wikipedia.org/wiki/Logarithm#Power_series
function Integer_LN2(precision) {
return summation('LN2', function (LN2) {
// TODO: no clone
var index = 1, d = LN2.clone(), addend;
while (!(addend = (d = d.division(9)).clone().division(index += 2)).is_0())
LN2.add(addend);
return LN2.division(3);
}, precision, 2, 1);
}
// https://en.wikipedia.org/wiki/Logarithm#Power_series
function Integer_LN10(precision) {
return summation('LN10', function (LN10) {
for (var index = 1, d = LN10.clone(), addend;
!(addend = (d = d.division(81)).clone().division(index += 2)).is_0() ;)
LN10.add(addend);
return LN10.division(9).add(Integer_LN2(precision + 1).multiply(3));
}, precision, 2);
}
//@inner
// https://en.wikipedia.org/wiki/Natural_logarithm
// https://en.wikipedia.org/wiki/Logarithm#Power_series
// ln({Integer}power, precision)
function ln(power, precision) {
var error_digits = 1, exponent = Math.ceil((precision |= 0) / DECIMAL_BASE_LENGTH) + error_digits,
//
ln_value = new Integer(2), index, addend, b, d, to_add;
power = new Integer(power, null, DECIMAL_BASE);
//正規化:去除末尾的0。
for (index = 0; index < power.length; index++)
if (power[index]) {
if (index)
shift_digits(power, index);
break;
}
for (d = 0, index = power[0], addend = 10; index % addend === 0;)
d++, to_add = addend, addend *= 10;
if (d)
power = power.division(to_add);
//至此處理完 10 ^ d 的部分。
for (b = 0, index = power[0], addend = 2; index % addend === 0;)
b++, to_add = addend, addend *= 2;
if (b)
power = power.division(to_add);
//let 1 <= power < 2 以加速 main loop 運算。
//先使 power 首位 [power.length - 1] < 2。
while (power.at(-1) > 1) {
if (power[0] % 2 === 1)
//預防失去精度。
shift_digits(power, -1);
b++, power = power.division(2);
}
// assert: 1 <= power.at(-1)
//至此處理完 2 ^ b 的部分。
//再使 power 首位 power.at(-1) 之 exponent 為 0。
if (to_add = (index = power.length - 1) + power[KEY_EXPONENT]) {
d += to_add * DECIMAL_BASE_LENGTH;
power[KEY_EXPONENT] = -index;
}
// assert: 1 <= power < 2, power.at(-1) === ZERO_EXPONENT === 1
if (d)
d = Integer_LN10(precision + error_digits * DECIMAL_BASE_LENGTH).multiply(d);
if (b) {
to_add = Integer_LN2(precision + error_digits * DECIMAL_BASE_LENGTH).multiply(b);
if (d)
to_add.add(d);
} else
to_add = d || 0;
if (!index)
return to_add ? to_add.to_precision(-error_digits * DECIMAL_BASE_LENGTH) : new Integer(0, DEFAULT_RADIX);
// assert: 1 < power < 2, power.at(-1) === ZERO_EXPONENT === 1
d = power.clone();
d[index = d.length - 1] = 2;
b = power.clone();
if (Array.isArray(b))
b.pop();
else
b[index] = 0;
// assert: now: d = power + 1, b = power - 1
//d = ( (power + 1) / (power - 1) ) ^ 2
d = d.division(b, exponent).square().to_precision(exponent);
//簡化d,去掉末尾的 0。
index = 0;
while (index < d.length && !d[index])
index++;
if (index)
shift_digits(d, index);
//初始化 ln_value, b, ..
shift_digits(ln_value, -exponent);
b = ln_value.clone();
index = 1;
// main loop of summation
while (!(addend = (b = b.division(d, exponent)).clone().division(index += 2)).is_0())
ln_value.add(addend);
d = power.clone();
d[index = d.length - 1] = 2;
// assert: now: d = power + 1
if (Array.isArray(power))
power.pop();
else
power[index] = 0;
ln_value = new Integer(ln_value.multiply(power).division(d), DEFAULT_RADIX);
if (to_add)
ln_value.add(to_add);
return ln_value.to_precision(precision);
}
//Logarithm: log _ base(power) = exponent
// https://en.wikipedia.org/wiki/Logarithm
//default base: e
//this.log({Number}real number base, precision)
//return {Number|Integer}
function log(base, precision) {
if (this[KEY_NEGATIVE] || (KEY_TYPE in this) || this.is_0() || this.is_0(1) || base && !isFinite(+base))
// 不處理虛數與複數。
// do simulation: 模擬與 NaN 等極端數字作運算。
return Math.log(this.valueOf(TYPE_TEST)) / (base ? Math.log(+base) : 1);
// 至此特殊值處理完畢。
var base_exponent = 0, value = this, remainder, quotient;
if (base) {
base = new Integer(quotient = base, null, this[KEY_BASE]);
if (base[KEY_TYPE] || !(base.compare(ZERO_EXPONENT) > 0)) {
library_namespace.error('log: Invalid base: [' + quotient + '].');
return NaN;
}
// 盡量取得整數次方。
for (; ; base_exponent++, value = quotient) {
remainder = value.clone();
quotient = remainder.division(base);
if (!remainder.is_0())
break;
}
// assert: is_Integer(base)
// assert: this = value * base ^ {0|natural number}base_exponent in base
// assert: value === value % base > 0
}
if (precision |= 0) {
//+ 1: error digits
value = ln(value, precision + (base ? 1 : 0));
if (base) {
if (!value.is_0())
value = value.division(ln(base, precision + 1));
if (base_exponent)
value.add(base_exponent);
}
return value.to_precision(precision);
}
//將 value 轉成可表現之最大精度 {Number}。
value = value.valueOf(TYPE_info_for_large);
value = typeof value === 'number' ? Math.log(Math.abs(value))
// assert: value = [{Number}large value, {0|natural number}exponent in this[KEY_BASE]]
: value[1] * Math.log(this[KEY_BASE]) + Math.log(Math.abs(value[0]));
if (base) {
if (value)
value /= base.log();
value += base_exponent;
}
return value;
}
// Exponentiation 冪/乘方: base ^ exponent = power
// https://en.wikipedia.org/wiki/Exponentiation
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
// {natural number}exponent
// {natural number}modulus = base^this.exponent
// this.power({Number}real number exponent, precision)
function power(exponent, precision) {
exponent = Integer(exponent);
if (exponent.is_0(1))
return this;
if (this[KEY_NEGATIVE] || (KEY_TYPE in this) || this.is_0() || this.is_0(1) || (KEY_TYPE in exponent) || exponent.is_0())
// 不處理虛數與複數。
// do simulation: 模擬與 NaN 等極端數字作運算。
return this.assignment(Math.pow(this.valueOf(TYPE_TEST), exponent.valueOf(TYPE_TEST)));
if (exponent[KEY_NEGATIVE]) {
//負數
delete exponent[KEY_NEGATIVE];
exponent = this.clone().power(exponent);
return this.assignment((new Integer(1)).division(exponent, precision));
}
var integer_part = exponent.valueOf() | 0, error_digits = 2, _precision = (precision || 2 * DECIMAL_BASE_LENGTH) + error_digits;
if (!Number.isSafeInteger(integer_part)) {
library_namespace.error('power: Invalid exponent: [' + exponent + '] (exponent too large, overflowed / underflowed).');
return this.assignment(this.compare(1) < 0 ? 0 : Infinity);
}
// 至此特殊值處理完畢。
exponent = exponent[KEY_EXPONENT] === 0 ? 0
// has a fractional part (有小數部分)
// v ^ e = exp ^ (e ln v)
: Integer_exp(exponent.add(-integer_part).multiply(ln(this, _precision)), _precision);
if (integer_part) {
//處理 integer part 整數部分。
_precision = precision && 2 * (precision + error_digits);
for (var product = this ; ;) {
if (integer_part % 2 === 1)
if (product !== this) {
// array multiply: this *= product
this.multiply(product);
if (_precision && this.length > _precision)
this.to_precision(_precision);
} else if (1 < integer_part)
product = this.clone();
if ((integer_part >>= 1) === 0)
break;
product.square();
}
if (exponent)
this.multiply(exponent);
} else
// assert: exponent != 0
this.assignment(exponent);
if (precision)
(new Integer(this, DEFAULT_RADIX)).to_precision(precision).clone(this);
return this;
}
// https://en.wikipedia.org/wiki/Pi
// https://en.wikipedia.org/wiki/List_of_formulae_involving_%CF%80#Efficient_infinite_series
// calculate mathematical constant π ≈
function Integer_PI(precision) {
return summation('PI', function (PI) {
for (var index = 0, addend = PI.clone() ;
!(addend = addend.multiply(++index).division(2 * index + 1)).is_0() ;)
PI.add(addend);
}, precision, 2, 2);
}
// ---------------------------------------------------------------------//
return Integer;
}
});