Addition of integer-formatted strings (base 10) of indefinite lengths can be done by splitting the string into segments of 9 characters, calculating +
or -
for that and then moving to the preceding 9 characters. This is because the largest 9 character number, 999999999
is 32-bit safe (as is 1999999999
, which I used in subtraction).
The following code has 3 functions and the word integer is assumed to mean an integer-formatted string.
addAsString
, takes two non-negative integers x
and y
, returns x + y
subtractAsString
, takes two non-negative integers x
and y
, |x| >= |y|
, returns x - y
addORsub
, takes any two integers x
and y
, returning x + y
I've tried to explain what is happening via comments in the code
// Indefinate length addition
function addAsString(x, y) { // x, y strings
var s = '';
if (y.length > x.length) { // always have x longer
s = x;
x = y;
y = s;
}
s = (parseInt(x.slice(-9),10) + parseInt(y.slice(-9),10)).toString(); // add last 9 digits
x = x.slice(0,-9); // cut off last 9 digits
y = y.slice(0,-9);
if (s.length > 9) { // if >= 10, add in the 1
if (x === '') return s; // special case (e.g. 9+9=18)
x = addAsString(x, '1');
s = s.slice(1);
} else if (x.length) { // if more recursions to go
while (s.length < 9) { // make sure to pad with 0s
s = '0' + s;
}
}
if (y === '') return x + s; // if no more chars then done, return
return addAsString(x, y) + s; // else recurse, next digit
}
// Indefinate length subtraction (x - y, |x| >= |y|)
function subtractAsString(x, y) {
var s;
s = (parseInt('1'+x.slice(-9),10) - parseInt(y.slice(-9),10)).toString(); // subtract last 9 digits
x = x.slice(0,-9); // cut off last 9 digits
y = y.slice(0,-9);
if (s.length === 10 || x === '') { // didn't need to go mod 1000000000
s = s.slice(1);
} else { // went mod 1000000000, inc y
if (y.length) { // only add if makes sense
y = addAsString(y, '1');
} else { // else set
y = '1';
}
if (x.length) {
while (s.length < 9) { // pad s
s = '0' + s;
}
}
}
if (y === '') { // finished
s = (x + s).replace(/^0+/,''); // dont return all 0s
return s;
}
return subtractAsString(x, y) + s;
}
// Indefinate length addition or subtraction (via above)
function addORsub(x, y) {
var s = '';
x = x.replace(/^(-)?0+/,'$1').replace(/^-?$/,'0'); // -000001 = -1
y = y.replace(/^(-)?0+/,'$1').replace(/^-?$/,'0'); // -000000 = 0
if (x[0] === '-') { // x negative
if (y[0] === '-') { // if y negative too
return '-' + addAsString(x.slice(1), y.slice(1)); // return -(|x|+|y|)
}
return addORsub(y, x); // else swap
}
if (y[0] === '-') { // x positive, y negative
s = y.slice(1);
if (s.length < x.length || (s.length === x.length && s < x)) return subtractAsString(x, s) || '0'; // if |x|>|y|, return x-y
if (s === x) return '0'; // equal then 0
s = subtractAsString(s, x); // else |x|<|y|
s = (s && '-' + s) || '0';
return s; // return -(|y|-x)
}
return addAsString(x, y); // x, y positive, return x+y
}
Example usage (fiddle)
var i = addORsub('291270990346989568', '1'); // add
i === '291270990346989569';
i = addORsub('291270990346989568', '-1'); // subtract
i === '291270990346989567';