summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--index.js56
-rw-r--r--test/01-basic.js166
2 files changed, 203 insertions, 19 deletions
diff --git a/index.js b/index.js
index 6218073..71d93d9 100644
--- a/index.js
+++ b/index.js
@@ -6,32 +6,41 @@ basic.abedecary = "0123456789abcdefghijklmnopqrstuvwxyz"
// Validate that a string s represents a number in base b
basic.validate = function (s, b) {
- return (base.validate_base(b) && base.validate_digits(s, b))
+ return (basic.validate_base(b) && basic.validate_digits(s, b))
}
// Validate that a string does not contain numerals
// foreign to a particular base.
basic.validate_digits = function(s, b) {
- var A = basic.abedecary.substr(0, b)
- var re = new RegExp ( "[^" + A + "]" )
- return !! re.match(s)
+ var A = basic.abedecary.substr(0, Math.abs(b))
+ if (b > 0) {
+ A = "-" + A
+ }
+ var re = new RegExp ( "[^" + A + "]", "g" )
+ return ! re.test(s)
}
// Validate that a base is valid.
basic.validate_base = function(b){
- return (b !== 0 && b !== 1 && b !== -1 && (Math.abs(b) % 2) === 0)
+ return (
+ ! isNaN(b)
+ && b !== 0
+ && b !== 1
+ && b !== -1
+ && (Math.abs(b) % 1) === 0
+ && Math.abs(b) <= 36
+ )
}
// 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)) {
+ if (! basic.validate(s, b)) {
return NaN
}
var n = 0
- s = s.reverse()
for (var i = 0, len = s.length; i < len; i++) {
- n += parseInt(s[i]) * Math.pow(b, i)
+ n += basic.abedecary.indexOf(s[len-1-i]) * Math.pow(b, i)
}
return n
}
@@ -42,23 +51,34 @@ 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 = ""
- var dividend, residual
while (n) {
- remainder = basic.mod(n, b)
- n = Math.floor(n/b)
- if (remainder) {
+ var remainder = n % b
+ n = basic.floor(n / b)
+ if (remainder < 0) {
n += 1
+ remainder -= b
}
- s += basic.abedecary[n]
+ s = basic.abedecary[remainder] + s
+ }
+ if (is_negative && b > 0) {
+ s = "-" + s
}
return s
}
-// Compute the residual of N mod M
-// Handle negative N and M correctly
-basic.mod = function (n,m){
- m = Math.abs(m)
- return n-(m * Math.floor(n/m))
+// Remove the mantissa from a number, handling negative numbers
+basic.floor = function (n){
+ if (n >= 0) {
+ return Math.floor(n)
+ }
+ return -1 * Math.floor(-n)
}
diff --git a/test/01-basic.js b/test/01-basic.js
index 5190008..8edb5f4 100644
--- a/test/01-basic.js
+++ b/test/01-basic.js
@@ -13,8 +13,172 @@ var basic = require('../index')
describe('basic', function(){
describe('#validate_base()', function(){
it('validates positive bases', function(done){
- assert( basic.validate_base(2), true )
+ assert.equal( basic.validate_base(2), true )
done()
})
+ it('validates negative bases', function(done){
+ assert.equal( basic.validate_base(-2), true )
+ 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()
+ })
+ it('does not validate bad bases', function(done){
+ assert.equal( basic.validate_base(-1), false )
+ assert.equal( basic.validate_base(0), false )
+ assert.equal( basic.validate_base(1), false )
+ assert.equal( basic.validate_base(NaN), false )
+ assert.equal( basic.validate_base(Infinity), false )
+ assert.equal( basic.validate_base(-Infinity), false )
+ done()
+ })
+ it('does not validate non-integer bases', function(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()
+ })
+ it('validates base 2', function(done){
+ assert.equal( basic.validate_digits("1010101", 2), true )
+ assert.equal( basic.validate_digits("1222222", 2), false )
+ done()
+ })
+ it('validates base 3', function(done){
+ assert.equal( basic.validate_digits("1201120", 3), true )
+ assert.equal( basic.validate_digits("1234567", 3), false )
+ done()
+ })
+ it('validates base -2', function(done){
+ assert.equal( basic.validate_digits("1010101", -2), true )
+ 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()
+ })
+ })
})