/** * @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; } });