Permalink
Browse files

init

  • Loading branch information...
0 parents commit d755c48fb87c83c764c9fc5da36919f7569f5332 @defunctzombie committed May 1, 2012
Showing with 382 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +2 −0 AUTHORS
  3. +214 −0 num.js
  4. +21 −0 package.json
  5. +1 −0 test/mocha.opts
  6. +143 −0 test/test.js
@@ -0,0 +1 @@
+node_modules
@@ -0,0 +1,2 @@
+Roman Shtylman <shtylman@gmail.com>
+Vadim Graboys <dimva13@gmail.com>
214 num.js
@@ -0,0 +1,214 @@
+var int = require('int');
+
+function Num(num, precision) {
+ if (!(this instanceof Num)) {
+ return new Num(num, precision);
+ }
+
+ var self = this;
+ if (num instanceof Num) {
+ self._int = int(num._int);
+ self._precision = num._precision;
+ return self;
+ }
+
+ // convert to a string
+ num = '' + num;
+
+ // find Num point
+ var dec = num.indexOf('.');
+
+ if (dec >= 0) {
+ // take out the Num point
+ num = num.replace('.', '');
+ var precision = num.length - dec;
+ }
+ else {
+ var precision = 0;
+ }
+
+ this._int = int(num);
+ this._precision = precision;
+}
+
+// TODO: this is probably slow, make faster
+Num.prototype.toString = function() {
+ var num_str = this._int.toString();
+
+ var sign = '';
+ if (num_str.charAt(0) === '-') {
+ sign = '-';
+ }
+
+ if (this._precision === 0) {
+ return num_str;
+ }
+
+ var arr = num_str.split('');
+ arr.splice(arr.length - this._precision, 0, '.');
+ return sign + arr.join('');
+};
+
+Num.prototype.valueOf = Num.prototype.toString;
+
+/// return {int} the precision
+Num.prototype.get_precision = function() {
+ return this._precision;
+};
+
+/// setting precision to < current precision will floor, NOT round
+/// modifies this object
+Num.prototype.set_precision = function(precision) {
+ var self = this;
+ var precision_diff = precision - self._precision;
+
+ if (precision_diff > 0) {
+ self._int = self._int.mul(int(10).pow(precision_diff));
+ }
+ else if(precision_diff < 0) {
+ self._int = self._int.div(int(10).pow(-precision_diff));
+ }
+
+ self._precision += precision_diff;
+ return self;
+};
+
+/// returns a copy
+Num.prototype.round = function(precision) {
+ var copy = Num(this);
+
+ if (precision >= copy._precision) {
+ return copy;
+ }
+
+ var num_str = copy._int.toString();
+
+ // the index to check for rounding
+ var idx = num_str.length - copy._precision + precision;
+
+ // the number to check if >= 5
+ var n = num_str[idx] - 0;
+
+ var neg = num_str[0] === '-';
+
+ copy.set_precision(precision);
+
+ if ((neg && n < 5) || (!neg && n >= 5)) {
+ copy._int = copy._int.add(1);
+ }
+
+ return copy;
+};
+
+/// returns new Num, -this
+Num.prototype.neg = function() {
+ return new Num(this._int.neg(), this._precision);
+};
+
+Num.prototype.to_int = function(precision) {
+ var copy = this.copy();
+ copy.set_precision(precision);
+ return copy._int;
+};
+
+/// converts a Num to an integer representation with specified precision
+/// Num('32.1').to_int(5) will be converted to 3210000
+/// for doing fast calculations before converting back with Num.from_int
+/// warning! cannot convert more than ~16 total Num digits of precision
+Num.prototype.to_int = function(precision) {
+ var dec_str = this.round(precision).toString();
+ return Math.round(dec_str * Math.pow(10, precision));
+};
+
+/// returns a + b
+/// a, b can each be either a Num, String, or Number
+/// will return a new Num with the greatest precision of the operands
+Num.add = function(a, b) {
+ // force a,b to be Num
+ if(!(a instanceof Num))
+ a = Num(a);
+ if(!(b instanceof Num))
+ b = Num(b);
+
+ // make sure num and a have the same precision
+ if(a._precision < b._precision) {
+ a = a.copy(); // copy before modifying
+ a.set_precision(b._precision);
+ } else if(b._precision < a._precision) {
+ b = b.copy(); // copy before modifying
+ b.set_precision(a._precision);
+ }
+
+ // the integer result
+ var num_res = a._int.add(b._int);
+
+ return new Num(num_res, a._precision);
+};
+
+/// returns a - b
+/// a, b can each be either a Num, String, or Number
+/// will return a new Num with the greatest precision of the operands
+Num.sub = function(a, b) {
+ b = Num(b); // convert/copy before modifying
+ b._int = b._int.neg(); // negate
+ return Num.add(a, b);
+};
+
+/// returns a * b
+/// a, b can each be either a Num, String, or Number
+/// will return a new Num with precision = sum(a.precision,b.precision)
+Num.mul = function(a, b) {
+ // force a,b to be Num
+ if(!(a instanceof Num))
+ a = Num(a);
+ if(!(b instanceof Num))
+ b = Num(b);
+
+ return new Num(a._int.mul(b._int), a._precision + b._precision);
+};
+
+/// returns < 0 if a < b, 0 if a == b, > 0 if a > b
+Num.cmp = function(a, b) {
+ // force a,b to be Num
+ if(!(a instanceof Num))
+ a = Num(a);
+ if(!(b instanceof Num))
+ b = Num(b);
+
+ return a.sub(b).toNumber();
+};
+
+Num.eq = function(a, b) {
+ return Num.cmp(a, b) === 0;
+};
+
+Num.gt = function(a, b) {
+ return Num.cmp(a, b) > 0;
+};
+
+Num.gte = function(a, b) {
+ return Num.cmp(a, b) >= 0;
+};
+
+Num.lt = function(a, b) {
+ return Num.cmp(a, b) < 0;
+};
+
+Num.lte = function(a, b) {
+ return Num.cmp(a, b) <= 0;
+};
+
+// add all the static methods in Num to Num's prototype
+(function() {
+ function add_method(name) {
+ Num.prototype[name] = function(b) {
+ return Num[name](this, b);
+ }
+ }
+
+ for(var i in Num) {
+ add_method(i);
+ }
+})();
+
+module.exports = Num;
@@ -0,0 +1,21 @@
+{
+ "author": "Roman Shtylman <shtylman@gmail.com>",
+ "name": "num",
+ "description": "arbitrary precision integer and decimal library in pure javascript",
+ "version": "0.0.0alpha",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/shtylman/node-num.git"
+ },
+ "main": "num.js",
+ "dependencies": {
+ "int": "0.0.1"
+ },
+ "devDependencies": {
+ "mocha": ">=1.x.x"
+ },
+ "optionalDependencies": {},
+ "engines": {
+ "node": "*"
+ }
+}
@@ -0,0 +1 @@
+--ui qunit
@@ -0,0 +1,143 @@
+
+var assert = require('assert');
+var num = require('../');
+
+test('build', function() {
+ // zeros
+ assert.equal(num(0), '0');
+ assert.equal(num('0'), '0');
+ assert.equal(num('0.'), '0');
+ assert.equal(num('.0'), '0.0');
+ assert.equal(num('-.00'), '0.00');
+ assert.equal(num('0.000'), '0.000');
+
+ // whole number
+ assert.equal(num(5), '5');
+ assert.equal(num(-5), '-5');
+ assert.equal(num('5'), '5');
+ assert.equal(num('-5'), '-5');
+
+ // misc
+ assert.equal(num(1.2), '1.2');
+ assert.equal(num(.2), '0.2');
+ assert.equal(num(-.2), '-0.2');
+ assert.equal(num(-1.2), '-1.2');
+ assert.equal(num('0.001'), '0.001');
+ assert.equal(num('0.001234'), '0.001234');
+ assert.equal(num(123), '123');
+ assert.equal(num(-234), '-234');
+
+ // large numbers
+ assert.equal(num('987654321987654321'), '987654321987654321');
+ assert.equal(num('-987654321987654321.12345678901'), '-987654321987654321.12345678901');
+ assert.equal(num('987654321987654321.12345678901'), '987654321987654321.12345678901');
+ assert.equal(num('-.000098765432198765432112345678901'), '-0.000098765432198765432112345678901');
+});
+
+test('add', function() {
+ assert.equal(num.add(0, 0), '0');
+ assert.equal(num.add(-0, 0.0), '0');
+
+ // presers precision
+ assert.equal(num.add(1.2, -1.2), '0.0');
+
+ // misc
+ assert.equal(num.add(1.2, 2.4), '3.6');
+
+ // large numbers
+ assert.equal(num.add('987654321987654321.12345678901', 1000.012), '987654321987655321.13545678901');
+
+ assert.equal(num.add('987654321987654321.12345678901', '-987654321987654321.12345678901'), '0.00000000000');
+});
+
+test('sub', function() {
+ assert.equal(num.sub(0, 0), '0');
+ assert.equal(num.sub('0', '-0'), '0');
+
+ assert.equal(num.sub('1.0', '-1.0'), '2.0');
+
+ assert.equal(num('987654321987654321.12345678901').sub(100.012), '987654321987654221.11145678901');
+ assert.equal(num(100.012).sub(num('987654321987654321.12345678901')), '-987654321987654221.11145678901');
+});
+
+test('mul', function() {
+ assert.equal(num.mul(1.2, 2.4), '2.88');
+ assert.equal(num.mul(.2, 2.4), '0.48');
+ assert.equal(num.mul(.2, 2), '0.4');
+ assert.equal(num.mul(5, 2), '10');
+ assert.equal(num.mul('123456789.32423455645', '123323.34343'), '15225104028597.7358269570716235');
+});
+
+test('precision', function() {
+ assert.equal(num(1.999).set_precision(30), '1.999000000000000000000000000000');
+ assert.equal(num(1.999).set_precision(1), '1.9');
+ assert.equal(num(-1.999).set_precision(30), '-1.999000000000000000000000000000');
+ assert.equal(num(-1.999).set_precision(1), '-2.0'); // TODO: is this correct behavior?
+});
+
+test('round', function() {
+ assert.equal(num(123.999).round(30), '123.999');
+ assert.equal(num(123.999).round(1), '124.0');
+ assert.equal(num(123.450).round(1), '123.5');
+ assert.equal(num(123.449).round(1), '123.4');
+ assert.equal(num(123.495).round(2), '123.50');
+ assert.equal(num(123.495).round(0), '123');
+ assert.equal(num(123.500).round(0), '124');
+
+ assert.equal(num(-123.999).round(30), '-123.999');
+ assert.equal(num(-123.999).round(1), '-124.0');
+ assert.equal(num(-123.450).round(1), '-123.5');
+ assert.equal(num(-123.449).round(1), '-123.4');
+ assert.equal(num(-123.495).round(2), '-123.50');
+ assert.equal(num(-123.495).round(0), '-123');
+ assert.equal(num(-123.500).round(0), '-124');
+
+ assert.equal(num(0.999).round(30), '0.999');
+ assert.equal(num(0.999).round(1), '1.0');
+ assert.equal(num(0.450).round(1), '0.5');
+ assert.equal(num(0.449).round(1), '0.4');
+ assert.equal(num(0.495).round(2), '0.50');
+ assert.equal(num(0.495).round(0), '0');
+
+ assert.equal(num(-0.999).round(30), '-0.999');
+ assert.equal(num(-0.999).round(1), '-1.0');
+ assert.equal(num(-0.450).round(1), '-0.5');
+ assert.equal(num(-0.449).round(1), '-0.4');
+ assert.equal(num(-0.495).round(2), '-0.50');
+ assert.equal(num(-0.495).round(0), '0');
+
+ assert.equal(num('0.000').round(0), '0');
+ assert.equal(num('0.000').round(1), '0.0');
+});
+
+/*
+test('int_conv', function() {
+ assert.equal(num.from_int(0, 0), '0');
+ assert.equal(num.from_int(1, 0), '1');
+ assert.equal(num.from_int(-1, 0), '-1');
+ assert.equal(num.from_int(0, 5), '0.00000');
+ assert.equal(num.from_int(1, 5), '0.00001');
+ assert.equal(num.from_int(-1, 5), '-0.00001');
+ assert.equal(num.from_int(123456, 5), '1.23456');
+ assert.equal(num.from_int(-123456, 5), '-1.23456');
+
+ assert.equal(num('0').to_int(1), 0);
+ assert.equal(num('1').to_int(0), 1);
+ assert.equal(num('1').to_int(2), 100);
+ assert.equal(num('1.2345').to_int(5), 123450);
+ assert.equal(num('-1.2345').to_int(5), -123450);
+});
+
+test('get_precision', function() {
+ assert.equal(0, num('0').get_precision());
+ assert.equal(2, num('0.20').get_precision());
+ assert.equal(1, num('.5').get_precision());
+});
+
+test('to_int', function() {
+ var d1 = num('12.35');
+ assert.equal('1235', '' + d1.to_int(2));
+ assert.equal('1235000', '' + d1.to_int(5));
+ assert.equal('123', '' + d1.to_int(1));
+});
+*/

0 comments on commit d755c48

Please sign in to comment.