From 138fbfd7b7918f968c171f91fd0fafdef0fabe4a Mon Sep 17 00:00:00 2001 From: dthwaite Date: Sun, 10 Apr 2016 15:45:53 +0100 Subject: [PATCH] v1.0.14 - fixed simplification of negative fraction bug --- CHANGELOG.md | 3 +++ README.md | 12 ++++++------ lib/N.js | 4 ++-- lib/tpa.js | 16 ++++++++-------- lib/tpa.min.js | 4 ++-- package.json | 2 +- test/tpa.js | 3 +++ 7 files changed, 25 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0473aac..f74de50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## TPA - Total Precision Arithmetic change log +### v1.0.14 (2016-04-10) +* Fixed simplification of negative fraction bug + ### v1.0.13 (2016-04-08) * Upgraded documentation diff --git a/README.md b/README.md index 254a8ba..62f8d41 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ##### tpa.js performs basic arithmetic operations with total precision. -Available on [GitHub](https://github.com/dthwaite/TPA), details on [JSDocs](http://dthwaite.github.io/docs/TPA/1.0.13). See it working: [Demonstration](http://dthwaite.github.io/tpa/) +Available on [GitHub](https://github.com/dthwaite/TPA), details on [JSDocs](http://dthwaite.github.io/docs/TPA/1.0.14). See it working: [Demonstration](http://dthwaite.github.io/tpa/) The main features are: @@ -41,8 +41,8 @@ console.log(n.toString()); // Outputs '3.[3]' ##### Browser: To install it: -* Download `lib/tpa.min.js` from my latest version on GitHub or use their CDN: 'https://cdn.rawgit.com/dthwaite/TPA/v1.0.13/lib/tpa.min.js' -* `tpa.min.js` is a UMD bundle with an export name of `Tpa` +* Download [tpa.min.js](https://github.com/dthwaite/TPA/tree/master/lib/tpa.min.js) from GitHub or use their CDN for my latest version: [v1.0.14](https://cdn.rawgit.com/dthwaite/TPA/v1.0.14/lib/tpa.min.js) +* `tpa.min.js` is a UMD (Universal Module Definition) bundle with an export name of `Tpa` To see how to use it: @@ -70,7 +70,7 @@ Build minified version for browser into lib/tpa.min.js: `npm run build` ### A note about performance -How fast is this library compared to others? Good question. And tricky to answer. It all depends on the operation, the size of the numbers, whether they are fractional or not (many libraries just do integers), whether you call static or instance methods and your run time environment. I spent some time comparing and contrasting and there's no straight answer. Most of the time this library performs quite well in comparison. Sometimes wildy better than most, sometimes not so good and it's difficult to summarise. If performance is really important then you must to do your own analysis specific to your environment and needs to then choose the fastest in your circumstance. If it's not that important then you could do a lot worse than choosing this one. I've focussed on delivering a healthy mix of the features listed earlier. It's not slow, by any means. +How fast is this library compared to others? Good question. And tricky to answer. It all depends on the operation, the size of the numbers, whether they are fractional or not (many libraries just do integers), whether you call static or instance methods and your run time environment. I spent some time comparing and contrasting and there's no straight answer. Most of the time this library performs quite well in comparison. Sometimes wildy better than most, sometimes not so good and it's difficult to summarise. If performance is really important then you must do your own analysis specific to your environment and needs to then choose the fastest in your circumstance. If it's not that important then you could do a lot worse than choosing this one. I've focussed on delivering a healthy mix of the features listed earlier. It's not slow, by any means. ### Usage #### Set up @@ -203,7 +203,7 @@ console.log(Tpa(-3).sign()); // -1 console.log(Tpa(3.3).hasFraction()); // true console.log(Tpa('-3 1/3').frac().toFraction()); // '-0 1/3' console.log(Tpa('-3 1/3').int().toFraction()); // '-3' -console.log(Tpa(22).modulus(3).toString()); // '1' +console.log(Tpa(22).modulus(3).toString()); // '1' console.log(Tpa(-33.5).abs().value()); // 33.5 ``` #### Static methods @@ -224,7 +224,7 @@ console.log(Tpa.add(a,b).value()); // 17 console.log(Tpa.subtract(a,b).value()); // -7 console.log(Tpa.multiply(a,b).value()); // 60 console.log(Tpa.divide(b,a).toFraction());// '2 25/50' -console.log(Tpa.modulus(a,b).value()); // 5 +console.log(Tpa.modulus(a,b).value()); // 5 console.log(Tpa.frac(b).value()); // 0.5 console.log(Tpa.int(b).value()); // 12 console.log(Tpa.abs(-23).value()); // 23 diff --git a/lib/N.js b/lib/N.js index 553d816..8e63b31 100644 --- a/lib/N.js +++ b/lib/N.js @@ -507,11 +507,11 @@ module.exports=(/** @lends module:N*/function() { * @return {String} The full decimal representation of this number */ N.prototype.toString=function() { - var result=this.isNegative() ? '-' : ''; - + var result=''; var test=new N(this).abs().normalise().positivise(); while (!test.isZero()) result=test.divide(N.TEN).lsb()+result; if (result.length==0) result='0'; + if (this.isNegative()) result='-'+result; return result; }; diff --git a/lib/tpa.js b/lib/tpa.js index 302d0e9..081f92f 100644 --- a/lib/tpa.js +++ b/lib/tpa.js @@ -251,7 +251,9 @@ module.exports = (/** @lends module:TPA*/function(globalObj) { //eslint-disable- throw new Error('Simplify() takes an optional numeric argument specifying the maximum number of millisecondsto process'); if (typeof milliseconds=='undefined') milliseconds=100; if (this.isInteger() || this.remainder.numerator.isZero()) return true; - var limit= N.abs(this.remainder.numerator)._roughSqrt().value(); + var isNegative=this.remainder.numerator.isNegative(); + this.remainder.numerator.abs(); + var limit= this.remainder.numerator._roughSqrt().value(); var primes=new N.Primes(); var start=new Date().getTime(); var factor=new N().set(1); @@ -276,9 +278,9 @@ module.exports = (/** @lends module:TPA*/function(globalObj) { //eslint-disable- if (remainder.isZero()) { this.remainder.denominator=denominator; this.remainder.numerator=factor; - return true; + prime=1; } else this.remainder.numerator.multiply(factor); - + if (isNegative) this.remainder.numerator.negate(); // If prime is zero then we never got to finish return prime>0; }; @@ -340,7 +342,7 @@ module.exports = (/** @lends module:TPA*/function(globalObj) { //eslint-disable- }; /** - * @returns {boolean} `true` if this number is equal than zero + * @returns {boolean} `true` if this number is equal to zero */ Tpa.prototype.isZero=function() { this._normaliseRemainder(); @@ -689,8 +691,7 @@ module.exports = (/** @lends module:TPA*/function(globalObj) { //eslint-disable- this.number.subtract(number.number); if (!this.integer) { if (!number.integer && !number.remainder.numerator.isZero()) { - this.remainder.numerator.multiply(number.remainder.denominator); - this.remainder.numerator.subtract(N.temporary(number.remainder.numerator).multiply(this.remainder.denominator)); + this.remainder.numerator.multiply(number.remainder.denominator).subtract(N.temporary(number.remainder.numerator).multiply(this.remainder.denominator)); this.remainder.denominator.multiply(number.remainder.denominator); } this._normaliseRemainder(); @@ -714,8 +715,7 @@ module.exports = (/** @lends module:TPA*/function(globalObj) { //eslint-disable- this.number.add(number.number); if (!this.integer) { if (!number.integer && !number.remainder.numerator.isZero()) { - this.remainder.numerator.multiply(number.remainder.denominator); - this.remainder.numerator.add(N.temporary(number.remainder.numerator).multiply(this.remainder.denominator)); + this.remainder.numerator.multiply(number.remainder.denominator).add(N.temporary(number.remainder.numerator).multiply(this.remainder.denominator)); this.remainder.denominator.multiply(number.remainder.denominator); } this._normaliseRemainder(); diff --git a/lib/tpa.min.js b/lib/tpa.min.js index 17ac3e8..0e516d7 100644 --- a/lib/tpa.min.js +++ b/lib/tpa.min.js @@ -1,6 +1,6 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Tpa = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o=0;i--)this.digits[i]=t.digits[i];this.safemaximum=t.safemaximum}else if("number"==typeof t){if(isNaN(t))throw new Error(e);this.set(Math.trunc(t))}else{if("string"!=typeof t)throw new Error(e);var s="-"==t[0]?-1:1;for(this.digits=[],this.safemaximum=0,i="-"==t[0]||"+"==t[0]?1:0;i=t){for(var s=0,e=0;s0&&0==this.digits[this.digits.length-1];)this.digits.length--;return this},h.prototype.positivise=function(){for(var i=0;i0&&0==this.digits[this.digits.length-1];)this.digits.length--;return this},h.prototype.isNegative=function(){return this.isZero()?!1:this.digits[this.digits.length-1]<0},h.prototype.isZero=function(){return 0==this.normalise().digits.length},h.prototype.isPositive=function(){return this.isZero()?!1:this.digits[this.digits.length-1]>0},h.prototype.lsb=function(){return this.isZero()?0:(t+this.digits[0])%t},h.prototype.reset=function(){return this.digits=[],this.safemaximum=0,this},h.prototype.isDivisibleBy=function(i){if(t>i){for(var s=this.digits.length-1,e=0;s>=0;s--)e=e%i*t+this.digits[s];return e%i==0}},h.prototype.set=function(i){this.digits=[],this.safemaximum=0;for(var s=0;0!=i;s++)this.digits[s]=i%t,i=Math.trunc(i/t);return this.safemaximum=t-1,this},h.prototype.value=function(){for(var i=this.digits.length-1,s=0;i>=0;i--)s+=this.digits[i]*Math.pow(t,i);return s},h.prototype.compare=function(t){if(this.digits.length>t.digits.length)return 1;if(this.digits.length=0;i--){if(this.digits[i]>t.digits[i])return 1;if(this.digits[i]=s&&this.normalise();var e=this.digits.length;if(t.digits.length>e)for(this.digits.length=t.digits.length,i=e;i=0;i--)this.digits[i]+=t.digits[i];return this},h.prototype.negate=function(){for(var t=0;t=s&&this.normalise();var e=this.digits.length;if(t.digits.length>e)for(this.digits.length=t.digits.length,i=e;i=0;i--)this.digits[i]-=t.digits[i];return this},h.prototype.multiply=function(e){var h;if(0==e.digits.length||0==this.digits.length)return this.reset();if(1==e.digits.length){var r=e.digits[0];if(this.safemaximum=this.safemaximum*Math.abs(r),this.safemaximum=0;h--)this.digits[h]*=r;else this._digitMultiplyWithAdd(r,0);return this}e.safemaximum>=t&&e.normalise(),this.safemaximum>=t&&this.normalise();var n=e.digits,g=this.digits;for(this.digits=new Array(g.length+n.length-1),h=0;h3&&n.length>3?this._rapidMultiplication(g,n,!0)._digitMultiplyWithAdd(i,0)._rapidMultiplication(g,n,!1):this._basicMultiplication(g,n)},h.prototype.digitMultiply=function(t){return this._digitMultiplyWithAdd(t,0)},h.prototype.random=function(i){this.reset();for(var s=Math.log(t)/Math.log(10),e=0;i>s;e++)this.digits[e]=Math.trunc(Math.random()*t),i-=s;return this.digits[e]=Math.trunc((1+Math.random())*Math.pow(10,i)),this.safemaximum=t-1,this},h.prototype.quotient=function(t){return this.divide(t),this},h.prototype.divide=function(i){var s,e,r=new h;if(i.safemaximum>=t&&i.normalise(),this.safemaximum>=t&&this.normalise(),0==this.digits.length)return r;if(0==i.digits.length)throw new Error("Attempt to divide by zero");if(1==i.digits.length)return r.set(this.digitDivide(i.digits[0]));var n=Math.sign(this.digits[this.digits.length-1]),g=Math.sign(i.digits[i.digits.length-1]);0>n?this.abs().positivise():this.positivise(),0>g?i.abs().positivise():i.positivise();var a=this.compare(i);switch(a){case-1:r=new h(this),this.reset();break;case 0:this.set(1);break;case 1:var o=i.digits,d=r.digits=this.digits.slice(this.digits.length-i.digits.length);r.safemaximum=this.safemaximum,this.digits.length-=d.length;var l;for(s=this.digits.length;s>=0;s--){for(this.digits[s]=0;r.compare(i)>=0;)l=d[d.length-1]*t+d[d.length-2],l=o.length0){for(e=d.length;e>0;e--)d[e]=d[e-1];d[0]=this.digits[s-1]}}}for(0>n*g&&(this.negate(),r.negate());this.digits.length>0&&0==this.digits[this.digits.length-1];)this.digits.length--;return r},h.prototype.digitDivide=function(i){for(var s,e=this.digits.length-1,h=0;e>=0;e--)s=h*t+this.digits[e],this.digits[e]=Math.trunc(s/i),h=s%i;for(;this.digits.length>0&&0==this.digits[this.digits.length-1];)this.digits.length--;return this.safemaximum=t-1,h},h.prototype.toString=function(){for(var t=this.isNegative()?"-":"",i=new h(this).abs().normalise().positivise();!i.isZero();)t=i.divide(h.TEN).lsb()+t;return 0==t.length&&(t="0"),t},h.prototype._digitMultiplyWithAdd=function(i,s){this.safemaximum>=t&&this.normalise(!0);for(var e=0;es.length){var e=i;i=s,s=e}for(var h=0,r=1,n=0,g=0;hs.length){var r=t;t=s,s=r}for(var n=t.length-1;n>=0;n--)if(h=e?Math.trunc(t[n]/i):t[n]%i,0!=h)for(var g=s.length-1;g>=0;g--)this.digits[n+g]+=h*s[g];return this.safemaximum*=i,this},h.prototype._subtractMultiple=function(i,s){for(var e=0,h=0,r=0;ethis.digits[e]?(this.digits[e]+=t-r,h++):this.digits[e]-=r;for(h&&(this.digits[e]-=h);this.digits.length>0&&0==this.digits[this.digits.length-1];)this.digits.length--},h.prototype._roughSqrt=function(){var i=new h;if(this.digits.length>0)if(1==this.digits.length)i.set(Math.ceil(Math.sqrt(this.digits[0])));else{var s=Math.ceil(Math.sqrt(this.digits[this.digits.length-1]*t+this.digits[this.digits.length-2]+1));i.digits=this.digits.slice(0,Math.trunc((this.digits.length-2)/2)),this.digits.length%2==1&&(s*=Math.sqrt(t)),i.digits.push(s%t)}return i},h.ZERO=new h,h.ONE=(new h).set(1),h.TWO=(new h).set(2),h.TEN=(new h).set(10),h.Primes=function(){function i(){this.iterator=0}var s=[2,3];return i.prototype.next=function(){if(this.iterator=t)return 0;for(var e=Math.sqrt(i),h=!0,r=0;r=0;i--)this.digits[i]=t.digits[i];this.safemaximum=t.safemaximum}else if("number"==typeof t){if(isNaN(t))throw new Error(e);this.set(Math.trunc(t))}else{if("string"!=typeof t)throw new Error(e);var s="-"==t[0]?-1:1;for(this.digits=[],this.safemaximum=0,i="-"==t[0]||"+"==t[0]?1:0;i=t){for(var s=0,e=0;s0&&0==this.digits[this.digits.length-1];)this.digits.length--;return this},h.prototype.positivise=function(){for(var i=0;i0&&0==this.digits[this.digits.length-1];)this.digits.length--;return this},h.prototype.isNegative=function(){return this.isZero()?!1:this.digits[this.digits.length-1]<0},h.prototype.isZero=function(){return 0==this.normalise().digits.length},h.prototype.isPositive=function(){return this.isZero()?!1:this.digits[this.digits.length-1]>0},h.prototype.lsb=function(){return this.isZero()?0:(t+this.digits[0])%t},h.prototype.reset=function(){return this.digits=[],this.safemaximum=0,this},h.prototype.isDivisibleBy=function(i){if(t>i){for(var s=this.digits.length-1,e=0;s>=0;s--)e=e%i*t+this.digits[s];return e%i==0}},h.prototype.set=function(i){this.digits=[],this.safemaximum=0;for(var s=0;0!=i;s++)this.digits[s]=i%t,i=Math.trunc(i/t);return this.safemaximum=t-1,this},h.prototype.value=function(){for(var i=this.digits.length-1,s=0;i>=0;i--)s+=this.digits[i]*Math.pow(t,i);return s},h.prototype.compare=function(t){if(this.digits.length>t.digits.length)return 1;if(this.digits.length=0;i--){if(this.digits[i]>t.digits[i])return 1;if(this.digits[i]=s&&this.normalise();var e=this.digits.length;if(t.digits.length>e)for(this.digits.length=t.digits.length,i=e;i=0;i--)this.digits[i]+=t.digits[i];return this},h.prototype.negate=function(){for(var t=0;t=s&&this.normalise();var e=this.digits.length;if(t.digits.length>e)for(this.digits.length=t.digits.length,i=e;i=0;i--)this.digits[i]-=t.digits[i];return this},h.prototype.multiply=function(e){var h;if(0==e.digits.length||0==this.digits.length)return this.reset();if(1==e.digits.length){var r=e.digits[0];if(this.safemaximum=this.safemaximum*Math.abs(r),this.safemaximum=0;h--)this.digits[h]*=r;else this._digitMultiplyWithAdd(r,0);return this}e.safemaximum>=t&&e.normalise(),this.safemaximum>=t&&this.normalise();var n=e.digits,g=this.digits;for(this.digits=new Array(g.length+n.length-1),h=0;h3&&n.length>3?this._rapidMultiplication(g,n,!0)._digitMultiplyWithAdd(i,0)._rapidMultiplication(g,n,!1):this._basicMultiplication(g,n)},h.prototype.digitMultiply=function(t){return this._digitMultiplyWithAdd(t,0)},h.prototype.random=function(i){this.reset();for(var s=Math.log(t)/Math.log(10),e=0;i>s;e++)this.digits[e]=Math.trunc(Math.random()*t),i-=s;return this.digits[e]=Math.trunc((1+Math.random())*Math.pow(10,i)),this.safemaximum=t-1,this},h.prototype.quotient=function(t){return this.divide(t),this},h.prototype.divide=function(i){var s,e,r=new h;if(i.safemaximum>=t&&i.normalise(),this.safemaximum>=t&&this.normalise(),0==this.digits.length)return r;if(0==i.digits.length)throw new Error("Attempt to divide by zero");if(1==i.digits.length)return r.set(this.digitDivide(i.digits[0]));var n=Math.sign(this.digits[this.digits.length-1]),g=Math.sign(i.digits[i.digits.length-1]);0>n?this.abs().positivise():this.positivise(),0>g?i.abs().positivise():i.positivise();var a=this.compare(i);switch(a){case-1:r=new h(this),this.reset();break;case 0:this.set(1);break;case 1:var o=i.digits,d=r.digits=this.digits.slice(this.digits.length-i.digits.length);r.safemaximum=this.safemaximum,this.digits.length-=d.length;var l;for(s=this.digits.length;s>=0;s--){for(this.digits[s]=0;r.compare(i)>=0;)l=d[d.length-1]*t+d[d.length-2],l=o.length0){for(e=d.length;e>0;e--)d[e]=d[e-1];d[0]=this.digits[s-1]}}}for(0>n*g&&(this.negate(),r.negate());this.digits.length>0&&0==this.digits[this.digits.length-1];)this.digits.length--;return r},h.prototype.digitDivide=function(i){for(var s,e=this.digits.length-1,h=0;e>=0;e--)s=h*t+this.digits[e],this.digits[e]=Math.trunc(s/i),h=s%i;for(;this.digits.length>0&&0==this.digits[this.digits.length-1];)this.digits.length--;return this.safemaximum=t-1,h},h.prototype.toString=function(){for(var t="",i=new h(this).abs().normalise().positivise();!i.isZero();)t=i.divide(h.TEN).lsb()+t;return 0==t.length&&(t="0"),this.isNegative()&&(t="-"+t),t},h.prototype._digitMultiplyWithAdd=function(i,s){this.safemaximum>=t&&this.normalise(!0);for(var e=0;es.length){var e=i;i=s,s=e}for(var h=0,r=1,n=0,g=0;hs.length){var r=t;t=s,s=r}for(var n=t.length-1;n>=0;n--)if(h=e?Math.trunc(t[n]/i):t[n]%i,0!=h)for(var g=s.length-1;g>=0;g--)this.digits[n+g]+=h*s[g];return this.safemaximum*=i,this},h.prototype._subtractMultiple=function(i,s){for(var e=0,h=0,r=0;ethis.digits[e]?(this.digits[e]+=t-r,h++):this.digits[e]-=r;for(h&&(this.digits[e]-=h);this.digits.length>0&&0==this.digits[this.digits.length-1];)this.digits.length--},h.prototype._roughSqrt=function(){var i=new h;if(this.digits.length>0)if(1==this.digits.length)i.set(Math.ceil(Math.sqrt(this.digits[0])));else{var s=Math.ceil(Math.sqrt(this.digits[this.digits.length-1]*t+this.digits[this.digits.length-2]+1));i.digits=this.digits.slice(0,Math.trunc((this.digits.length-2)/2)),this.digits.length%2==1&&(s*=Math.sqrt(t)),i.digits.push(s%t)}return i},h.ZERO=new h,h.ONE=(new h).set(1),h.TWO=(new h).set(2),h.TEN=(new h).set(10),h.Primes=function(){function i(){this.iterator=0}var s=[2,3];return i.prototype.next=function(){if(this.iterator=t)return 0;for(var e=Math.sqrt(i),h=!0,r=0;re?Math.ceil(e):Math.floor(e)},Math.sign=Math.sign||function(e){return e=+e,0===e||isNaN(e)?e:e>0?1:-1};var o=t,a=require("./N.js");return o.prototype.set=function(e,t){function m(e,t){u.remainder=r();for(var n=0,o=null;n0||!this.integer)&&(this.integer=!1,this.remainder={numerator:new a(h),denominator:new a(d)})}return this}if("string"==typeof e){if(e=e.trim(),this.integer||(this.remainder=r()),e.match(/^[\+\-]?\d+\/\d+$/))"boolean"!=typeof t&&(this.integer=!1),this.number=new a,s(e);else{var p="-"==e[0];if(null===e.match(/^[\+\-]?\d*/))throw new Error(i);if(this.number=new a(e.match(/^[\+\-]?\d*/)[0]),e.match(/^[\+\-]?\d*$/))return this;var l=e.match(/^[\+\-]?\d*([\. ])/);if(null===l)throw new Error(i);var f=e.match(/^[\+\-]?\d*[\. ](.*)/)[1];switch("boolean"!=typeof t&&(this.integer=!1),l[1]){case".":if(null===f.match(/^\d*\[?\d+\]?$/))throw new Error(i);this.integer||m(f,p?-1:1);break;case" ":if(null===f.match(/^\d+\/\d+$/))throw new Error(i);s((p?"-":"")+f)}}return this}if("undefined"==typeof e&&arguments.length>0)throw new Error(i);return this.number=new a,this.integer||(this.remainder=r()),this},o.prototype.simplify=function(e){if(arguments.length>0&&("number"!=typeof e||isNaN(e)))throw new Error("Simplify() takes an optional numeric argument specifying the maximum number of millisecondsto process");if("undefined"==typeof e&&(e=100),this.isInteger()||this.remainder.numerator.isZero())return!0;for(var r=a.abs(this.remainder.numerator)._roughSqrt().value(),t=new a.Primes,i=(new Date).getTime(),n=(new a).set(1),o=t.next();o>0&&r>=o;o=t.next()){for(;this.remainder.numerator.isDivisibleBy(o);)this.remainder.numerator.digitDivide(o),this.remainder.denominator.isDivisibleBy(o)?this.remainder.denominator.digitDivide(o):n.digitMultiply(o);if((new Date).getTime()-i>e&&e>0){o=0;break}}var m=new a(this.remainder.denominator),s=m.divide(this.remainder.numerator);return s.isZero()?(this.remainder.denominator=m,this.remainder.numerator=n,!0):(this.remainder.numerator.multiply(n),o>0)},o.prototype.makeInteger=function(){return this.integer=!0,delete this.remainder,this},o.prototype.makeFractional=function(){return this.integer&&(this.integer=!1,this.remainder=r()),this},o.prototype.isInteger=function(){return this.integer},o.prototype.isFractional=function(){return!this.integer},o.prototype.isNegative=function(){return this.isZero()?!1:this.number.isZero()?this.remainder.numerator.isNegative():this.number.isNegative()},o.prototype.isPositive=function(){return this.isZero()?!1:this.number.isZero()?this.remainder.numerator.isPositive():this.number.isPositive()},o.prototype.isZero=function(){return this._normaliseRemainder(),this.number.isZero()&&(this.isInteger()||this.remainder.numerator.isZero())},o.prototype.sign=function(){return this.isZero()?0:this.isNegative()?-1:1},o.prototype.hasFraction=function(){return this.integer?!1:(this._normaliseRemainder(),!this.remainder.numerator.isZero())},o.prototype.value=function(){var e=Math.pow(10,n);if(this.integer)return this.number.value();var r=new a(this.remainder.numerator).multiply(new a(e));return r.divide(this.remainder.denominator),this.number.value()+1*(r.value()/e).toFixed(n)},o.makeFractional=function(e){return new o(e).makeFractional()},o.makeInteger=function(e){return new o(e).makeInteger()},o.frac=function(e){return new o(e).frac()},o["int"]=function(e){return new o(e)["int"]()},o.add=function(e,r){return new o(e).add(r)},o.subtract=function(e,r){return new o(e).subtract(r)},o.multiply=function(e,r){return new o(e).multiply(r)},o.divide=function(e,r){return new o(e).divide(r)},o.modulus=function(e,r){return new o(e).mod(r)},o.abs=function(e){return new o(e).abs()},o.random=function(e){if(!("number"==typeof e&&e>0))throw new Error("You must specify a positive number of decimal digits as an approximate size for this number");var r=new o;return r.number.random(e),r},o.prototype.compare=function(e){function r(e,r){return a.abs(e).normalise().positivise().compare(a.abs(r).positivise().normalise())}if(e===this)return 0;if(e=o(e),this._normaliseRemainder(),e._normaliseRemainder(),this.sign()!=e.sign())return 0==this.sign()?-e.sign():this.sign();var t=r(this.number,e.number);return 0==t&&this.isFractional()&&e.isFractional()&&(t=r(new a(this.remainder.numerator).multiply(e.remainder.denominator),new a(this.remainder.denominator).multiply(e.remainder.numerator))),t},o.prototype.lt=function(e){return-1==this.compare(e)},o.prototype.lte=function(e){return 1!=this.compare(e)},o.prototype.gt=function(e){return 1==this.compare(e)},o.prototype.gte=function(e){return-1!=this.compare(e)},o.prototype.eq=function(e){return 0==this.compare(e)},o.prototype["int"]=function(){return this.integer||(this.remainder=r()),this},o.prototype.frac=function(){return this._normaliseRemainder().number.reset(),this},o.prototype.abs=function(){return this.number.abs(),this.integer||this.remainder.numerator.abs(),this},o.prototype.multiply=function(e){return e instanceof t||(e=o(e)),this.integer||(e.integer?this.remainder.numerator.multiply(e.number):(this.remainder.numerator.multiply(a.temporary(e.remainder.denominator).multiply(e.number).add(e.remainder.numerator)).add(a.temporary(e.remainder.numerator).multiply(this.number).multiply(this.remainder.denominator)),this.remainder.denominator.multiply(e.remainder.denominator))),this.number.multiply(e.number),this},o.prototype.divide=function(e){return e instanceof t||(e=o(e)),this.integer?this.number.divide(e.number):e.integer?(this.number.multiply(this.remainder.denominator).add(this.remainder.numerator),this.remainder.numerator=this.number.divide(this.remainder.denominator.multiply(e.number))):(this.number.multiply(this.remainder.denominator).add(this.remainder.numerator).multiply(e.remainder.denominator),this.remainder.numerator=this.number.divide(this.remainder.denominator.multiply(a.temporary(e.number).multiply(e.remainder.denominator).add(e.remainder.numerator)))),this},o.prototype.modulus=function(e){return e instanceof t||(e=o(e)),this.number=this.number.divide(e.number),this.integer||(this.remainder=r()),this},o.prototype.subtract=function(e){return e instanceof t||(e=o(e)),this.number.subtract(e.number),this.integer||(e.integer||e.remainder.numerator.isZero()||(this.remainder.numerator.multiply(e.remainder.denominator),this.remainder.numerator.subtract(a.temporary(e.remainder.numerator).multiply(this.remainder.denominator)),this.remainder.denominator.multiply(e.remainder.denominator)),this._normaliseRemainder()),this},o.prototype.add=function(e){return e instanceof t||(e=o(e)),this.number.add(e.number),this.integer||(e.integer||e.remainder.numerator.isZero()||(this.remainder.numerator.multiply(e.remainder.denominator),this.remainder.numerator.add(a.temporary(e.remainder.numerator).multiply(this.remainder.denominator)),this.remainder.denominator.multiply(e.remainder.denominator)),this._normaliseRemainder()),this},o.prototype.toDecimal=function(e){return"undefined"==typeof e?this.toString():this.toString(e)},o.prototype.toInteger=function(){return this._normaliseRemainder(),(this.isNegative()?"-":"")+a.abs(this.number).toString()},o.prototype.toFraction=function(){var e=this.toInteger();return this.isFractional()&&!this.remainder.numerator.isZero()&&(e=e+" "+a.abs(this.remainder.numerator).toString(),e=e+"/"+this.remainder.denominator.toString()),e},o.prototype.toString=function(e){if("number"!=typeof e||isNaN(e)){if(arguments.length>0)throw new Error("toString() takes an optional parameter to specify the maximum DPs to output [default=100]");e=100}var r=this.toInteger();if(this.isFractional()&&!this.remainder.numerator.isZero()){r+=".";for(var t=[],i=new a(this.remainder.numerator).abs().normalise().positivise(),n=0;!i.isZero()&&e>0;e--){for(var o=t.length-1;o>=0&&0!=t[o].compare(i);o--);if(o>=0){r=r.substr(0,r.length+o-t.length)+"["+r.substr(r.length+o-t.length)+"]";break}t.push(new a(i)),n=i._digitMultiplyWithAdd(10,0).divide(this.remainder.denominator),r+=i.lsb(),i=n}0!=e||i.isZero()||(r+="...")}return r},o.prototype._normaliseRemainder=function(){if(!this.integer){var e=this.remainder.numerator.divide(this.remainder.denominator);this.number.add(this.remainder.numerator),this.remainder.numerator=e,this.remainder.numerator.isZero()?this.remainder.denominator.set(1):this.remainder.numerator.isNegative()?this.number.isPositive()&&(this.remainder.numerator.add(this.remainder.denominator),this.number.subtract(a.ONE)):this.number.isNegative()&&(this.remainder.numerator.subtract(this.remainder.denominator),this.number.add(a.ONE))}return this},o.plus=o.add,o.prototype.plus=o.prototype.add,o.minus=o.subtract,o.prototype.minus=o.prototype.subtract,o.sub=o.subtract,o.prototype.sub=o.prototype.subtract,o.times=o.multiply,o.prototype.times=o.prototype.multiply,o.mult=o.multiply,o.prototype.mult=o.prototype.multiply,o.div=o.divide,o.prototype.div=o.prototype.divide,o.mod=o.modulus,o.prototype.mod=o.prototype.modulus,o}(); +module.exports=function(e){"use strict";function r(e,r){return{numerator:e instanceof a?e:new a,denominator:r instanceof a?r:new a(1)}}function t(e,r){if(!(this instanceof o)){if(e instanceof o&&("boolean"!=typeof r||r==e.integer))return e;switch(arguments.length){case 0:return new o;case 1:return new o(e);default:return new o(e,r)}}return this.set.apply(this,arguments)}var i="Number initialisation parameter badly formed",n=8;Math.trunc=Math.trunc||function(e){return 0>e?Math.ceil(e):Math.floor(e)},Math.sign=Math.sign||function(e){return e=+e,0===e||isNaN(e)?e:e>0?1:-1};var o=t,a=require("./N.js");return o.prototype.set=function(e,t){function m(e,t){u.remainder=r();for(var n=0,o=null;n0||!this.integer)&&(this.integer=!1,this.remainder={numerator:new a(h),denominator:new a(d)})}return this}if("string"==typeof e){if(e=e.trim(),this.integer||(this.remainder=r()),e.match(/^[\+\-]?\d+\/\d+$/))"boolean"!=typeof t&&(this.integer=!1),this.number=new a,s(e);else{var p="-"==e[0];if(null===e.match(/^[\+\-]?\d*/))throw new Error(i);if(this.number=new a(e.match(/^[\+\-]?\d*/)[0]),e.match(/^[\+\-]?\d*$/))return this;var l=e.match(/^[\+\-]?\d*([\. ])/);if(null===l)throw new Error(i);var f=e.match(/^[\+\-]?\d*[\. ](.*)/)[1];switch("boolean"!=typeof t&&(this.integer=!1),l[1]){case".":if(null===f.match(/^\d*\[?\d+\]?$/))throw new Error(i);this.integer||m(f,p?-1:1);break;case" ":if(null===f.match(/^\d+\/\d+$/))throw new Error(i);s((p?"-":"")+f)}}return this}if("undefined"==typeof e&&arguments.length>0)throw new Error(i);return this.number=new a,this.integer||(this.remainder=r()),this},o.prototype.simplify=function(e){if(arguments.length>0&&("number"!=typeof e||isNaN(e)))throw new Error("Simplify() takes an optional numeric argument specifying the maximum number of millisecondsto process");if("undefined"==typeof e&&(e=100),this.isInteger()||this.remainder.numerator.isZero())return!0;var r=this.remainder.numerator.isNegative();this.remainder.numerator.abs();for(var t=this.remainder.numerator._roughSqrt().value(),i=new a.Primes,n=(new Date).getTime(),o=(new a).set(1),m=i.next();m>0&&t>=m;m=i.next()){for(;this.remainder.numerator.isDivisibleBy(m);)this.remainder.numerator.digitDivide(m),this.remainder.denominator.isDivisibleBy(m)?this.remainder.denominator.digitDivide(m):o.digitMultiply(m);if((new Date).getTime()-n>e&&e>0){m=0;break}}var s=new a(this.remainder.denominator),u=s.divide(this.remainder.numerator);return u.isZero()?(this.remainder.denominator=s,this.remainder.numerator=o,m=1):this.remainder.numerator.multiply(o),r&&this.remainder.numerator.negate(),m>0},o.prototype.makeInteger=function(){return this.integer=!0,delete this.remainder,this},o.prototype.makeFractional=function(){return this.integer&&(this.integer=!1,this.remainder=r()),this},o.prototype.isInteger=function(){return this.integer},o.prototype.isFractional=function(){return!this.integer},o.prototype.isNegative=function(){return this.isZero()?!1:this.number.isZero()?this.remainder.numerator.isNegative():this.number.isNegative()},o.prototype.isPositive=function(){return this.isZero()?!1:this.number.isZero()?this.remainder.numerator.isPositive():this.number.isPositive()},o.prototype.isZero=function(){return this._normaliseRemainder(),this.number.isZero()&&(this.isInteger()||this.remainder.numerator.isZero())},o.prototype.sign=function(){return this.isZero()?0:this.isNegative()?-1:1},o.prototype.hasFraction=function(){return this.integer?!1:(this._normaliseRemainder(),!this.remainder.numerator.isZero())},o.prototype.value=function(){var e=Math.pow(10,n);if(this.integer)return this.number.value();var r=new a(this.remainder.numerator).multiply(new a(e));return r.divide(this.remainder.denominator),this.number.value()+1*(r.value()/e).toFixed(n)},o.makeFractional=function(e){return new o(e).makeFractional()},o.makeInteger=function(e){return new o(e).makeInteger()},o.frac=function(e){return new o(e).frac()},o["int"]=function(e){return new o(e)["int"]()},o.add=function(e,r){return new o(e).add(r)},o.subtract=function(e,r){return new o(e).subtract(r)},o.multiply=function(e,r){return new o(e).multiply(r)},o.divide=function(e,r){return new o(e).divide(r)},o.modulus=function(e,r){return new o(e).mod(r)},o.abs=function(e){return new o(e).abs()},o.random=function(e){if(!("number"==typeof e&&e>0))throw new Error("You must specify a positive number of decimal digits as an approximate size for this number");var r=new o;return r.number.random(e),r},o.prototype.compare=function(e){function r(e,r){return a.abs(e).normalise().positivise().compare(a.abs(r).positivise().normalise())}if(e===this)return 0;if(e=o(e),this._normaliseRemainder(),e._normaliseRemainder(),this.sign()!=e.sign())return 0==this.sign()?-e.sign():this.sign();var t=r(this.number,e.number);return 0==t&&this.isFractional()&&e.isFractional()&&(t=r(new a(this.remainder.numerator).multiply(e.remainder.denominator),new a(this.remainder.denominator).multiply(e.remainder.numerator))),t},o.prototype.lt=function(e){return-1==this.compare(e)},o.prototype.lte=function(e){return 1!=this.compare(e)},o.prototype.gt=function(e){return 1==this.compare(e)},o.prototype.gte=function(e){return-1!=this.compare(e)},o.prototype.eq=function(e){return 0==this.compare(e)},o.prototype["int"]=function(){return this.integer||(this.remainder=r()),this},o.prototype.frac=function(){return this._normaliseRemainder().number.reset(),this},o.prototype.abs=function(){return this.number.abs(),this.integer||this.remainder.numerator.abs(),this},o.prototype.multiply=function(e){return e instanceof t||(e=o(e)),this.integer||(e.integer?this.remainder.numerator.multiply(e.number):(this.remainder.numerator.multiply(a.temporary(e.remainder.denominator).multiply(e.number).add(e.remainder.numerator)).add(a.temporary(e.remainder.numerator).multiply(this.number).multiply(this.remainder.denominator)),this.remainder.denominator.multiply(e.remainder.denominator))),this.number.multiply(e.number),this},o.prototype.divide=function(e){return e instanceof t||(e=o(e)),this.integer?this.number.divide(e.number):e.integer?(this.number.multiply(this.remainder.denominator).add(this.remainder.numerator),this.remainder.numerator=this.number.divide(this.remainder.denominator.multiply(e.number))):(this.number.multiply(this.remainder.denominator).add(this.remainder.numerator).multiply(e.remainder.denominator),this.remainder.numerator=this.number.divide(this.remainder.denominator.multiply(a.temporary(e.number).multiply(e.remainder.denominator).add(e.remainder.numerator)))),this},o.prototype.modulus=function(e){return e instanceof t||(e=o(e)),this.number=this.number.divide(e.number),this.integer||(this.remainder=r()),this},o.prototype.subtract=function(e){return e instanceof t||(e=o(e)),this.number.subtract(e.number),this.integer||(e.integer||e.remainder.numerator.isZero()||(this.remainder.numerator.multiply(e.remainder.denominator).subtract(a.temporary(e.remainder.numerator).multiply(this.remainder.denominator)),this.remainder.denominator.multiply(e.remainder.denominator)),this._normaliseRemainder()),this},o.prototype.add=function(e){return e instanceof t||(e=o(e)),this.number.add(e.number),this.integer||(e.integer||e.remainder.numerator.isZero()||(this.remainder.numerator.multiply(e.remainder.denominator).add(a.temporary(e.remainder.numerator).multiply(this.remainder.denominator)),this.remainder.denominator.multiply(e.remainder.denominator)),this._normaliseRemainder()),this},o.prototype.toDecimal=function(e){return"undefined"==typeof e?this.toString():this.toString(e)},o.prototype.toInteger=function(){return this._normaliseRemainder(),(this.isNegative()?"-":"")+a.abs(this.number).toString()},o.prototype.toFraction=function(){var e=this.toInteger();return this.isFractional()&&!this.remainder.numerator.isZero()&&(e=e+" "+a.abs(this.remainder.numerator).toString(),e=e+"/"+this.remainder.denominator.toString()),e},o.prototype.toString=function(e){if("number"!=typeof e||isNaN(e)){if(arguments.length>0)throw new Error("toString() takes an optional parameter to specify the maximum DPs to output [default=100]");e=100}var r=this.toInteger();if(this.isFractional()&&!this.remainder.numerator.isZero()){r+=".";for(var t=[],i=new a(this.remainder.numerator).abs().normalise().positivise(),n=0;!i.isZero()&&e>0;e--){for(var o=t.length-1;o>=0&&0!=t[o].compare(i);o--);if(o>=0){r=r.substr(0,r.length+o-t.length)+"["+r.substr(r.length+o-t.length)+"]";break}t.push(new a(i)),n=i._digitMultiplyWithAdd(10,0).divide(this.remainder.denominator),r+=i.lsb(),i=n}0!=e||i.isZero()||(r+="...")}return r},o.prototype._normaliseRemainder=function(){if(!this.integer){var e=this.remainder.numerator.divide(this.remainder.denominator);this.number.add(this.remainder.numerator),this.remainder.numerator=e,this.remainder.numerator.isZero()?this.remainder.denominator.set(1):this.remainder.numerator.isNegative()?this.number.isPositive()&&(this.remainder.numerator.add(this.remainder.denominator),this.number.subtract(a.ONE)):this.number.isNegative()&&(this.remainder.numerator.subtract(this.remainder.denominator),this.number.add(a.ONE))}return this},o.plus=o.add,o.prototype.plus=o.prototype.add,o.minus=o.subtract,o.prototype.minus=o.prototype.subtract,o.sub=o.subtract,o.prototype.sub=o.prototype.subtract,o.times=o.multiply,o.prototype.times=o.prototype.multiply,o.mult=o.multiply,o.prototype.mult=o.prototype.multiply,o.div=o.divide,o.prototype.div=o.prototype.divide,o.mod=o.modulus,o.prototype.mod=o.prototype.modulus,o}(); },{"./N.js":1}]},{},[2])(2) }); \ No newline at end of file diff --git a/package.json b/package.json index f5611a3..52c77eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "TPA", - "version": "1.0.13", + "version": "1.0.14", "description": "Total Precision Arithmetic", "homepage": "http://dthwaite.github.io/tpa", "tonicExampleFilename": "tonicexample.js", diff --git a/test/tpa.js b/test/tpa.js index 0dbfcff..ebbdfd8 100644 --- a/test/tpa.js +++ b/test/tpa.js @@ -853,6 +853,9 @@ function alltests() { assert.throws(function() { n.simplify('123'); }, Error, 'Bad argument passed to simplify'); + n.set('-0 575792/29506624'); + n.simplify(0); + assert.equal(n.toFraction(),'-0 53/2716',"Simplification of negative fraction>-1"); }); } });