From 7eb3ea06ff217648b68d8d0f43bbdb25431c7771 Mon Sep 17 00:00:00 2001 From: Javier Cejudo Date: Sat, 27 Feb 2016 23:06:58 +1100 Subject: [PATCH] feat: add support for fractional numbers --- README.md | 18 +++++++++--- package.json | 1 + src/R.js | 2 +- src/U.js | 26 +++++++++++++++++ src/algorithm.js | 18 ++++++++++++ src/fracMapper.js | 11 ++++++++ src/index.js | 51 ++++++++++++---------------------- src/translate.js | 11 ++++++++ test/integer-base-converter.js | 8 ++++++ test/spec.js | 24 +++++++++++++--- 10 files changed, 127 insertions(+), 43 deletions(-) create mode 100644 src/U.js create mode 100644 src/algorithm.js create mode 100644 src/fracMapper.js create mode 100644 src/translate.js diff --git a/README.md b/README.md index 5eb39ac..a1b0353 100644 --- a/README.md +++ b/README.md @@ -25,21 +25,32 @@ hexToBin('1E'); //=> '11110' See [spec](test/spec.js). +## Fractional support (including bases) + +```js +bc(9, '11.08'); //=> '10.098765432098766' +``` + +See in [wolfram|Alpha](https://www.wolframalpha.com/input/?i=convert+11.08_9+to+base10). + +```js +bc(3.145, '100.01'); //=> '9.992126756390263' +``` + +See in [wolfram|Alpha](https://www.wolframalpha.com/input/?i=convert+100.01+from+base+3.145+to+base10). + ## Custom symbols For any bases above 62, custom symbols are required. See [tests](test/bigint-base-converter.js) for working examples. ```js -var bc = require('base-conversion-from-dec'); - bc.symbols('⓿①②③④⑤⑥⑦⑧⑨ⒶⒷ', 12, '⑥①'); //=> '⑦③' ``` ## Arbitrary precision ```js -var bc = require('base-conversion-to-dec'); var Big = require('arbitrary-precision')(require('bigjs-adapter')); var toBigFactory = require('to-decimal-arbitrary-precision'); @@ -55,7 +66,6 @@ bc.big(d, 9, '802531310452364303450750087576673257456135727727'); ## Full raw version ```js -var bc = require('base-conversion-to-dec'); var Big = require('arbitrary-precision')(require('bigjs-adapter')); var toBigFactory = require('to-decimal-arbitrary-precision'); diff --git a/package.json b/package.json index 606c9a8..f8806a0 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "positional-notation": "^2.0.0", "pow-arbitrary-precision": "^2.1.0", "ramda": "^0.19.1", + "string-translate": "^1.1.1", "times-arbitrary-precision": "^1.1.0", "to-decimal-arbitrary-precision": "^1.0.2" } diff --git a/src/R.js b/src/R.js index bac87cc..df7f35e 100644 --- a/src/R.js +++ b/src/R.js @@ -5,13 +5,13 @@ module.exports = Object.freeze({ __: require('ramda/src/__'), addIndex: require('ramda/src/addIndex'), + adjust: require('ramda/src/adjust'), curryN: require('ramda/src/curryN'), identical: require('ramda/src/identical'), identity: require('ramda/src/identity'), indexOf: require('ramda/src/indexOf'), invoker: require('ramda/src/invoker'), join: require('ramda/src/join'), - nth: require('ramda/src/nth'), map: require('ramda/src/map'), memoize: require('ramda/src/memoize'), pipe: require('ramda/src/pipe'), diff --git a/src/U.js b/src/U.js new file mode 100644 index 0000000..804d05b --- /dev/null +++ b/src/U.js @@ -0,0 +1,26 @@ +/*jshint node:true */ + +'use strict'; + +var R = require('./R'); + +var add = R.invoker(1, 'plus'); + +module.exports = Object.freeze({ + add: add, + + indexOfSymbol: R.memoize(function(symbols) { + return R.memoize(R.indexOf(R.__, symbols)); + }), + + joinWithoutSep: R.join(''), + joinWithDot: R.join('.'), + + splitByDot: R.split('.'), + + sum: function(big) { + return R.reduce(add, big('0')); + }, + + toString: R.invoker(0, 'toString') +}); diff --git a/src/algorithm.js b/src/algorithm.js new file mode 100644 index 0000000..c598613 --- /dev/null +++ b/src/algorithm.js @@ -0,0 +1,18 @@ +/*jshint node:true */ + +'use strict'; + +var toBigFactory = require('to-decimal-arbitrary-precision'); + +var R = require('./R'); +var U = require('./U'); + +var toDecimalRaw = R.curryN(5, function(mapper, big, symbols, base, n) { + return R.pipe( + R.map(U.indexOfSymbol(symbols)), + R.addIndex(R.map)(mapper(big, base)), + U.sum(big) + )(n); +}); + +module.exports = toDecimalRaw; diff --git a/src/fracMapper.js b/src/fracMapper.js new file mode 100644 index 0000000..a270841 --- /dev/null +++ b/src/fracMapper.js @@ -0,0 +1,11 @@ +/*jshint node:true */ + +'use strict'; + +var posNotation = require('positional-notation'); + +var R = require('./R'); + +module.exports = R.curryN(4, function(big, base, val, index) { + return posNotation.raw(big, base, [-index - 1, val]); +}); diff --git a/src/index.js b/src/index.js index b694dd4..ce12b1f 100644 --- a/src/index.js +++ b/src/index.js @@ -6,51 +6,34 @@ var posNotation = require('positional-notation'); var toBigFactory = require('to-decimal-arbitrary-precision'); var R = require('./R'); +var U = require('./U'); +var toDecimalAlg = require('./algorithm'); +var fracMapper = require('./fracMapper'); +var translate = require('./translate'); -var defaultB = toBigFactory(require('./Big')); +var defaultBig = toBigFactory(require('./Big')); var defaultSymbols = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; -var joinWithoutSep = R.join(''); -var splitWithoutSep = R.split(''); -var toString = R.invoker(0, 'toString'); -var add = R.invoker(1, 'plus'); -var indexOfSymbol = R.memoize(function(symbols) { - return R.memoize(R.indexOf(R.__, symbols)); -}); - -var nthSymbol = R.memoize(function(symbols) { - return R.memoize(R.nth(R.__, symbols)); -}); - -var postprocess = R.memoize(function(symbols) { - return R.identical(symbols, defaultSymbols) ? - R.identity : - R.pipe( - R.map(nthSymbol(symbols)), - joinWithoutSep, - toString - ); -}); - -var toDecimalRaw = R.curryN(4, function(b, symbols, base, n) { +var toDecimalRaw = R.curryN(4, function(big, symbols, base, n) { return R.pipe( - toString, - R.reverse, - R.map(indexOfSymbol(symbols)), - R.addIndex(R.map)(posNotation.mapper(b, base)), - R.reduce(add, b(0)), - toString, - postprocess(symbols) + U.toString, + U.splitByDot, + R.adjust(R.reverse, 0), + R.adjust(toDecimalAlg(posNotation.mapper, big, symbols, base), 0), + R.adjust(toDecimalAlg(fracMapper, big, symbols, base), 1), + U.sum(big), + U.toString, + translate(defaultSymbols, symbols) )(n); }); -var toDecimal = toDecimalRaw(defaultB, defaultSymbols); +var toDecimal = toDecimalRaw(defaultBig, defaultSymbols); toDecimal.big = toDecimalRaw(R.__, defaultSymbols); -toDecimal.symbols = toDecimalRaw(defaultB); +toDecimal.symbols = toDecimalRaw(defaultBig); toDecimal.raw = toDecimalRaw; toDecimal.defaultSymbols = defaultSymbols; -toDecimal.defaultB = defaultB; +toDecimal.defaultBig = defaultBig; module.exports = toDecimal; diff --git a/src/translate.js b/src/translate.js new file mode 100644 index 0000000..a17b86d --- /dev/null +++ b/src/translate.js @@ -0,0 +1,11 @@ +/*jshint node:true */ + +'use strict'; + +var tr = require('string-translate'); + +var R = require('./R'); + +module.exports = R.memoize(function(defaultSymbols, symbols) { + return R.identical(defaultSymbols, symbols) ? R.identity : tr(defaultSymbols, symbols); +}); diff --git a/test/integer-base-converter.js b/test/integer-base-converter.js index 2c2f2c8..61c3104 100644 --- a/test/integer-base-converter.js +++ b/test/integer-base-converter.js @@ -19,4 +19,12 @@ describe('integer-base-converter', function() { .should.be.exactly(other.convert('Gf', 60, 10).toString()) .and.exactly(b60To10('Gf')); }); + + it.skip('yields the same results for fractionals from base 60', function() { + var b60To10 = fn(60); + + '3.14159' + .should.be.exactly(other.convert('3.8ThQO', 60, 10).toString()) + .and.exactly(b60To10('3.8ThQO')); + }); }); diff --git a/test/spec.js b/test/spec.js index 581a818..4a0b4a9 100644 --- a/test/spec.js +++ b/test/spec.js @@ -10,14 +10,14 @@ var toBigFactory = require('to-decimal-arbitrary-precision'); var fn = require('../src/'); describe('base conversion', function() { - it('base 62 to decimal', function() { + it('should support base 62 to decimal', function() { var decTo62 = fn(62); decTo62('y').should.be.exactly('60'); decTo62('11').should.be.exactly('63'); }); - it('large base 9 to decimal', function() { + it('should support large base 9 to decimal', function() { var d = toBigFactory(Big); Big.Impl.E_POS = 50; @@ -39,7 +39,23 @@ describe('base conversion', function() { .should.be.exactly('#678364#6#34#634#634#63467#7364#63#34#3464#74#'); }); - it.skip('non-integer from base 9', function() { - fn(9, '11.08').should.be.exactly('10.10'); + it('should supportnon-integer from binary', function() { + fn.symbols('⓿①②③④⑤⑥⑦⑧⑨', 2, '①⓿⓿①.①⓿①') + .should.be.exactly('⑨.⑥②⑤'); + }); + + it('should support non-integer from base 60', function() { + fn(60, '3.8ThQO') + .should.be.exactly('3.14159'); + }); + + it('should support non-integer from base 9', function() { + fn(9, '11.08') + .should.be.exactly('10.098765432098766'); + }); + + it('should support non-integer from non-integer base 3.145', function() { + fn(3.145, '100.01') + .should.be.exactly('9.992126756390263'); }); });