UNPKG

polyrats

Version:

polynumbers

472 lines (398 loc) 14.1 kB
void function(root){ "use strict" var pns = {} , rats = require('rationals') ; function isInt(input){ return typeof input !== 'object' && parseInt(input, 10) == input } function convertToInt(input){ if ( isInt(input) ) { return parseInt(input, 10) } else { throw new Error('bad format: '+input+(' ('+typeof input+')')) } } function lefttrim(arr, maxDrop){ if ( maxDrop == null ) maxDrop = arr.length-1 while ( arr.length > 1 && arr[0] === 0 && maxDrop > 0 ) { arr.shift() maxDrop-- } return arr } function righttrim(arr){ while ( arr.length > 1 && arr[arr.length-1] === 0 ) { arr.pop() } return arr } function largestNonZeroIndex(arr){ var len = arr.length , i, t; for ( i=0; i<len; i++ ) { if ( Math.abs(arr[i]) > 0) { if ( t === undefined ) t = 0 if ( i > t ) t = i } } return t } function alpha(pow){ pow = pow == null ? 1 : pow var a=[], i = pow; while ( i-- > 0 ) { a.push(0) } a.push(1) return a } function rand(max, min){ var r = Math.floor(Math.random() * (max - min + 1)) + min; return r == 0 ? rand(max, min) : r } function rndp(mindeg, maxdeg, pure){ pure = pure != null ? false : pure var deg = rand(maxdeg == null ? 6 : maxdeg, mindeg == null ? 3 : mindeg) , base = alpha(deg) , common_factor = rand(13, -13) ; return piper(base.map(function(){ var coefficient = rand(13, -13) ; return pure ? coefficient : coefficient * common_factor })) } function degree(arr){ if ( arr == null && this == null ) { throw new Error('missing argument') } var arr = (arr == null) ? this : arr , numerator_degree, denominator_degree ; if ( arr instanceof polyrat ) { numerator_degree = largestNonZeroIndex(arr[0]) denominator_degree = largestNonZeroIndex(arr[1]) return numerator_degree > denominator_degree ? numerator_degree : denominator_degree } else if ( Array.isArray(arr) ) { return largestNonZeroIndex(arr) } else { throw new Error('dafuq') } } function divide(a, b){ var remainder, divisor, k, j, quotient=[] , adeg = degree(a), bdeg = degree(b) ; remainder = a.slice(0) divisor = b.slice(0) for ( k = adeg - bdeg ; k >= 0 ; k-- ) { quotient[k] = Math.floor(remainder[bdeg+k]/divisor[bdeg]) for ( j = bdeg + k ; j >= k ; j-- ) { remainder[j] = remainder[j]-(quotient[k]*divisor[j-k]) } } quotient = righttrim(quotient) remainder = righttrim(remainder) return [quotient, remainder] } function gcd(a, b){ var result = [] , i = 1 , deg_current , deg_last , lead_current , lead_last , divisor , shifts = [[0],[0]] , gcd ; // if any of the elements is 1, return 1 imediatelly if ( (a.length == 1 && a[0] == 1) || (b.length == 1 && b[0] == 1) ) { return piper([1]) } // current element should be the smaller one // last element should be the larger one if ( degree(a) >= degree(b) ) { result[0] = a result[1] = b } else { result[0] = b result[1] = a } while ( result[i] != 0 ) { // degrees of the last and the current elements deg_last = degree(result[i-1]) deg_current = degree(result[i]) // raise the current element to the same power as the last element result[i] = piper(result[i]).times(piper(alpha(deg_last-deg_current)))[0] shifts[i%2].push(deg_last-deg_current) // get the leading coefficient for the last and current element lead_last = result[i-1][result[i-1].length-1] lead_current = result[i][result[i].length-1] // multiply the last and current element with the lead coefficients result[i-1] = result[i-1].map(function(c){return c*lead_current}) result[i] = result[i].map(function(c){return c*lead_last}) // calculate the gcd of all the coefficients from the elements divisor = result[i].concat(result[i-1]).reduce( function(p,c){ return p===0?c:(rats.gcd(p,c)) } ) // divide the last two elements with the gcd result[i-1] = result[i-1].map(function(c){return c/divisor}) result[i] = result[i].map(function(c){return c/divisor}) // calculate the difference between the last and current elements and // drop off the highest power, now zero coefficients result[i+1] = righttrim(result[i-1].map(function(c,j){return c - result[i][j]})) i++ // if we are past 2 iterations and nothing changed // there is no gcd, return 1 if ( result.length > 3 && piper(result[i]) == piper(result[i-2]) && piper(result[i-1]) == piper(result[i-3]) ) { return piper([1]) } } // drop off all the smaller coefficients of 0 which // were introduced by raising return piper(lefttrim(result[i-1], shifts[(i-1)%2].reduce(function(x,y){return x + y}))) } function hashify(){ return '['+this[0].join(',')+']/['+this[1].join(',')+']' } function display(){ //rats display el van baszodva //console.log(rats(this[0][0], this[1][0]).display()) // rahhh return this.degree() === 0 ? rats(this[0][0], this[1][0]).display() : '['+this[0].join(',')+']/['+this[1].join(',')+']' } function toPolynom(α){ α = α == null ? 'α' : α function nom(v){ return v.map(function(c,i){ var O, C, B, P, ac = Math.abs(c); O = ( i == v.length-1 || ac == 0 ) ? '' : c < 0 ? '-' : '+' C = ( ac == 0 || ( i > 0 && ac == 1 ) ) ? '' : ac B = ( i == 0 || ac == 0 ) ? '' : (ac == 1 ? '' : '*')+α P = (i == 0 || i == 1 || ac == 0) ? '' : '^'+i return O + C + B + P }).reverse().join('') } return '('+nom(this[0])+')/('+nom(this[1])+')' } function plus(first, second){ var len, i, left, right, result=[]; len = first.length > second.length ? first.length : second.length for ( i = 0; i < len; i++ ) { left = first[i] !== undefined ? first[i] : 0 right = second[i] !== undefined ? second[i] : 0 result[i] = left+right } return result } function minus(first, second){ var len, i, left, right, result=[]; len = first.length > second.length ? first.length : second.length for ( i = 0; i < len; i++ ) { left = first[i] !== undefined ? first[i] : 0 right = second[i] !== undefined ? second[i] : 0 result[i] = left-right } return result } function times(first, second){ var p, plen, q, qlen, i, j, result=[]; p = first.slice(0) plen = first.length q = second.slice(0) qlen = second.length for ( i=0; i<plen; i++ ) { for ( j=0; j<qlen; j++ ) { if ( result[i+j] === undefined ) result[i+j] = 0 if ( p[i+j] === undefined ) p[i+j] = 0 if ( q[i+j] === undefined ) q[i+j] = 0 result[i+j] = result[i+j]+(p[i]*q[j]) } } return result } function per(first, second){ var result , f = first instanceof polyrat , s = second instanceof polyrat , t = null ; if ( f && s ) { throw new Error ('wtf') result = divide(first, second) //} else if ( f && !s) { // result = input.per(piper(second)) //} else if ( !f && s) { // result = piper(input).per(second) } else { result = piper(first, second) } return result } function pow(first, second){ var i, result=[]; if ( ! isInt( second ) ) { throw new Error('undefined operation, look for roots elsewhere') } i=0 result = first if ( second !== 0 ) { while ( ++i < second ) { result = result.times(first) } } else { result = piper([1]) } return result } function val(first, second){ var n = piper([0]) , d = piper([0]) , len , i , t1 , t2 ; if ( ! ( second instanceof polyrat ) ) { if ( Array.isArray(second) ) { second = piper(second) } else { second = piper([second]) } } len = first[0].length for ( i=0; i < len; i++ ) { t1 = piper([first[0][i]]) t2 = piper(second.pow(i)) n = n.plus(t1.times(t2)) } len = first[1].length for ( i=0; i < len; i++ ) { t1 = piper([first[1][i]]) t2 = piper(second.pow(i)) d = d.plus(t1.times(t2)) } return piper(n, d) } function polyrat(){} polyrat.prototype.hashify = display polyrat.prototype.toString = display polyrat.prototype.degree = degree polyrat.prototype.display = display polyrat.prototype.toPolynom = toPolynom polyrat.prototype.plus = function(input){ var p = this[0] , q = this[1] , r = input[0] , s = input[1] ; return per(plus(times(p, s), times(r, q)), times(q, s)) } polyrat.prototype.minus = function(input){ var p = this[0] , q = this[1] , r = input[0] , s = input[1] ; return per(minus(times(p, s), times(r, q)), times(q, s)) } polyrat.prototype.times = function(input){ var p = this[0] , q = this[1] , r = input[0] , s = input[1] , n = times(p, r) , d = times(q, s) ; return per(n, d) } polyrat.prototype.pow = function (input){ return pow(this, input) } polyrat.prototype.val = function (input){ return val(this, input) } polyrat.prototype.per = function (input){ var p = this[0] , q = this[1] , r = input[0] , s = input[1] , n = times(p, s) , d = times(r, q) ; return per(n, d) } polyrat.prototype.divide = function (input){ return divide(this, input) } polyrat.prototype.leftTr = function (input){ return val(this,piper([input,1])) } polyrat.prototype.compose = function (input){ return compose(this, input) } function piper(numerator, denominator){ var key, idx, t, len, i, n, j, d, intvals, dd, divisor; if ( numerator instanceof polyrat ) { if ( denominator == null ) { return numerator } else if ( denominator instanceof polyrat) { n = times(numerator[0], denominator[1]) d = times(denominator[0], numerator[1]) numerator = n denominator = d } } if ( ! Array.isArray(numerator) ) { throw new Error('invalid argument, array expected instead of '+ numerator+' ('+typeof numerator+')') } else { numerator = numerator.map(convertToInt) } denominator = Array.isArray(denominator) ? denominator.map(convertToInt) : [1] dd = largestNonZeroIndex(denominator) if ( dd === undefined ) { throw new Error('the denominator must not equal 0') } numerator = righttrim(numerator) denominator = righttrim(denominator) if ( dd > 0 ) { divisor = gcd(numerator, denominator) if ( Math.abs(degree(divisor[0])) > 0 || divisor[0][0] !== 1 ) { numerator = divide(numerator, divisor[0])[0] denominator = divide(denominator, divisor[0])[0] } } if ( numerator.length === 1 && Math.abs(numerator[0]) === 0 ) { denominator = [1] } divisor = numerator.concat(denominator).reduce( function(p,c){ return p===0?c:(rats.gcd(p,c)) } ) divisor = denominator[denominator.length-1] * divisor < 0 ? divisor * -1 : divisor numerator = righttrim(numerator.map(function(v){ return v/divisor})) denominator = righttrim(denominator.map(function(v){ return v/divisor})) idx = '['+numerator.join(',')+']/['+denominator.join(',')+']' if ( pns[idx] === undefined ) { pns[idx] = new polyrat pns[idx][0] = numerator pns[idx][1] = denominator } return pns[idx] } piper.polyrat = polyrat piper.rndp = rndp if ( module != undefined && module.exports ) module.exports = piper else root.factory = piper }(this)