math-evalrational
Version:
Evaluates a rational function.
159 lines (140 loc) • 3.71 kB
JavaScript
/* jshint evil:true */
;
// EVAL RATIONAL FACTORY //
/**
* FUNCTION: factory( P, Q )
* Returns a function for evaluating a rational function.
*
* @param {Number[]|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} P - numerator polynomial coefficients sorted in ascending degree
* @param {Number[]|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} Q - denominator polynomial coefficients sorted in ascending degree
* @returns {Function} function for evaluating a rational function
*/
function factory( P, Q ) {
var f;
var r;
var n;
var m;
var i;
// Code generation. Start with the function definition...
f = 'return function evalrational(x){';
// Create the function body...
n = P.length;
// Declare variables...
f += 'var ax,s1,s2;';
// If no coefficients, the function always returns NaN...
if ( n === 0 ) {
f += 'return NaN;';
}
// If P and Q have different lengths, the function always returns NaN...
else if ( n !== Q.length ) {
f += 'return NaN;';
}
// If P and Q have only one coefficient, the function always returns the ratio of the first coefficients...
else if ( n === 1 ) {
r = P[ 0 ] / Q[ 0 ];
f += 'return ' + r + ';';
}
// If more than one coefficient, apply Horner's method to both the numerator and denominator...
else {
// If `x == 0`, return the ratio of the first coefficients...
r = P[ 0 ] / Q[ 0 ];
f += 'if(x===0){return ' + r + ';}';
// Compute the absolute value of `x`...
f += 'if(x<0){ax=-x;}else{ax=x;}';
// If `abs(x) <= 1`, evaluate the numerator and denominator of the rational function using Horner's method...
f += 'if(ax<=1){';
f += 's1 = ' + P[ 0 ];
m = n - 1;
for ( i = 1; i < n; i++ ) {
f += '+x*';
if ( i < m ) {
f += '(';
}
f += P[ i ];
}
// Close all the parentheses...
for ( i = 0; i < m-1; i++ ) {
f += ')';
}
f += ';';
f += 's2 = ' + Q[ 0 ];
m = n - 1;
for ( i = 1; i < n; i++ ) {
f += '+x*';
if ( i < m ) {
f += '(';
}
f += Q[ i ];
}
// Close all the parentheses...
for ( i = 0; i < m-1; i++ ) {
f += ')';
}
f += ';';
// Close the if statement...
f += '}else{';
// If `abs(x) > 1`, evaluate the numerator and denominator via the inverse to avoid overflow...
f += 'x = 1/x;';
m = n - 1;
f += 's1 = ' + P[ m ];
for ( i = m - 1; i >= 0; i-- ) {
f += '+x*';
if ( i > 0 ) {
f += '(';
}
f += P[ i ];
}
// Close all the parentheses...
for ( i = 0; i < m-1; i++ ) {
f += ')';
}
f += ';';
m = n - 1;
f += 's2 = ' + Q[ m ];
for ( i = m - 1; i >= 0; i-- ) {
f += '+x*';
if ( i > 0 ) {
f += '(';
}
f += Q[ i ];
}
// Close all the parentheses...
for ( i = 0; i < m-1; i++ ) {
f += ')';
}
f += ';';
// Close the else statement...
f += '}';
// Return the ratio of the two sums...
f += 'return s1/s2;';
}
// Close the function:
f += '}';
// Create the function in the global scope:
return ( new Function( f ) )();
/**
* returns
* function evalrational( x ) {
* var ax, s1, s2;
* if ( x === 0 ) {
* return P[0] / Q[0];
* }
* if ( x < 0 ) {
* ax = -x;
* } else {
* ax = x;
* }
* if ( ax <= 1 ) {
* s1 = P[0]+x*(P[1]+x*(P[2]+x*(P[3]+...+x*(P[n-2]+x*P[n-1]))));
* s2 = Q[0]+x*(Q[1]+x*(Q[2]+x*(Q[3]+...+x*(Q[n-2]+x*Q[n-1]))));
* } else {
* x = 1/x;
* s1 = P[n-1]+x*(P[n-2]+x*(P[n-3]+x*(P[n-4]+...+x*(P[1]+x*P[0]))));
* s2 = Q[n-1]+x*(Q[n-2]+x*(Q[n-3]+x*(Q[n-4]+...+x*(Q[1]+x*Q[0]))));
* }
* return s1 / s2;
* }
*/
} // end FUNCTION factory()
// EXPORTS //
module.exports = factory;