Revert "permet l'ajout des frameworks et des routes"

This reverts commit 361112699c
This commit is contained in:
Dario Duchateau-weinberger
2023-09-25 09:44:12 +02:00
parent 361112699c
commit 20cb812095
2787 changed files with 0 additions and 864804 deletions

View File

@@ -1,273 +0,0 @@
/**
* @name CeL Hamming function
* @fileoverview 本檔案包含了 Hamming Code, 漢明碼的 functions。
* @since 2010/3/21 14:26:08
* @example <code>
CeL.run('data.math.Hamming');
var hc = CeL.Hamming.encode('1100');
TODO:
最佳化
calculate generator matrix
SEC-DED ("single error correction, double error detection") 版本(加在最後)
http://www.ee.unb.ca/cgi-bin/tervo/hamming.pl
最小漢明距離3
http://phpbb.godfat.org/viewtopic.php?t=66&sid=6e34dd040aa98c64c75bfe099008c82a
BCH碼
</code>
*/
// More examples: see /_test suite/test.js
'use strict';
// 'use asm';
// --------------------------------------------------------------------------------------------
// 不採用 if 陳述式,可以避免 Eclipse JSDoc 與 format 多縮排一層。
typeof CeL === 'function' && CeL.run({
// module name
name : 'data.math.Hamming',
// require : '',
// 設定不匯出的子函式。
no_extend : '*',
// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
code : module_code
});
function module_code(library_namespace) {
// nothing required
var module_name = this.id;
// ============================================================================
// definition of module Hamming
var
/**
* Hamming code
*
* @class Hamming Code 的 constructor
* @constructor
*/
_// JSDT:_module_
= function() {
return this.encode.apply(this, arguments);
};
// class public interface ---------------------------
_// JSDT:_module_
.
/**
* 是否左右顛倒。 default: data[1,2,..] 左至右, reverse: data[..,2,1] 右至左
*
* @_memberOf _module_
*/
reverse = false;
_// JSDT:_module_
.
/**
* encode data to Hamming Code.
*
* @param data
* data stream
* @param no_reverse
* forced NO reverse
* @return {String} encoded Hamming Code
* @_memberOf _module_
*/
encode = function(data, no_reverse) {
data = (Array.isArray(data) ? data.join('') : '' + data).replace(
/[ ,]/g, '');
if (!/^[01]{1,20}$/.test(data))
return '';
if (this.reverse && !no_reverse)
data = data.split('').reverse().join('');
if (false)
library_namespace.debug('encode [' + d + ']', 1, module_name
+ '.encode');
var g = [ '' ], i_g = 1, bin = 1, i, i_d = 0, l_d = data.length, ch;
for (;; i_g++) {
if (i_g === bin) {
if (false)
library_namespace.debug('initial [' + g.length + '] as 0',
1, module_name + '.encode');
g.push(0);
bin *= 2;
} else {
if (false)
library_namespace.debug('initial [' + g.length + '] as '
+ d.charAt(i_d) + ' (' + i_d + '/' + l_d + ')', 1,
module_name + '.encode');
g.push(ch = data.charAt(i_d));
for (i = 1; i < bin; i *= 2)
if (i_g & i)
g[i] ^= ch;
if (++i_d === l_d)
break;
}
}
if (library_namespace.is_debug(2)) {
// for debug print
for (bin = i = 1, i_d = []; i < g.length; i++) {
ch = g[i];
if (i === bin)
ch = '<span style="color: #292;">' + ch + '</span>',
bin *= 2;
// i_d 在這表示一個專門用於顯示的 array
i_d.push(ch);
}
library_namespace.log('Hamming code of [' + data + ']: ['
+ i_d.join('') + ']');
}
if (this.reverse && !no_reverse)
g = g.reverse();
return g.join('');
};
_// JSDT:_module_
.
/**
* 將 Hamming Code 分成 data & check bits
*
* @param code
* Hamming Code to split
* @return [資料位元 data bits, 檢查位元 check bits (parity bits)]
* @_memberOf _module_
*/
split_code = function(code) {
if (Array.isArray(code))
code = code.join('');
code = (' ' + code).split('');
library_namespace.debug('split [' + code + ']', 1, module_name
+ '.split_code', 3);
var i = 1, l = code.length, cb = [];
while (i < l) {
cb.push(code[i]);
code[i] = '';
i *= 2;
}
library_namespace.debug('→ data [' + code.join('').replace(/ +/g, '')
+ '], check bits [' + cb + ']', 1,
module_name + '.split_code', 3);
return [ code.join('').replace(/ +/g, ''), cb ];
};
_// JSDT:_module_
.
/**
* decode Hamming Code to data
*
* @param code
* @return
* @_memberOf _module_
*/
decode = function(code) {
if (!code
|| !/^[01]{3,30}$/
.test(code = ('' + code).replace(/[ ,]/g, '')))
return '';
code = code.split('');
if (this.reverse)
code = code.reverse();
var i = 0, l = code.length, ch, bin = 1, split_c = this
.split_code(code), test_c, cb;
if (!split_c)
return;
// check bits (parity bits)
cb = split_c[1];
test_c = this.encode(split_c[0], 1);
if (!test_c || !(test_c = this.split_code(test_c)))
return;
library_namespace.debug('received check bits: [' + cb.join('')
+ '], calculated: [' + test_c[1].join('') + ']', 1, module_name
+ '.decode');
test_c = parseInt(test_c[1].reverse().join(''), 2)
^ parseInt(cb.reverse().join(''), 2);
library_namespace.debug('error bit'
+ (this.reverse ? ' (do reversed XOR)' : '') + ': ' + test_c
+ '(' + test_c.toString(2) + '), ' + code.join(''), 1,
module_name + '.decode');
if (test_c)
if (test_c < code.length) {
code[test_c - 1] ^= 1;
split_c = this.split_code(code);
} else {
// 這算是能檢測出 2 bits 以上錯誤的特殊例子,機率通常也不大:已經超過 index 了。
// e.g., reversed 011010001100
library_namespace.debug(
'<em>Out of index!</em> More than 2 errors occurred.',
1, module_name + '.decode');
}
if (library_namespace.is_debug())
if (test_c) {
cb = code.join('\0').split('\0');
cb[test_c - 1] = '<span style="color:#f33;">' + cb[test_c - 1]
+ '</span>';
library_namespace.debug('→ ' + cb.join(''), 1, module_name
+ '.decode');
} else
library_namespace.debug('The Hamming code is correct.', 1,
module_name + '.decode');
split_c = split_c[0];
if (this.reverse)
split_c = split_c.split('').reverse().join('');
return split_c;
};
_// JSDT:_module_
.
/**
* 顯示 Hamming Code 的計算方法
*
* @param {Number}
* bit_length bit length. e.g., 8, 16.
* @_memberOf _module_
*/
show = function(bit_length) {
var code = [], bit = [], parity = [], i = 1, j, k, d = 1, a = 1, cc = 1, dc = 1;
for (;; i++) {
bit[i] = i.toString(2);
if (i === a) {
code[i] = 'C' + Math.pow(2, cc++ - 1);
a *= 2;
} else {
code[i] = 'D' + dc++;
for (j = 1, k = 1; j < cc; j++, k *= 2)
if (i & k)
if (parity[j])
parity[j] += '<span style="color:#aaa;">⊕</span>'
+ code[i];
else
parity[j] = code[i];
if (dc > bit_length)
break;
}
}
for (i = 1; i < code.length; i++) {
a = code[i];
if (j = a.match(/^C(\d+)$/))
a += ' = '
+ parity[Math.round(Math.log(j[1]) * Math.LOG2E) + 1];
library_namespace.debug(bit[i] + ': ' + a);
}
};
return (_// JSDT:_module_
);
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

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

Binary file not shown.

View File

@@ -1,816 +0,0 @@
/**
* @name CeL rational number function
* @fileoverview
* 本檔案包含了分數/有理數 (rational number)/比例值 (ratio) 的 functions相當/類似於 BigRational, BigQuotient (numerator and denominator), BigDecimal。<br />
* 在純 javascript 的環境下,藉由原生計算功能,盡可能提供高效的大數計算。<br />
*
* @example
* <code>
* CeL.run('data.math.rational');
* </code>
*
* @since 2013/9/8 13:42:58
* @see
* https://en.wikipedia.org/wiki/Rational_number
*/
/*
TODO:
以 BigInt() 重寫。
http://reference.wolfram.com/mathematica/ref/RootApproximant.html
規格書:
rational = new Rational(numerator, denominator, base);
rational = new Rational(10783, 2775);
rational = new Rational('10783/2775');
rational = new Rational('3+2458/2775');
rational = new Rational('3 2458/2775');
//https://en.wikipedia.org/wiki/Vinculum_(symbol)
rational = new Rational('3.88¯576');
//Brackets
rational = new Rational('3.88(576)');
numerator 10783
denominator 2775
integer part 整數部分 == quotient == continued fraction[0]
fractional part 分數/小數部分 == remainder / denominator
mixed fraction 帶分數 == integer part + fractional part
vulgar fraction 真分數/假分數 ==
decimal approximation (numerical value) 無限小數 3.88576576576576576576576576
//https://en.wikipedia.org/wiki/Overline#Math_and_science
repeating decimal 循環小數 3.88¯576
continued fraction 連分數 == [3; 1, 7, 1, 3, 15, 1, 1, 2]
Egyptian fraction expansion 古埃及分數
最簡分數(irreducible fraction, reduced proper fraction)
約分 reduce
*/
'use strict';
if (typeof CeL === 'function')
CeL.run(
{
name: 'data.math.rational',
require: 'data.code.compatibility.|data.native.|data.math.integer.',
no_extend: 'random,compare',
code: function (library_namespace) {
// requiring
var Integer = library_namespace.data.math.integer,
// radix point / radix character / decimal mark
radix_point = Integer.radix_point(),
// 為正規 radix。
valid_radix = Integer.valid_radix,
DEFAULT_BASE = Integer.DEFAULT_BASE
;
// ---------------------------------------------------------------------//
// basic constants. 定義基本常數。
var
// copy from data.math
MULTIPLICATIVE_IDENTITY = library_namespace.MULTIPLICATIVE_IDENTITY,
// copy from data.math
ZERO_EXPONENT = library_namespace.ZERO_EXPONENT,
// copy from data.math.integer.
//{Integer}
KEY_NUMERATOR = 'numerator',
//{Integer|Undefined}integer > 0
KEY_DENOMINATOR = 'denominator',
//{Boolean|Undefined}最簡分數
KEY_IRREDUCIBLE = 'irreducible',
// 應與 parseInt() 一致。
DEFAULT_RADIX = parseInt('10'),
// 可辨認之數字字串。
// [ full , sign, integer part 整數部分, sign of fractional part 小數部分, numerator, denominator ]
PATTERN_FRACTION = /([+\-]?)(?:(\d+)([ +\-]))?(\d+)\/(\d+)/,
// [ full , sign, integer part 整數部分, fractional part 小數部分, repeating decimal 循環小數1, repeating decimal 循環小數2 ]
PATTERN_DECIMAL = /([+\-]?)(\d*)\.(\d*)(?:¯(\d+)|\((\d+)\))?/
;
// ---------------------------------------------------------------------//
// 初始調整並規範基本常數。
// ---------------------------------------------------------------------//
// 工具函數
function do_modified(rational, not_amount) {
if (!not_amount)
delete rational[KEY_IRREDUCIBLE];
}
// ---------------------------------------------------------------------//
// definition of module integer
/**
* 任意大小、帶正負號的有理數。rational number instance.
*
* @example
* <code>
* </code>
*
* @class Rational 的 constructor
* @constructor
*/
function Rational(number) {
if (!(this instanceof Rational))
return 1 === arguments.length && is_Rational(number) ? number : assignment.apply(new Rational, arguments);
if (arguments.length > 0)
assignment.apply(this, arguments);
}
// instance public interface -------------------
// https://en.wikipedia.org/wiki/Operation_(mathematics)
var OP_REFERENCE = {
'+': add,
'-': subtract,
'*': multiply,
'/': divide,
'^': power,
'=': assignment,
'==': compare
};
Object.assign(Rational.prototype, OP_REFERENCE, {
reduce: reduce,
// 下面全部皆為 assignment例如 '+' 實為 '+='。
assignment: assignment,
// add_assignment
add: add,
// subtract_assignment
subtract: subtract,
// multiply_assignment
multiply: multiply,
// divide_assignment
divide: divide,
div: divide,
power: power,
pow: power,
square: square,
square_root: square_root,
sqrt: square_root,
// 至此為 assignment。
clone: clone,
//https://en.wikipedia.org/wiki/Absolute_value
abs: function (negative) {
do_modified(this, true);
this[KEY_NUMERATOR].abs(negative);
return this;
},
// 變換正負號。
negate: function () {
do_modified(this, true);
this[KEY_NUMERATOR].negate();
return this;
},
is_positive: function () {
return this.compare(0) > 0;
},
is_negative: function () {
return this[KEY_NUMERATOR].is_negative();
},
// 正負符號。
// https://en.wikipedia.org/wiki/Sign_(mathematics)
// https://en.wikipedia.org/wiki/Sign_function
sign: function (negative) {
return this[KEY_NUMERATOR].sign(negative);
},
to_continued_fraction: to_continued_fraction,
to_repeating_decimal: to_repeating_decimal,
integer_part: function () {
var n = this[KEY_NUMERATOR].clone().expand_exponent();
if (KEY_DENOMINATOR in this)
n.divide(this[KEY_DENOMINATOR]);
return n;
},
toPrecision: toPrecision,
factorize: factorize,
log: log,
is_0: function (little_natural) {
return this[KEY_NUMERATOR].is_0(little_natural);
},
isFinite: function () {
return this[KEY_NUMERATOR].isFinite();
},
//compare_amount: compare_amount,
compare: compare,
equals: function (number) {
return this.compare(number) === 0;
},
// is proper fraction
is_proper: function () {
return (KEY_DENOMINATOR in this) && this[KEY_NUMERATOR].compare(this[KEY_DENOMINATOR]) < 0;
},
op: Integer.set_operate(OP_REFERENCE),
valueOf: valueOf,
toString: toString
});
// class public interface ---------------------------
function is_Rational(value) {
return value instanceof Rational;
}
function Rational_compare(number1, number2) {
if (typeof number1 === 'number' && typeof number2 === 'number')
return number1 - number2;
if (!is_Rational(number1))
number1 = new Rational(number1);
return number1.compare(number2);
}
//get the extreme value (極端值: max/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 成 Rational 的效能低下情形!
//但若許多數字不同底,而最大的是 String則可能獲得部分效能。
if (Number.isNaN(compare = Rational_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;
}
// TODO: max
function random(max) {
return new Rational(Integer.random(), Integer.random());
}
function is_0(value, little_natural) {
if (typeof value === 'string')
value = new Rational(value);
return value === (little_natural || 0) || (is_Rational(value) ? value[KEY_NUMERATOR] : Integer(value)).is_0(little_natural);
}
Object.assign(Rational, {
from_continued_fraction: function (sequence, length, base) {
var convergent = Integer.convergent_of(sequence, length, base);
return new Rational(convergent[0], convergent[1]);
},
random: random,
max: function Rational_max() {
// get max()
return extreme(arguments);
},
min: function Rational_min() {
// get min()
return extreme(arguments, true);
},
compare: Rational_compare,
// little_natural: little natural number, e.g., 1
is_0: is_0,
is_Rational: is_Rational
});
// ---------------------------------------------------------------------//
// 因 clone 頗為常用,作特殊處置以增進效率。
function clone() {
var rational = new Rational;
rational[KEY_NUMERATOR] = this[KEY_NUMERATOR].clone();
if (KEY_DENOMINATOR in this)
rational[KEY_DENOMINATOR] = this[KEY_DENOMINATOR].clone();
if (KEY_IRREDUCIBLE in this)
rational[KEY_IRREDUCIBLE] = this[KEY_IRREDUCIBLE];
return rational;
}
function assignment(numerator, denominator, base) {
do_modified(this);
var matched, tmp;
if (is_Rational(numerator)) {
[KEY_DENOMINATOR, KEY_IRREDUCIBLE].forEach(function (key) {
if (key in numerator)
this[key] = numerator[key];
else
delete this[key];
}, this);
this[KEY_NUMERATOR] = numerator = numerator[KEY_NUMERATOR];
} else if (typeof numerator === 'string' && (matched = numerator.match(PATTERN_FRACTION))) {
//rational = new Rational('10783/2775');
//rational = new Rational('3+2458/2775');
//rational = new Rational('3 2458/2775');
if (base === undefined && valid_radix(denominator))
// shift arguments
base = denominator, denominator = undefined;
if (!valid_radix(base))
base = DEFAULT_RADIX;
// [ full , sign, integer part 整數部分, sign of fractional part 小數部分, numerator, denominator ]
if (matched[3] === '-' && matched[1] !== '-')
library_namespace.error('assignment: Invalid number sign!');
this[KEY_DENOMINATOR] = tmp = new Integer(matched[5], base, DEFAULT_BASE);
this[KEY_NUMERATOR] = numerator = new Integer(matched[4], base, DEFAULT_BASE);
if (matched[2])
numerator.add((new Integer(matched[2], base, DEFAULT_BASE)).multiply(tmp));
if (matched[1] === '-')
// 將正負符號擺在 [KEY_NUMERATOR],確保 [KEY_DENOMINATOR] 不為負。
numerator.negate();
} else if (typeof numerator === 'string' && (matched = numerator.match(PATTERN_DECIMAL))) {
//https://en.wikipedia.org/wiki/Vinculum_(symbol)
//rational = new Rational('3.88¯576');
//Brackets
//rational = new Rational('3.88(576)');
if (base === undefined && valid_radix(denominator))
// shift arguments
base = denominator, denominator = undefined;
if (!valid_radix(base))
base = DEFAULT_RADIX;
// [ full , sign, integer part 整數部分, fractional part 小數部分, repeating decimal 循環小數1, repeating decimal 循環小數2 ]
// e.g., 1111.222¯33333 → 1111 + (22233333 - 222) / 99999000
// 處理完小數部分之 numerator。
if (matched[4] || (matched[4] = matched[5])) {
// 有循環節(period)。
numerator = new Integer(matched[3] + matched[4], base, DEFAULT_BASE);
if (matched[3])
numerator.add(new Integer(matched[3], base, DEFAULT_BASE), true);
tmp = (base - 1).toString(base).repeat(matched[4].length);
} else {
// 無循環節(period)。
numerator = new Integer(matched[3] || 0, base, DEFAULT_BASE);
tmp = MULTIPLICATIVE_IDENTITY;
}
if (matched[3])
tmp += '0'.repeat(matched[3].length);
if (tmp === MULTIPLICATIVE_IDENTITY)
delete this[KEY_DENOMINATOR];
else
// assert: {String} tmp
this[KEY_DENOMINATOR] = new Integer(tmp, base, DEFAULT_BASE);
if (matched[2])
numerator.add(new Integer(matched[2], base, DEFAULT_BASE).multiply(this[KEY_DENOMINATOR]));
if (matched[1] === '-')
// 將正負符號擺在 [KEY_NUMERATOR],確保 [KEY_DENOMINATOR] 不為負。
numerator.negate();
this[KEY_NUMERATOR] = numerator;
} else {
delete this[KEY_DENOMINATOR];
if ((this[KEY_NUMERATOR] = numerator = new Integer(tmp = numerator, base, DEFAULT_BASE)).isNaN())
library_namespace.error('assignment: Invalid number: [' + tmp + '].');
// 確保不使用 exponent使 exponent 為 0。
else if ((tmp = numerator.get_exponent()) > 0)
numerator.expand_exponent();
else if (tmp < 0) {
(this[KEY_DENOMINATOR] = new Integer(numerator.get_base(), numerator.get_base()))
.power(-tmp);
numerator.get_exponent(0);
}
}
if (denominator)
// rational = new Rational(10783, 2775);
this.divide(valid_radix(base) && typeof denominator === 'string' ? new Rational(denominator, MULTIPLICATIVE_IDENTITY, base) : denominator);
if ((KEY_DENOMINATOR in this)
&& (!numerator.isFinite()
|| numerator.is_0()
// [KEY_DENOMINATOR] 預設即為 MULTIPLICATIVE_IDENTITY。
|| this[KEY_DENOMINATOR].is_0(MULTIPLICATIVE_IDENTITY)
))
delete this[KEY_DENOMINATOR];
return this;
}
function reduce() {
if ((KEY_DENOMINATOR in this) && !this[KEY_IRREDUCIBLE]) {
var gcd = this[KEY_NUMERATOR].clone().Euclidean_algorithm(this[KEY_DENOMINATOR].clone())[1];
this[KEY_NUMERATOR].divide(gcd);
if (this[KEY_DENOMINATOR].equals(gcd))
delete this[KEY_DENOMINATOR];
else
this[KEY_DENOMINATOR].divide(gcd);
this[KEY_IRREDUCIBLE] = true;
}
return this;
}
/**
* 測試大小/比大小
* @param number the number to compare
* @return {Number} 0:==, <0:<, >0:>
* @_name _module_.prototype.compare_to
*/
function compare(number) {
if (typeof number === 'string')
number = new Rational(number);
if (is_Rational(number) && (KEY_DENOMINATOR in number.reduce()))
return this.reduce()[KEY_NUMERATOR].clone().multiply(number[KEY_DENOMINATOR])
//
.compare(KEY_DENOMINATOR in this ? this[KEY_DENOMINATOR].clone().multiply(number[KEY_NUMERATOR]) : number[KEY_NUMERATOR]);
else {
if (is_Rational(number))
number = number[KEY_NUMERATOR];
return this.reduce()[KEY_NUMERATOR]
//
.compare(KEY_DENOMINATOR in this ? this[KEY_DENOMINATOR].clone().multiply(number) : number);
}
}
// ---------------------------------------------------------------------//
//四則運算,即加減乘除, + - * / (+-×÷)**[=]
//https://en.wikipedia.org/wiki/Elementary_arithmetic
// 正規化(normalize) operand
// return is_Integer
function normalize_operand(operand, rational) {
// TODO: defferent base
return Integer.is_Integer(operand) && operand.get_base() === rational[KEY_NUMERATOR].get_base()
|| is_Rational(operand) && operand[KEY_NUMERATOR].get_base() === rational[KEY_NUMERATOR].get_base()
? operand
: new Rational(operand);
}
// Addition 和: addend + addend = sum
function add(addend, is_subtract) {
if (!is_0(addend = normalize_operand(addend, this))) {
// assert: addend != 0.
do_modified(this.reduce());
addend = Rational(addend);
if (is_Rational(addend) && !(KEY_DENOMINATOR in addend.reduce()))
addend = addend[KEY_NUMERATOR];
// assert: addend is non-Rational or reduced Rational with denominator.
if (is_Rational(addend)
// 分母相同時,直接相加減分子。
? (KEY_DENOMINATOR in this) && addend[KEY_DENOMINATOR].equals(this[KEY_DENOMINATOR])
// 分母相同(=1)時,直接相加減分子。
: !(KEY_DENOMINATOR in this))
this[KEY_NUMERATOR].add(is_Rational(addend) ? addend[KEY_DENOMINATOR] : addend, is_subtract);
// 分母相同,毋須更動。
else {
// n1/d1 ± n2/d2 = (n1d2 ± n2d1)/d1d2
// assert: d1 != d2
var denominator_need_multiply;
if (is_Rational(addend)) {
// 僅在 (KEY_DENOMINATOR in addend) 時,才須處理分母。
if (KEY_DENOMINATOR in this)
//為不干擾 this[KEY_NUMERATOR].add() 之操作,另作 cache。
denominator_need_multiply = addend[KEY_DENOMINATOR];
else
// 為不干擾 addend另外創建。
this[KEY_DENOMINATOR] = addend[KEY_DENOMINATOR].clone();
this[KEY_NUMERATOR].multiply(addend[KEY_DENOMINATOR]);
addend = addend[KEY_NUMERATOR];
}
this[KEY_NUMERATOR].add(KEY_DENOMINATOR in this ? this[KEY_DENOMINATOR].clone().multiply(addend) : addend, is_subtract);
if (denominator_need_multiply)
this[KEY_DENOMINATOR].multiply(denominator_need_multiply);
}
}
return this;
}
// Subtraction 差: minuend subtrahend = difference
function subtract(subtrahend) {
return this.add(subtrahend, true);
}
// Multiplication 乘: multiplicand × multiplier = product
function multiply(multiplier) {
if (!this[KEY_NUMERATOR].isNaN())
if (is_0(multiplier = normalize_operand(multiplier, this))) {
do_modified(this);
this[KEY_NUMERATOR].assignment(this[KEY_NUMERATOR].isFinite() ? 0 : NaN);
delete this[KEY_DENOMINATOR];
} else if (!is_0(multiplier, MULTIPLICATIVE_IDENTITY)) {
do_modified(this.reduce());
if (is_Rational(multiplier) && !(KEY_DENOMINATOR in multiplier.reduce()))
multiplier = multiplier[KEY_NUMERATOR];
// assert: multiplier is non-Rational or reduced Rational with denominator.
if (is_Rational(multiplier)) {
this[KEY_NUMERATOR].multiply(multiplier[KEY_NUMERATOR]);
if (KEY_DENOMINATOR in this)
this[KEY_DENOMINATOR].multiply(multiplier[KEY_DENOMINATOR]);
else
this[KEY_DENOMINATOR] = multiplier[KEY_DENOMINATOR].clone();
} else
this[KEY_NUMERATOR].multiply(multiplier);
}
return this;
}
// Division 除: dividend ÷ divisor = quotient
function divide(denominator) {
if (!this[KEY_NUMERATOR].isNaN())
if (!denominator || is_0(denominator = normalize_operand(denominator, this))) {
do_modified(this);
this[KEY_NUMERATOR].assignment(1 / 0);
delete this[KEY_DENOMINATOR];
} else if (!is_0(denominator, MULTIPLICATIVE_IDENTITY)) {
do_modified(this.reduce());
if (is_Rational(denominator)) {
if (KEY_DENOMINATOR in denominator.reduce())
this[KEY_NUMERATOR].multiply(denominator[KEY_DENOMINATOR]);
denominator = denominator[KEY_NUMERATOR];
}
if (KEY_DENOMINATOR in this)
this[KEY_DENOMINATOR].multiply(denominator);
else
this[KEY_DENOMINATOR] = denominator.clone();
}
return this;
}
// ---------------------------------------------------------------------//
// https://en.wikipedia.org/wiki/Minimal_polynomial_(field_theory)
// return p[{Integer}], p[0] + p[1]*this = 0
function minimal_polynomial() {
this.reduce();
var polynomial = [this[KEY_NUMERATOR], this[KEY_DENOMINATOR]];
// translate to {Number} if possible.
polynomial.forEach(function (coefficient, index) {
var value = coefficient.valueOf();
polynomial[index] = Number.isSafeInteger(value) ? value : coefficient.clone();
});
return polynomial;
}
function continued_fraction_toString() {
return '[' + this.join(',').replace(/,/, ';') + ']';
}
function to_continued_fraction() {
var c = KEY_DENOMINATOR in this
// http://www.mathpath.org/concepts/cont.frac.htm
? this[KEY_NUMERATOR].clone().Euclidean_algorithm(this[KEY_DENOMINATOR].clone())[0]
//
: [this[KEY_NUMERATOR].clone()];
Object.defineProperty(c, 'toString', {
enumerable: false,
value: continued_fraction_toString
});
return c;
}
// precise divide, to repeating decimal
// radix===1: 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 to_repeating_decimal(radix, period_limit) {
return this[KEY_NUMERATOR].precise_divide(this[KEY_DENOMINATOR] || MULTIPLICATIVE_IDENTITY, radix, period_limit);
}
// precision: 不包含小數點,共取 precision 位precision > 0。
function toPrecision(precision) {
if (!(0 < precision) || !Number.isSafeInteger(precision |= 0))
return this.toString();
var d, tmp, is_negative = this[KEY_NUMERATOR].is_negative();
if (precision < 1e2
// 當循環節(period)相對於 precision 過長,採用 .to_repeating_decimal() 無實益。
|| ((KEY_DENOMINATOR in this) && precision < 4 * this[KEY_DENOMINATOR].valueOf())
|| !(d = this.to_repeating_decimal(DEFAULT_RADIX, precision))) {
//general method
d = new Integer(this[KEY_NUMERATOR], DEFAULT_RADIX);
if (KEY_DENOMINATOR in this)
d.divide(tmp = new Integer(this[KEY_DENOMINATOR], DEFAULT_RADIX),
precision + tmp.length + Math.max(tmp.get_exponent(), 0));
d = d.toString();
d = d.match(/(-?\d*)\.(\d+)/) || d.match(/(-?\d*)/);
d = [d[1], d[2] || '', ''];
}
// assert: d = [ {String}integer part, {String}non-repeating fractional part, {String}period (repeating decimal part) ]
if (d[0].length === precision + (is_negative ? 1 : 0) && d[0].charAt(d[0].length - 1) !== '0')
return d[0];
if (is_negative)
//減少負擔。
d[0] = d[0].slice(1);
if (d[0] === '0') {
precision++;
if (tmp = d[1].match(/^0+/))
precision += tmp[0].length;
}
if (d[0].length < precision) {
// 會用到小數部分。
d[0] += radix_point + d[1];
// -2: radix_point, 判斷用之位數1位
if (d[0].length - 2 < precision) {
if (!d[2])
d[2] = '0';
d[0] += d[2].repeat(Math.ceil((precision - d[0].length + 2) / d[2].length));
}
// 34.56 3
d = (5 <= (d[0].charAt(precision + 1) | 0)
? d[0].slice(0, precision) + ((d[0].charAt(precision) | 0) + 1)
: d[0].slice(0, precision + 1));
} else
d = d[0].charAt(0) + radix_point
+ (5 <= (d[0].charAt(precision) | 0)
? d[0].slice(1, --precision) + ((d[0].charAt(precision) | 0) + 1)
: d[0].slice(1, precision))
+ 'e+' + (d[0].length - 1);
return is_negative ? '-' + d : d;
}
// ---------------------------------------------------------------------//
// advanced functions
function factorize(radix, limit) {
var f, d, factors = this.reduce()[KEY_NUMERATOR].factorize(radix, limit);
if (KEY_DENOMINATOR in this) {
d = this[KEY_DENOMINATOR].factorize(radix, limit);
// TODO: sort
for (f in d)
factors[f] = -d[f];
}
return factors;
}
function square() {
do_modified(this.reduce());
this[KEY_NUMERATOR].square();
if (KEY_DENOMINATOR in this)
this[KEY_DENOMINATOR].square();
return this;
}
// Exponentiation 冪/乘方: base ^ exponent = power
// https://en.wikipedia.org/wiki/Exponentiation
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
function power(exponent) {
do_modified(this.reduce());
this[KEY_NUMERATOR].power(exponent);
if (KEY_DENOMINATOR in this)
this[KEY_DENOMINATOR].power(exponent);
return this;
}
// WARNING 注意: this will get floor(sqrt(this)),結果僅會回傳整數!
function square_root(precision) {
do_modified(this.reduce());
if (KEY_DENOMINATOR in this) {
this[KEY_NUMERATOR].divide(this[KEY_DENOMINATOR], precision);
delete this[KEY_DENOMINATOR];
}
this[KEY_NUMERATOR].square_root(precision);
return this;
}
function log(base) {
var value = this[KEY_NUMERATOR].log(base);
if (KEY_DENOMINATOR in this)
value -= this[KEY_DENOMINATOR].log(base);
return value;
}
// ---------------------------------------------------------------------//
// WARNING 注意: 若回傳非 Number.isSafeInteger(),則會有誤差,不能等於最佳近似值。
function valueOf(type) {
var n = this[KEY_NUMERATOR].valueOf(), d;
if (KEY_DENOMINATOR in this)
if (isFinite(d = this[KEY_DENOMINATOR].valueOf()) || isFinite(n))
n /= d;
else
n = this[KEY_NUMERATOR].ratio_to(this[KEY_DENOMINATOR]);
return n;
}
// default: numerator/denominator
// e.g., 1 2/3
var TYPE_MIX = 1,
// e.g., 1.2¯3
TYPE_DECIMAL = 2,
// Parentheses, e.g., 1.2(3)
TYPE_PARENTHESES = 3;
function toString(type) {
if (!(KEY_DENOMINATOR in this))
return this[KEY_NUMERATOR].toString();
var string = this[KEY_NUMERATOR];
if (type === TYPE_DECIMAL || type === TYPE_PARENTHESES) {
string = string.precise_divide(this[KEY_DENOMINATOR]);
if (string[2]) {
string[1] += type === TYPE_DECIMAL
// e.g., 1.2¯3
? '¯' + string[2]
// Parentheses, e.g., 1.2(3)
: '(' + string[2] + ')';
// using the combining overline (U+0305)
// https://en.wikipedia.org/wiki/Vinculum_(symbol)#Computer_entry_of_the_symbol
// https://en.wikipedia.org/wiki/Overline
//string[1] += string[2].replace(/(.)/g, '$1̅');
}
if (string[1])
string[0] += radix_point + string[1];
return string[0];
}
return (type === TYPE_MIX ? (string = string.clone()).division(this[KEY_DENOMINATOR]).toString() + ' ' + string.abs().toString() : string.toString())
//
+ '/' + this[KEY_DENOMINATOR].toString();
}
// ---------------------------------------------------------------------//
return Rational;
}
});