0

Given two numbers in string format (eg. '10.23' and '25.69') how can I get their sum without converting the string into numbers? (eg '35.92') I do not want to convert the strings into numbers using things like parseInt, Number, parseFloat etc....

Tom Riddle
  • 11
  • 1
  • 1
    why not? have you tried anything? – Nina Scholz Sep 25 '19 at 21:00
  • What is the reason for not converting? this arithmetic can be done without modifying your input strings, if thats the concern here – Dacre Denny Sep 25 '19 at 21:01
  • this might be what youre looking for https://stackoverflow.com/questions/8976627/how-to-add-two-strings-as-if-they-were-numbers – mph85 Sep 25 '19 at 21:04
  • 1
    I think this is a very good question. Simply because this is very useful for large numbers. You would have to work with parsing out each digit and adding one by one with a carry as you would on paper. –  Sep 25 '19 at 21:27

4 Answers4

0

An old trick is to multiply by 1, as that forces numeric conversion. The * operator doesn't work on strings, so it forces a switch to numbers. It's an old trick though, as I said.

The unary plus operator is a more modern.

var num1 = '20',
    num2 = '30.5';

console.log(num1 * 1 + num2 * 1); // = '50.5'

If you want the output to definitely be a string, you can also:

console.log((num1 * 1 + num2 * 1)+"");
HBlackorby
  • 1,308
  • 1
  • 11
  • 18
  • `typeof (num1 * 1 + num2 * 1)` is `number` – Olian04 Sep 25 '19 at 21:11
  • @Olian04 no kidding. I'm assuming he doesn't want to run through a conversion function, not that the output can't be a number. If he wants the output back as a string, he can: console.log((num1 * 1 + num2 * 1)+""); – HBlackorby Sep 25 '19 at 21:13
  • @Olian04 what's with the downvote? He did not say that the output couldn't be a number, only that he didn't want to use a conversion function. – HBlackorby Sep 25 '19 at 21:18
  • it adds +1 to number if its very large. "9333852702227987" becomes 9333852702227988 after num1*1 – pride Apr 03 '22 at 08:40
0

Disclaimer: I am not recommending you actually do this. However, you could implement your own add method using a pre calculated lookup table and a rough implementation of a "binary" adder (converted into decimal). The code below work for your example, but i leave no guarantee that it will work for any general cases.

const lookupTable = Array(10).fill(0)
  .map((_, i) => Array(10).fill(0)
    .map((_, j) => [`${i},${j}`, i+j+'']))
  .reduce((flatArr, innerArr) => [...flatArr, ...innerArr], [])
  .reduce((lookupTable, [k, v]) => ({...lookupTable, [k]: v}), {})

const addDigits = (a, b) => {
  const sum = lookupTable[`${a},${b}`];
  if (sum.length === 2) return [sum[1], '1'];
  else return [sum, '0'];
}

const strAdd = (a, b) => {
  const add = ([aH, ...aT], [bH, ...bT], carryBit='0') => {
    if (aH === undefined && aH === undefined) return '';
    if (aH === undefined) return add([], bT, carryBit) + bH;
    if (bH === undefined) return add(aT, [], carryBit) + aH;
    if (aH === '.' || bH === '.') return add(aT, bT, carryBit) + '.';
    const [partial_sum, partial_carryBit1] = addDigits(aH, bH);
    const [sum, partial_carryBit2] = addDigits(partial_sum, carryBit);
    const [newCarryBit] = addDigits(partial_carryBit1, partial_carryBit2);
    return add(aT, bT, newCarryBit) + sum;
  }
  const [whole_a, decimal_a] = a.split('.');
  const [whole_b, decimal_b] = b.split('.');
  const wholeMaxLength = Math.max(whole_a.length, whole_b.length)+1;
  const decimalMaxLength = Math.max((decimal_a || '0').length, (decimal_b || '0').length);
  a = whole_a.padStart(wholeMaxLength, '0') + '.' + (decimal_a || '').padEnd(decimalMaxLength, '0');
  b = whole_b.padStart(wholeMaxLength, '0') + '.' + (decimal_b || '').padEnd(decimalMaxLength, '0');
  return add([...a].reverse(), [...b].reverse(), '0')
    .replace(/^0+/, '') // remove leading 0
    .replace(/0+$/, '') // remove trailing 0
    .replace(/\.$/, '') // remove trailing .
}

const calc = (a, b, expected) => {
  const result = strAdd(a, b);
  console.log(result, result === expected);
}

calc('10.23', '25.69', '35.92');
calc('1', '2', '3');
calc('10.3', '2', '12.3');
calc('99999', '1.01', '100000.01');
Olian04
  • 6,480
  • 2
  • 27
  • 54
0

Here's the solution for your problem:

const format_numStr = (num, no_of_digits, digits_Arr) => {
    
    outNum = 0

    no_of_digits-=1
    
    for (digit of num) {
        
        if (digits_Arr.includes(digit)) {

            // power of 10 decreases as digits progress from left to right i.e from 10^(len(num)-1) to 10^0 
            
            // index() Method returns the exact number or digit we pass in type integer

            outNum+=(digits_Arr.indexOf(digit)*10**(no_of_digits))

            no_of_digits-=1
        }
    };

    return outNum
}


const numStr_Sum = (numStr_Arr) => {

    digits_Arr = Array.from(new Array(10), (_, i) => String(i)) //array contains digits from [0-9]

    num_Arr=[]  // Initialise an array to store the given str number as type integer

    numStr_Arr.forEach(num => {

        no_of_digits = num.length

        if (num.includes('.')) {

            decimal_val = num.split('.')[1].length      // Gives the Decimal point (.) position value
            
            //Since period(.) exists in the num, no_of_digits should be decreased by 1 
            float_num = format_numStr(num, no_of_digits-1,digits_Arr)/10**decimal_val

            num_Arr.push(float_num)
        
        }
        else {
            num_Arr.push(format_numStr(num, no_of_digits, digits_Arr))
        }
    
    });

    total_sum = num_Arr.reduce((a,b)=>a+b,0)

    if (Number.isInteger(total_sum)) {
        return total_sum
        
    }
    else {
        return total_sum.toFixed(decimal_val)
    }

}


console.log(numStr_Sum(['22.22','22.22']))
-1

You can use the unary plus operator (+), but in the background it is converting the string into numbers anyway.

Example: +string1 + +string2