Skip to content

Instantly share code, notes, and snippets.

@zootella
Created November 30, 2015 20:16
Show Gist options
  • Select an option

  • Save zootella/84e943a4876b8de4137f to your computer and use it in GitHub Desktop.

Select an option

Save zootella/84e943a4876b8de4137f to your computer and use it in GitHub Desktop.
// A 0+ integer of unlimited size
function Int(p) { // Takes a number like 5, a string of numerals like "789", a bignumber.js BigNumber, or another Int
if (isType(p, "Int")) return p; // Return the given Int instead of making a new one, the value inside an Int can't change
var o = {};
o.v = _3type(p); // Parse the given parameter, keeping together v.s() numerals, and v.n() number and v.b() BigNumber once we have them or they are necessary
o.inside = o.v.inside; // Point to function, see which types v has built up with text like "bns" or "--s" for testing
o.add = function(q) { return _add(o.v, q); } // Math
o.subtract = function(q) { return _sub(o.v, q); }
o.multiply = function(q) { return _mul(o.v, q); }
o.divide = function(q) { return _div(o.v, q); }
o.modulo = function(q) { return _mod(o.v, q); }
o.equals = function(q) { return _equ(o.v, q); }
o.greaterThan = function(q) { return _gth(o.v, q); }
o.greaterThanOrEqualTo = function(q) { return _gte(o.v, q); }
o.lessThan = function(q) { return _lth(o.v, q); }
o.lessThanOrEqualTo = function(q) { return _lte(o.v, q); }
o.increment = function() { return _inc(o.v); }
o.decrement = function() { return _dec(o.v); }
o.is = function() { return _isp(o.v); }
o._ = function(c, q) { return _calculate(o.v, c, q); }
o.text = o.v.s();
o.hasNumber = function() { return o.v.fit; } // True if our value is small enough to fit in a number as an integer, not a floating point number
o.toNumber = o.v.n; // Point to function, throws if too big
o.type = "Int";
return freeze(o);
}
function _3type(p) { // Parse the parameter given to Int or a method on Int, keeping the same integer value in up to 3 different types
var type = getType(p);
if (type == "Int") return p.v; // We got an Int, return the value inside instead of making a new one
// Hold the same integer value 1, 2 or 3 different ways, keeping the type we were given, only converting when necessary, and checking everything we can with the types we have
var b = "none"; // Our integer value in a BigNumber object, or "none" before we have one
var n = "none"; // Our integer value in a number type variable, or "none" before we have one, or if our value won't fit
var s = "none"; // Our integer value as a string of numerals, we always have this type
if (hasMethod(p, "dividedToIntegerBy")) { b = p; s = b.toFixed(0); checkNumerals(s); } // Given a BigNumber, make and check numerals
else if (type == "number") { n = p; checkNumberMath(n); s = n+""; checkNumerals(s); checkNumeralsFit(s); } // Given a number, check it, make numerals, and check them
else if (type == "string") { s = p; checkNumerals(s); } // Given numerals, check them
else { toss("type"); } // Int(p).method(p) only accepts p as an Int, BigNumber, number, or string
var o = {}; // Return, or make, check, keep, and return, our value in a BigNumber, number, or string ♫ There's three ways of saying, the very same thing
o.b = function() { if (b !== "none") return b; b = new platformBigNumber(s); checkSame(s, b.toFixed(0)); return b; } // Make from numerals rather than number to avoid 15 digit limit
o.n = function() { if (n !== "none") return n; n = numeralsToNumber(s); return n; }
o.s = function() { return s; }
o.fit = numeralsFit(s); // Small enough to fit
o.bs = function() { return b !== "none" ? b : s; } // Our value in a BigNumber if we have one, numerals otherwise
o.inside = function() { return "###".fill(b === "none" ? "-" : "b", n === "none" ? "-" : "n", s === "none" ? "-" : "s"); } // Show which types we've built up
return o;
}
// Small values use number for speed Potentially large values use BigNumber instead
function _add(v, q) { var w = _3type(q); return _bothFitProduct(v, w) ? Int(v.n() + w.n()) : Int(v.b().plus( w.bs())); }
function _sub(v, q) { var w = _3type(q); _checkSubtract(v, w); return _bothFit(v, w) ? Int(v.n() - w.n()) : Int(v.b().minus( w.bs())); }
function _mul(v, q) { var w = _3type(q); return _bothFitProduct(v, w) ? Int(v.n() * w.n()) : Int(v.b().times( w.bs())); }
function _div(v, q) { var w = _3type(q); _checkDivide(v, w); return _bothFit(v, w) ? Int(Math.floor(v.n() / w.n())) : Int(v.b().dividedToIntegerBy(w.bs())); }
function _mod(v, q) { var w = _3type(q); _checkDivide(v, w); return _bothFit(v, w) ? Int(v.n() % w.n()) : Int(v.b().mod( w.bs())); }
function _equ(v, q) { var w = _3type(q); return _bothFit(v, w) ? v.n() == w.n() : v.b().equals( w.bs()); }
function _gth(v, q) { var w = _3type(q); return _bothFit(v, w) ? v.n() > w.n() : v.b().greaterThan( w.bs()); }
function _gte(v, q) { var w = _3type(q); return _bothFit(v, w) ? v.n() >= w.n() : v.b().greaterThanOrEqualTo( w.bs()); }
function _lth(v, q) { var w = _3type(q); return _bothFit(v, w) ? v.n() < w.n() : v.b().lessThan( w.bs()); }
function _lte(v, q) { var w = _3type(q); return _bothFit(v, w) ? v.n() <= w.n() : v.b().lessThanOrEqualTo( w.bs()); }
function _inc(v) { return _add(v, 1); }
function _dec(v) { return _sub(v, 1); }
function _isp(v) { return _gth(v, 0); }
function _checkSubtract(v, w) { if (compareCheckedNumerals(v.s(), w.s()) < 0) toss("bounds"); } // Make sure v - w will be 0+, as negative values aren't allowed
function _checkDivide(v, w) { if (w.s() == "0") toss("math"); } // Who says you can't divide by zero? OH SHI-
function _bothFit(v, w) { return v.fit && w.fit; } // True if both values will fit in numbers, so we can use minus, divide, and modulo
function _bothFitProduct(v, w) { // True if adding or multipling the given two numbers can't produce an answer that's too big
return _bothFit(v, w) && v.s().length + w.s().length < (Number.MAX_SAFE_INTEGER+"").length; // Even if v and w are all 9s, a*b will still be a digit shorter than max safe integer
}
function _calculate(v, c, q) { // Who says JavaScript can't do operator overloading?
if (c == "+") { return _add(v, q); }
else if (c == "-") { return _sub(v, q); }
else if (c == "*") { return _mul(v, q); }
else if (c == "/") { return _div(v, q); }
else if (c == "%") { return _mod(v, q); }
else if (c == "==") { return _equ(v, q); }
else if (c == ">") { return _gth(v, q); }
else if (c == ">=") { return _gte(v, q); }
else if (c == "<") { return _lth(v, q); }
else if (c == "<=") { return _lte(v, q); }
else if (c == "++") { return _inc(v); }
else if (c == "--") { return _dec(v); }
else if (c == ">0") { return _isp(v); }
else { toss("code"); }
}
exports.Int = Int;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment