diff options
| author | Jules <jules@asdf.us> | 2017-03-12 15:49:12 -0400 |
|---|---|---|
| committer | Jules <jules@asdf.us> | 2017-03-12 15:49:12 -0400 |
| commit | 4cf0c1611192bc353db3b1676fca28a2a370b66a (patch) | |
| tree | 4ebc379117e248c3955e48feeb75cd3d5e8d0cc0 | |
| parent | 15ddd0beabb2342d9d68ff4625139ab7fb456ace (diff) | |
| -rw-r--r-- | index.html | 70 | ||||
| -rw-r--r-- | index.js | 101 | ||||
| -rw-r--r-- | test/01-basic.js | 260 |
3 files changed, 215 insertions, 216 deletions
@@ -11,19 +11,19 @@ button { font-size: 200%; } <body class="loading"> <div id="numbers"> - <script type="text/html" id="number-template"> - <div> - <label for="base-{{base}}">{{base}}</label> - <input id="base-{{base}}" type="text"> - </div> - </script> - </div> + <script type="text/html" id="number-template"> + <div> + <label for="base-{{base}}">{{base}}</label> + <input id="base-{{base}}" type="text"> + </div> + </script> + </div> <div id="buttons"> - <button id="add">+</button> - <button id="sub">-</button> - <button id="inv">(-)</button> - </div> + <button id="add">+</button> + <button id="sub">-</button> + <button id="inv">(-)</button> + </div> </body> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script> <script src="./index.js"></script> @@ -33,8 +33,8 @@ var $inputs = {} var template = $("#number-template").html() function init () { iter(build) - bind() - rebuild(0) + bind() + rebuild(0) $("body").removeClass("loading") } function bind () { @@ -44,46 +44,46 @@ function bind () { } function build (base) { var $div, $input - $div = $(template.replace(/{{base}}/g, base)) - $input = $div.find("input") - $input.on("input", function(){ - var n = basic.toNumber( $input.val(), base ) - if (isNaN(n)) { - return - } - rebuild(n, base) - }) - $inputs[base] = $input + $div = $(template.replace(/{{base}}/g, base)) + $input = $div.find("input") + $input.on("input", function(){ + var n = basic.toNumber( $input.val(), base ) + if (isNaN(n)) { + return + } + rebuild(n, base) + }) + $inputs[base] = $input $("#numbers").prepend($div) } function rebuild (n, base) { iter(function(i){ - if (i == base) return - var $i = $inputs[i] - var v = basic.toString(n, i) - $i.val(v) + if (i == base) return + var $i = $inputs[i] + var v = basic.toString(n, i) + $i.val(v) }) } function iter (f) { for (var i = -MAX_BASE; i <= MAX_BASE; i++) { if (basic.validate_base(i)) { - f(i) - } - } + f(i) + } + } } function current () { var n = basic.toNumber( $inputs[2].val(), 2 ) - if (isNaN(n)) n = 2 - return n + if (isNaN(n)) n = 2 + return n } function add () { - rebuild( current() + 1 ) + rebuild( current() + 1 ) } function sub () { - rebuild( current() - 1 ) + rebuild( current() - 1 ) } function inv () { - rebuild( current() * -1 ) + rebuild( current() * -1 ) } init() @@ -17,79 +17,78 @@ basic.validate = function (s, b) { // foreign to a particular base. basic.validate_digits = function(s, b) { var A = basic.abedecary.substr(0, Math.abs(b)) - if (b > 0) { - A = "-" + A + if (b > 0) { + A = "-" + A } - var re = new RegExp ( "[^" + A + "]", "g" ) - return ! re.test(s) + var re = new RegExp ( "[^" + A + "]", "g" ) + return ! re.test(s) } // Validate that a base is valid. basic.validate_base = function(b){ - return ( - ! isNaN(b) - && b !== 0 - && b !== 1 - && b !== -1 - && (Math.abs(b) % 1) === 0 - && Math.abs(b) <= 36 - ) + b = Math.abs(b) + return ( + ! isNaN(b) + && b > 1 + && b <= 36 + && (b % 1) === 0 + ) } // Convert a string s representing a number in base b // to an integer. Assumes s is big-endian. basic.toNumber = function (s, b) { - if (! basic.validate(s, b)) { - return NaN - } + if (! basic.validate(s, b)) { + return NaN + } var n = 0, is_negative = false - if (s.indexOf("-") == 0) { - is_negative = true - s = s.substr(1) - } - for (var i = 0, len = s.length; i < len; i++) { - n += basic.abedecary.indexOf(s[len-1-i]) * Math.pow(b, i) - } - if (is_negative) { - n *= -1 - } - return n + if (s.indexOf("-") == 0) { + is_negative = true + s = s.substr(1) + } + for (var i = 0, len = s.length; i < len; i++) { + n += basic.abedecary.indexOf(s[len-1-i]) * Math.pow(b, i) + } + if (is_negative) { + n *= -1 + } + return n } // Convert an integer n to a string representing that // integer in base b, big-endian. basic.toString = function (n, b) { - if (! basic.validate_base(b)) { - throw new Error ("invalid base") - } - if (n === 0) { - return "0" - } - var is_negative = n < 0 - if (is_negative && b > 0) { - n = Math.abs(n) - } - var s = "" - while (n) { - var remainder = n % b + if (! basic.validate_base(b)) { + throw new Error ("invalid base") + } + if (n === 0) { + return "0" + } + var is_negative = n < 0 + if (is_negative && b > 0) { + n = Math.abs(n) + } + var s = "" + while (n) { + var remainder = n % b n = basic.floor(n / b) - if (remainder < 0) { - n += 1 - remainder -= b - } - s = basic.abedecary[remainder] + s - } - if (is_negative && b > 0) { - s = "-" + s - } - return s + if (remainder < 0) { + n += 1 + remainder -= b + } + s = basic.abedecary[remainder] + s + } + if (is_negative && b > 0) { + s = "-" + s + } + return s } // Remove the mantissa from a number, handling negative numbers basic.floor = function (n){ if (n >= 0) { - return Math.floor(n) + return Math.floor(n) } - return -1 * Math.floor(-n) + return -1 * Math.floor(-n) } diff --git a/test/01-basic.js b/test/01-basic.js index 8edb5f4..cb5c194 100644 --- a/test/01-basic.js +++ b/test/01-basic.js @@ -14,18 +14,18 @@ describe('basic', function(){ describe('#validate_base()', function(){ it('validates positive bases', function(done){ assert.equal( basic.validate_base(2), true ) - done() + done() }) it('validates negative bases', function(done){ assert.equal( basic.validate_base(-2), true ) - done() + done() }) it('does not validate abs(base) > 36', function(done){ assert.equal( basic.validate_base(36), true ) assert.equal( basic.validate_base(37), false ) assert.equal( basic.validate_base(-36), true ) assert.equal( basic.validate_base(-37), false ) - done() + done() }) it('does not validate bad bases', function(done){ assert.equal( basic.validate_base(-1), false ) @@ -34,151 +34,151 @@ describe('basic', function(){ assert.equal( basic.validate_base(NaN), false ) assert.equal( basic.validate_base(Infinity), false ) assert.equal( basic.validate_base(-Infinity), false ) - done() + done() }) it('does not validate non-integer bases', function(done){ - assert.equal( basic.validate_base(1.1), false ) - done() - }) + assert.equal( basic.validate_base(1.1), false ) + done() + }) }) describe('#validate_digits()', function(){ it('validates negative numbers', function(done){ assert.equal( basic.validate_digits("-1234567890", 10), true ) assert.equal( basic.validate_digits("-123456789a", 10), false ) - done() + done() }) it('validates base 2', function(done){ assert.equal( basic.validate_digits("1010101", 2), true ) assert.equal( basic.validate_digits("1222222", 2), false ) - done() + done() }) it('validates base 3', function(done){ assert.equal( basic.validate_digits("1201120", 3), true ) assert.equal( basic.validate_digits("1234567", 3), false ) - done() + done() }) it('validates base -2', function(done){ assert.equal( basic.validate_digits("1010101", -2), true ) - done() + done() + }) + it('validates bases up to 36 and -36', function(done){ + for (var i = 2; i <= 36; i++) { + var s = basic.abedecary.substr(0, i).split("").reverse().join("") + assert.equal( basic.validate_digits(s, i), true ) + assert.equal( basic.validate_digits(s, -i), true ) + } + done() + }) + }) + describe('#validate()', function(){ + it('validates number and base', function(done){ + assert.equal( basic.validate_digits("1234567890", 10), true ) + assert.equal( basic.validate_digits("1234567890", -10), true ) + assert.equal( basic.validate_digits("123456789a", 10), false ) + assert.equal( basic.validate_digits("123456789a", -10), false ) + done() + }) + }) + describe('#floor()', function(){ + it('removes the mantissa of negative numbers', function(done){ + assert.equal( basic.floor(2.2), 2 ) + assert.equal( basic.floor(-2.2), -2 ) + done() + }) + }) + describe('#toNumber()', function(){ + it('handles base 2', function(done){ + assert.equal( basic.toNumber("00", 2), 0 ) + assert.equal( basic.toNumber("01", 2), 1 ) + assert.equal( basic.toNumber("10", 2), 2 ) + assert.equal( basic.toNumber("11", 2), 3 ) + done() + }) + it('handles base -2', function(done){ + assert.equal( basic.toNumber("00", -2), 0 ) + assert.equal( basic.toNumber("01", -2), 1 ) + assert.equal( basic.toNumber("10", -2), -2 ) + assert.equal( basic.toNumber("11", -2), -1 ) + assert.equal( basic.toNumber("101101", -2), -35 ) + done() + }) + it('handles base 10', function(done){ + assert.equal( basic.toNumber("100", 10), 100 ) + done() + }) + it('inverts toString', function(done){ + assert.equal( basic.toNumber(basic.toString(100, 10), 10), 100 ) + assert.equal( basic.toNumber(basic.toString(100, 3), 3), 100 ) + assert.equal( basic.toNumber(basic.toString(100, 2), 2), 100 ) + assert.equal( basic.toNumber(basic.toString(100, -2), -2), 100 ) + assert.equal( basic.toNumber(basic.toString(100, -3), -3), 100 ) + assert.equal( basic.toNumber(basic.toString(100, -10), -10), 100 ) + done() + }) + }) + describe('#toString()', function(){ + it('handles base 2', function(done){ + assert.equal( basic.toString(0, 2), "0" ) + assert.equal( basic.toString(1, 2), "1" ) + assert.equal( basic.toString(2, 2), "10" ) + assert.equal( basic.toString(3, 2), "11" ) + assert.equal( basic.toString(4, 2), "100" ) + assert.equal( basic.toString(5, 2), "101" ) + assert.equal( basic.toString(6, 2), "110" ) + done() + }) + it('handles base 3', function(done){ + assert.equal( basic.toString(0, 3), "0" ) + assert.equal( basic.toString(1, 3), "1" ) + assert.equal( basic.toString(-1, 3), "-1" ) + assert.equal( basic.toString(2, 3), "2" ) + assert.equal( basic.toString(3, 3), "10" ) + assert.equal( basic.toString(4, 3), "11" ) + assert.equal( basic.toString(5, 3), "12" ) + assert.equal( basic.toString(6, 3), "20" ) + assert.equal( basic.toString(9, 3), "100" ) + assert.equal( basic.toString(26, 3), "222" ) + assert.equal( basic.toString(27, 3), "1000" ) + assert.equal( basic.toString(28, 3), "1001" ) + done() + }) + it('handles base 10', function(done){ + assert.equal( basic.toString(1, 10), "1" ) + assert.equal( basic.toString(2, 10), "2" ) + assert.equal( basic.toString(3, 10), "3" ) + assert.equal( basic.toString(9, 10), "9" ) + assert.equal( basic.toString(10, 10), "10" ) + assert.equal( basic.toString(19, 10), "19" ) + assert.equal( basic.toString(20, 10), "20" ) + assert.equal( basic.toString(-20, 10), "-20" ) + done() + }) + it('handles base -2', function(done){ + assert.equal( basic.toString(0, -2), "0" ) + assert.equal( basic.toString(1, -2), "1" ) + assert.equal( basic.toString(2, -2), "110" ) + assert.equal( basic.toString(3, -2), "111" ) + assert.equal( basic.toString(-1, -2), "11" ) + assert.equal( basic.toString(-2, -2), "10" ) + assert.equal( basic.toString(-3, -2), "1101" ) + assert.equal( basic.toString(-4, -2), "1100" ) + done() + }) + it('handles base -3', function(done){ + assert.equal( basic.toString(119, -3), "22102" ) + done() + }) + it('inverts toNumber', function(done){ + for (var i = 2; i <= 36; i++) { + var s = basic.abedecary.substr(0, i) + .split("") + .reverse() + .join("") + .substr(0, 9) // cutoff here, otherwise we get rounding error + assert.equal( basic.toString(basic.toNumber(s, i), i), s ) + assert.equal( basic.toString(basic.toNumber(s, -i), -i), s ) + } + done() }) - it('validates bases up to 36 and -36', function(done){ - for (var i = 2; i <= 36; i++) { - var s = basic.abedecary.substr(0, i).split("").reverse().join("") - assert.equal( basic.validate_digits(s, i), true ) - assert.equal( basic.validate_digits(s, -i), true ) - } - done() - }) }) - describe('#validate()', function(){ - it('validates number and base', function(done){ - assert.equal( basic.validate_digits("1234567890", 10), true ) - assert.equal( basic.validate_digits("1234567890", -10), true ) - assert.equal( basic.validate_digits("123456789a", 10), false ) - assert.equal( basic.validate_digits("123456789a", -10), false ) - done() - }) - }) - describe('#floor()', function(){ - it('removes the mantissa of negative numbers', function(done){ - assert.equal( basic.floor(2.2), 2 ) - assert.equal( basic.floor(-2.2), -2 ) - done() - }) - }) - describe('#toNumber()', function(){ - it('handles base 2', function(done){ - assert.equal( basic.toNumber("00", 2), 0 ) - assert.equal( basic.toNumber("01", 2), 1 ) - assert.equal( basic.toNumber("10", 2), 2 ) - assert.equal( basic.toNumber("11", 2), 3 ) - done() - }) - it('handles base -2', function(done){ - assert.equal( basic.toNumber("00", -2), 0 ) - assert.equal( basic.toNumber("01", -2), 1 ) - assert.equal( basic.toNumber("10", -2), -2 ) - assert.equal( basic.toNumber("11", -2), -1 ) - assert.equal( basic.toNumber("101101", -2), -35 ) - done() - }) - it('handles base 10', function(done){ - assert.equal( basic.toNumber("100", 10), 100 ) - done() - }) - it('inverts toString', function(done){ - assert.equal( basic.toNumber(basic.toString(100, 10), 10), 100 ) - assert.equal( basic.toNumber(basic.toString(100, 3), 3), 100 ) - assert.equal( basic.toNumber(basic.toString(100, 2), 2), 100 ) - assert.equal( basic.toNumber(basic.toString(100, -2), -2), 100 ) - assert.equal( basic.toNumber(basic.toString(100, -3), -3), 100 ) - assert.equal( basic.toNumber(basic.toString(100, -10), -10), 100 ) - done() - }) - }) - describe('#toString()', function(){ - it('handles base 2', function(done){ - assert.equal( basic.toString(0, 2), "0" ) - assert.equal( basic.toString(1, 2), "1" ) - assert.equal( basic.toString(2, 2), "10" ) - assert.equal( basic.toString(3, 2), "11" ) - assert.equal( basic.toString(4, 2), "100" ) - assert.equal( basic.toString(5, 2), "101" ) - assert.equal( basic.toString(6, 2), "110" ) - done() - }) - it('handles base 3', function(done){ - assert.equal( basic.toString(0, 3), "0" ) - assert.equal( basic.toString(1, 3), "1" ) - assert.equal( basic.toString(-1, 3), "-1" ) - assert.equal( basic.toString(2, 3), "2" ) - assert.equal( basic.toString(3, 3), "10" ) - assert.equal( basic.toString(4, 3), "11" ) - assert.equal( basic.toString(5, 3), "12" ) - assert.equal( basic.toString(6, 3), "20" ) - assert.equal( basic.toString(9, 3), "100" ) - assert.equal( basic.toString(26, 3), "222" ) - assert.equal( basic.toString(27, 3), "1000" ) - assert.equal( basic.toString(28, 3), "1001" ) - done() - }) - it('handles base 10', function(done){ - assert.equal( basic.toString(1, 10), "1" ) - assert.equal( basic.toString(2, 10), "2" ) - assert.equal( basic.toString(3, 10), "3" ) - assert.equal( basic.toString(9, 10), "9" ) - assert.equal( basic.toString(10, 10), "10" ) - assert.equal( basic.toString(19, 10), "19" ) - assert.equal( basic.toString(20, 10), "20" ) - assert.equal( basic.toString(-20, 10), "-20" ) - done() - }) - it('handles base -2', function(done){ - assert.equal( basic.toString(0, -2), "0" ) - assert.equal( basic.toString(1, -2), "1" ) - assert.equal( basic.toString(2, -2), "110" ) - assert.equal( basic.toString(3, -2), "111" ) - assert.equal( basic.toString(-1, -2), "11" ) - assert.equal( basic.toString(-2, -2), "10" ) - assert.equal( basic.toString(-3, -2), "1101" ) - assert.equal( basic.toString(-4, -2), "1100" ) - done() - }) - it('handles base -3', function(done){ - assert.equal( basic.toString(119, -3), "22102" ) - done() - }) - it('inverts toNumber', function(done){ - for (var i = 2; i <= 36; i++) { - var s = basic.abedecary.substr(0, i) - .split("") - .reverse() - .join("") - .substr(0, 9) // cutoff here, otherwise we get rounding error - assert.equal( basic.toString(basic.toNumber(s, i), i), s ) - assert.equal( basic.toString(basic.toNumber(s, -i), -i), s ) - } - done() - }) - }) }) |
