Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // A big counter is an arbitrary precision positive integer which you can add or subtract values from.
- // If any value goes below zero it returns zero.
- // Example Usage
- // n = BigCounter("9999999999999999999999999")
- // n.add("7777777777777777777")
- // n.subtract("1");
- // n.greaterThan("100"); -- true
- // creates a big counter array from a string or number.
- BigCounter.runTests = function(){
- console.log("Running BigCounter test cases. . . ");
- n = BigCounter("9999999999999999999999999")
- console.log('n = BigCounter("9999999999999999999999999"): ' + n);
- console.log('n.add("7777777777777777777"): ' + n.add("7777777777777777777"));
- console.log('n.subtract("1"): ' + n.subtract("1"));
- console.log('n.greaterThan("100"): ' + n.greaterThan("100"));
- console.log('n.subtract("9999999999999999999999999999999999"): ' + n.subtract("9999999999999999999999999999999999"));
- console.log('n.greaterThan("100"): ' + n.greaterThan("100"));
- }
- function BigCounter(x){
- BIG_DIGIT_LOG_BASE = 9; // base 1 billion
- BIG_DIGIT_BASE = Math.pow(10, BIG_DIGIT_LOG_BASE);
- var result = [];
- if(Array.isArray(x)){
- assertBigCounter(x);
- return x; }
- if(typeof x == "string"){
- while(x.length > 0){
- var i = x.length-BIG_DIGIT_LOG_BASE;
- result.unshift(parseInt(x.substring(i)));
- x = x.substring(0,i); }}
- else{ result.unshift(parseInt(x)); }
- result.toString = bigCounterToString;
- result.add = function(other){ return bigAdd2(this, BigCounter(other)); }
- result.subtract = function(other){ return bigSubtract2(this, BigCounter(other)); }
- result.equals = function(other){ return this.toString() == other.toString(); }
- result.greaterThan = function(other){
- var s = other.toString();
- var t = this.toString();
- if(s.length > t.length) return false;
- if(t.length > s.length) return true;
- return t > s; // lexicographical comparison works if they are the same length
- }
- result.lessThan = function(other){
- var s = other.toString();
- var t = this.toString();
- if(s.length < t.length) return false;
- if(t.length < s.length) return true;
- return t < s;
- }
- return result;
- // converts a big counter array to a string
- function bigCounterToString(n){
- if(n === undefined) n = this;
- assertBigCounter(n);
- if(n.length == 1 && n[0] == 0) return "0";
- var result = n.reduce(function(s,x){
- return (s? s: "") + (x + BIG_DIGIT_BASE).toString().substring(1); });
- return result.substring(result.indexOf(/[^0]/));
- }
- // should be array of integers in range [0, BIG_DIGIT_BASE)
- function assertBigCounter(n){
- if(!Array.isArray(n)){
- throw new Error("Big counter should be array"); }
- for(var i=0; i < n.length; ++i){
- var digit = n[i];
- if(isNaN(digit)){
- throw new Error("Big counter digit not a number: " + digit); }
- if(digit < 0 || digit >= BIG_DIGIT_BASE){
- throw new Error("Big counter digit out of range"); }
- if(n.length > 1 && i==0 && digit == 0){
- throw new Error("Big counter leading digit was zero."); }
- if(digit - Math.round(digit) > 0.0001){
- throw new Error("Big counter digit not an integer"); }
- }
- }
- // add a small number to the counter and return a value.
- //function bigAdd(n, x){
- // assertBigCounter(n);
- // n[n.length-1] += x;
- // return bigCarryOrBorrow(n);
- //}
- // these functions both operate in place and return the value.
- // add 2 big counters
- function bigAdd2(n, m){
- var n_len = n.length;
- var m_len = m.length;
- var len = Math.min(m_len, n_len);
- for(var i=1; i<=len; ++i){
- n[n_len-i] += m[m_len-i]; }
- if(m_len > n_len){
- for(var i=n_len + 1; i<=m_len; ++i){
- n.unshift(m[m_len - i]); }}
- // console.log("n", n, "m", m);
- return bigCarryOrBorrow(n);
- }
- function bigSubtract2(n, m){
- var n_len = n.length;
- var m_len = m.length;
- if(m_len > n_len){
- console.warn("BigCounter: Negative value changed to zero");
- n[0] = 0;
- n.length = 1;
- return n; }
- for(var i=1; i<=m_len; ++i){
- n[n_len-i] -= m[m_len-i]; }
- return bigCarryOrBorrow(n);
- }
- // carry or borrow
- // may not go below zero.
- function bigCarryOrBorrow(n){
- for(var i=n.length-1; i >= 0; --i){
- var x = n[i];
- if(x >= BIG_DIGIT_BASE || (x < 0 && i > 0)){
- var extra = Math.floor(x/BIG_DIGIT_BASE);
- n[i] -= extra * BIG_DIGIT_BASE;
- if(i == 0){
- n.unshift(extra);
- ++i; }
- n[i-1] += extra;
- }
- }
- while(n.length > 1 && n[0] == 0){
- n.shift(); }
- if(n.length && n[0] < 0){
- console.warn("BigCounter: Negative value changed to zero");
- n[0] = 0;
- n.length = 1; }
- return n;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement