Skip to content

Instantly share code, notes, and snippets.

@zootella
Created November 18, 2015 19:59
Show Gist options
  • Select an option

  • Save zootella/36a5d2d71d0ac8183773 to your computer and use it in GitHub Desktop.

Select an option

Save zootella/36a5d2d71d0ac8183773 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._ = function(c, q) { return _calculate(o.v, c, _3type(q)); } // Who says JavaScript can't do operator overloading?
o.text = o.v.s();
o.hasNumber = function() { return o.v.fit; } // True if our value is small enough it will fit in a number as an integer, not a floating point number
o.toNumber = function() { return o.v.n(); } // 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 = p.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 works 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; } // BigNumber, make it from numerals rather than a number to avoid a separate lower size limit
o.n = function() { if (n !== "none") return n; n = numeralsToNumber(s); return n; } // number
o.s = function() { return s; } // string of numerals
o.fit = numeralsFit(s); // True if you can call o.n() to get our value as a number, because it's small enough to fit
o.bs = function() { return b !== "none" ? b : s; } // Our value in a BigNumber if we have one, numerals otherwise
return o;
}
function _calculate(v, c, w) {
// For small values, use number for speed For potentially large values, use BigNumber instead
if (c == "+") { if (_bothFitProduct(v, w)) return Int(v.n() + w.n()); else return Int(v.b().plus( w.bs())); }
else if (c == "-") { _checkSubtract(v, w); if (_bothFit(v, w)) return Int(v.n() - w.n()); else return Int(v.b().minus( w.bs())); }
else if (c == "*") { if (_bothFitProduct(v, w)) return Int(v.n() * w.n()); else return Int(v.b().times( w.bs())); }
else if (c == "/") { _checkDivide(v, w); if (_bothFit(v, w)) return Int(Math.floor(v.n() / w.n())); else return Int(v.b().dividedToIntegerBy( w.bs())); }
else if (c == "%") { _checkDivide(v, w); if (_bothFit(v, w)) return Int(v.n() % w.n()); else return Int(v.b().mod( w.bs())); }
else if (c == "==") { if (_bothFit(v, w)) return v.n() == w.n(); else return v.b().equals( w.bs()); }
else if (c == ">") { if (_bothFit(v, w)) return v.n() > w.n(); else return v.b().greaterThan( w.bs()); }
else if (c == ">=") { if (_bothFit(v, w)) return v.n() >= w.n(); else return v.b().greaterThanOrEqualTo( w.bs()); }
else if (c == "<") { if (_bothFit(v, w)) return v.n() < w.n(); else return v.b().lessThan( w.bs()); }
else if (c == "<=") { if (_bothFit(v, w)) return v.n() <= w.n(); else return v.b().lessThanOrEqualTo( w.bs()); }
else { toss("code"); }
}
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 number operators that produce smaller values like 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
}
exports.Int = Int;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment