mirror of
https://scm.univ-tours.fr/22107988t/rappaurio-sae501_502.git
synced 2025-08-29 08:45:58 +02:00
Revert "permet l'ajout des frameworks et des routes"
This reverts commit 361112699c
This commit is contained in:
273
app/node_modules/cejs/data/math/Hamming.js
generated
vendored
273
app/node_modules/cejs/data/math/Hamming.js
generated
vendored
@@ -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_
|
||||
);
|
||||
}
|
3412
app/node_modules/cejs/data/math/integer.js
generated
vendored
3412
app/node_modules/cejs/data/math/integer.js
generated
vendored
File diff suppressed because it is too large
Load Diff
BIN
app/node_modules/cejs/data/math/polynomial.js
generated
vendored
BIN
app/node_modules/cejs/data/math/polynomial.js
generated
vendored
Binary file not shown.
646
app/node_modules/cejs/data/math/quadratic.js
generated
vendored
646
app/node_modules/cejs/data/math/quadratic.js
generated
vendored
@@ -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;
|
||||
}
|
||||
|
||||
});
|
BIN
app/node_modules/cejs/data/math/quotient.js
generated
vendored
BIN
app/node_modules/cejs/data/math/quotient.js
generated
vendored
Binary file not shown.
816
app/node_modules/cejs/data/math/rational.js
generated
vendored
816
app/node_modules/cejs/data/math/rational.js
generated
vendored
@@ -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;
|
||||
}
|
||||
|
||||
});
|
Reference in New Issue
Block a user