简体   繁体   中英

How come it doesn't slice a number until the end despite including the number's length

I made a code to extract every odd numbers from one number, and it works for numbers that are not too long such as "1341" (which give me the numbers "1,13,1341,341,41,1") but oddly doesn't work for very long numbers.

function solve(s) {
    var newarray = [];
    for (var i = 0; i <= s.length; i++) {
        for (var j = 0; j <= s.length; j++) {
            var slicing = s.slice(i, j);
            if (slicing % 2 !== 0) {
                newarray.push(slicing);
            }
        }
    }
    return newarray.length;
}

Despite putting s.length, it slices until a certain point. For example:

With "93711892377292643581488317", it slices until "9371189237729", then when it starts from 3 it slices until "93711892377292643" (until the next odd number)

With "65266112954758467", from the start it slices until "6526611295475", then when it starts from 5, it slices until "65266112954758467" (until the next odd number).

What's going on?

slicing % 2 doesn't work properly when slicing is large. Javascript treats large numbers as floating-point numbers, which means it's not accurate to know the value to the nearest integer - in binary, the units bit becomes 0, so it's a multiple of 2.

You want to count all odd numeric substrings within a numeric string.

First, consult the documentation of str.slice(beginIndex[, endIndex]) .

Then, in order to gain a better understanding of your code, it is helpful to slowly iterate through a few steps of your loops and write down the expected vs. the observed output.

I recommend to use the debugger built into all modern browsers:

  1. Add a debugger; statement into the inner for-loop:

     function solve(s) { var newarray = []; for (var i = 0; i <= s.length; i++) { for (var j = 0; j <= s.length; j++) { var slicing = s.slice(i, j); debugger; // <-- we want to break here and check our values if (slicing % 2 !== 0) { newarray.push(slicing); } } } return newarray.length; } 
  2. Press [F12] and run this code in your browser's console for some exemplary input.

  3. The debugger tab should now pop up. Press [F8] to step through your code and keep track of the value of your slicing variable.

You will probably notice that slicing is empty at the beginning. You should start your inner loop from j = i + 1 to fix that.

Also, you might notice that your i iterates one time too many, so that slicing is empty during the final iterations of the inner for-loop. You need to terminate your outer loop one step earlier.

Then, for the problematic input "93711892377292643581488317" you will notice that large numeric slices such as "93711892377292643" will not be recognized as odd. "93711892377292643" % 2 evaluates to 0 instead of 1 . In order to understand this, you need to know that JavaScript numbers are internally represented as limited precision floating point values. If you put 93711892377292643 into your browser console, it will evaluate to 93711892377292640 - an even number! JavaScript can only handle integer numbers up to Number.MAX_SAFE_INTEGER == 9007199254740991 without introducing such truncation errors.

Now, how to solve this issue? Well, a number is odd if and only if the last digit is odd. So we don't have to inspect the full number, just the last digit:

 function solve(s) { var newarray = []; for (var i = 0; i < s.length; i++) { for (var j = i; j < s.length; j++) { var digit = s.slice(j, j + 1); if (digit % 2 !== 0) { var slicing = s.slice(i, j + 1); newarray.push(slicing); } } } return newarray.length; } console.log(solve("1234567890")); // 25 

Once you have sufficient understanding of this code, you could start improving it. You could for example replace the newarray with a simple counter, as you are only interested in the number of off digits, not the digits themselves.

A faster solution could be written down as follows:

 function solve(str) { let count = 0; for (let i = 0; i < str.length; i++) { if (str[i] % 2) count += i + 1; } return count; } console.log(solve("1234567890")); // 25 

Or, written in a more declarative way:

 const solve = (str) => str.split('').reduce((count, chr, i) => chr % 2 ? count + i + 1 : count, 0); console.log(solve("1234567890")); // 25 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM