Created
November 30, 2015 20:16
-
-
Save zootella/84e943a4876b8de4137f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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