I have a answer to another guy question here How to count string occurrence in string?
So I was playing with algorithms here, and after benchmarking some functions I was wondering why a backwards loop was significantly slower than forward.
Benchmark test here
NOTE: This code below does not work as supposed to be, there are
others that work (thats not the point of this question), be aware
before Copying>Pasting it
Forward
function occurrences(string, substring) {
var n = 0;
var c = 0;
var l = substring.length;
for (var i = 0, len = string.length; i < len; i++) {
if (string.charAt(i) == substring.charAt(c)) {
c++;
} else {
c = 0;
}
if (c == l) {
c = 0;
n++;
}
}
return n;
}
Backwards
function occurrences(string, substring) {
var n = 0;
var l = substring.length - 1;
var c = l;
for (i = string.length; i > 1; i--) {
if (string.charAt(i) == substring.charAt(c)) {
c--;
} else {
c = l;
}
if (c < 0) {
c = l;
n++;
}
}
return n;
}
I think the backwards test has a bug:
for (i = string.length; i > 1; i--) {
should be
for (i = string.length - 1; i >= 0; i--) {
When i is string.length, string.charAt(i) is undefined. Do this several thousand times, and it could yield a substantial difference.
Here's a modified test that seems to yield much closer to identical performances.
I found the bottle-neck myself.
when I did this
for (i = string.length; i > 1; i--) {
I accidentaly deleted the "var" from var i, so I've made i global.
After fixing it I got the expected results.
for (var i = string.length; i > 1; i--) {
I never though that this may be a HUGE difference, so pay attention guys.
Fixed Benckmark test here
Before:
After:
PS: for practical use, do NOT use this functions, the indexOf version is much faster.
What data are you testing with. If your data has lots of matching prefixes but not many false matches the other way round , that might affect it.
also wont that search bug on cases like "aaabbaaa" try to find "aab" it will match aa, then fail , then continue from third a and fail. ?
Because they are not complete mirrored functions, add console.log()s inside all ifs and elses of both functions and compare the results, you will see that the tests aren't fair.
You did something wrong. I suggest to ensure that they both work as expected before even start the testings.
Related
I am trying to understand what this mean?
What I am thinking is that phrase will pass a part of array, so this in this case eve to phrase.palindrome method. That method will take and run it through. First var len takes eve and remove 1 from it using length -1. This results in var len being assigned number two as the length of eve is 3. Now for is in use, so var i = 0; i <= len/2; i++.
now becomes var i = 1;1 <= 1; i++."is this correct"
I don't understand what going on here:
for (var i = 0; i <= len/2; i++) {
if (this.charAt(i) !== this.charAt(len-i)) {
return false;
Here is all of the the code:
String.prototype.palindrome = function() {
var len = this.length-1;
for (var i = 0; i <= len/2; i++) {
if (this.charAt(i) !== this.charAt(len-i)) {
return false;
}
}
return true;
};
var phrases = ["eve", "kayak", "mom", "wow", "Not a palindrome"];
for (var i = 0; i < phrases.length; i++) {
var phrase = phrases[i];
if (phrase.palindrome()) {
console.log("'" + phrase + "' is a palindrome");
} else {
console.log("'" + phrase + "' is NOT a palindrome");
}
}
The code is essentially iterating through the string from both directions, comparing the first and last characters (indexes 0 and len) then the second from first and second from last and so forth until you reach the middle. A word is a palindrome if and only if the first and last characters are the same and the second and second to last characters are the same and so forth.
Note, there is something very wrong with this code. While it is technically possible to mutate the prototypes of built-in types in Javascript you should never, ever, ever do it. You gain no functionality you wouldn't from a normal function, while badly violating the principle of least surprise. Treat all types from other libraries, including built ins as if they are closed for modification and open for extension.
I think this line has error:
for (var i = 0; i <= len/2; i++) {
Beacuse somethimes length can be 3,5,7... and that can be problem.
I added some using examples:
for (var i = 0; i <= Math.floor(len / 2); i++) {
// That same thing with floor in positive numbers, but in negative numbers that works like ceil.
for (var i = 0; i <= ~~(len / 2); i++) {
// That same thing with floor, we can think like this pollyfill of floor.
for (var i = 0; i <= ~~(len / 2) + (Math.abs(len)>len?-1:0); i++) {
It is supposed to print prime n numbers. The for loop will run from 2 to x which will iterate each time. if i == x then it means that the number was not divisible and so it should be printed as prime
var n;
var x = 2;
var i;
function prime(n) {
while (n) {
for (i = 2; i < x; i++) {
if (x % i == 0) {
break;
}
if (i == x) {
document.write(i + " ");
n--;
}
x++;
}
}
}
prime(10);
When you try to execute this code, this will never get into the for loop and goes into an infinite while loop. You have got:
i = 2; i < x;
The i will never be less than x. And it doesn't enter the for loop and comes out. And n will always be 10, that goes on into an infinite loop.
You need to use the modulus operator to check if a number is divisible by them.
Maybe change your approach a bit and try to find the first X prime number using just for loops.
var n;
var x = 2;
var i;
function prime(n) {
if (n <= 0) return;
var i, j, p_no = 0, res = [];
for (i = 2; ; i++) {
var ifPrime = true;
for (j = 2; ifPrime && j <= Math.sqrt(i); j++) {
if (i % j === 0) ifPrime = false;
}
if (ifPrime) {
res.push(i);
console.log(i + ' ');
p_no++;
if (p_no === n) return res.toString();
}
}
}
document.getElementById('prime').innerHTML = prime(10);
<p id="prime"></p>
What's happening when the code runs is what Praveen describes. I want to address how you got to your algorithm in the first place.
It looks like you're trying to print all primes less than a specific number n. You've jumbled different aspects of your algorithm together. Specifically, you've combined a loop that exists to find whether a number is prime with a loop over all numbers less than n.
The first thing you can do to help manage this complexity is to use methods. If you had a method isPrime(k) that returns true or false if a given number is prime, then your function's main loop looks much simpler, and separates the two problems from each other:
function prime(n) {
for (var i = n; i > 1; i--) {
if (isPrime(i)) {
document.write(i + " ");
}
}
}
Then you can focus on defining the isPrime method separately, without getting its parts confused with the main loop:
function isPrime(k) {
for (var i = 2; i < k; i++) {
if (k % i == 0) {
return false;
}
}
return true;
}
Methods are a fantastic way of keeping algorithms simpler by isolating their components. They're building blocks one can use to make more complex systems without having to keep track of the whole. It lets you make smaller changes, each encapsulated from other concerns, meaning you have less to keep in your mind while you're making those changes. The less you have to keep in your mind, the easier it is to spot mistakes.
I am trying to write a function which should calculate all prime numbers up to an input parameter and return it. I am doing this for practice.
I wrote this function in a few ways but I was trying to find new ways to do this for more practice and better performance. The last thing I tried was the code below:
function primes(num){
let s = []; // sieve
for(let i = 2; i <= num; i++){
s.push(i);
}
for(let i = 0; i < s.length; i++) {
for(let j = s[i]*s[i]; j <= num;) {
//console.log(j);
if(s.indexOf(j)!= -1){
s.splice(s.indexOf(j), 1, 0);
}
j+=s[i];
}
}
s = s.filter(a => a != 0);
return s;
}
console.log(primes(10));
The problem is that when I run this in a browser it keeps calculating and won't stop and I don't know why.
Note: when I comment out the splice and uncomment console.log(j); everything works as expected and logs are the things they should be but with splice, the browser keep calculating and won't stop.
I am using the latest version of Chrome but I don't think that can have anything to do with the problem.
Your problem lies in this line:
s.splice(s.indexOf(j), 1, 0);
Splice function third argument contains elements to be added in place of the removed elements. Which means that instead of removing elements, you are swapping their values with 0's, which then freezes your j-loop.
To fix it, simply omit third parameter.
function primes(num){
let s = []; // sieve
for(let i = 2; i <= num; i++){
s.push(i);
}
for(let i = 0; i < s.length; i++) {
for(let j = s[i]*s[i]; j <= num;) {
//console.log(j);
if(s.indexOf(j)!= -1){
s.splice(s.indexOf(j), 1);
}
j+=s[i];
}
}
return s;
}
console.log(primes(10));
Your problem is in this loop:
for(let j = s[i]*s[i]; j <= num;)
This for loop is looping forever because j is always less than or equal to num in whatever case you're testing. It is very difficult to determine exactly when this code will start looping infinitely because you are modifying the list as you loop.
In effect though, the splice command will be called setting some portion of the indexes in s to 0 which means that j+=s[i] will no longer get you out of the loop.
So, I have seen this piece of code at alot of places:
for (var i = 0, len = myArray.length; i < len; i++) {
}
I am aware that is the length caching of the array.
Today I saw this:
var len = myArray.length;
var i = 0;
while(i++ < len)
Efficiency wise, both would be the same, right? Any input would be appreciated.
If you have a "normal" loop, you can also change i < len to i !== len. This makes the loop a lot faster, because the the check for inequality is very fast. The caching of the variable is not so important, but it do no harm.
So a fast loop in javascript can written as follows:
for (var i = 0, len = myArray.length; i !== len; i++) {
}
UPDATE
I made some performance tests a while ago and this was what I found out. But nowadays the browsers don't show the same behaviour, furthermore it's the opposite (< is faster than !==) . Here is a test I made just now: http://jsperf.com/loop-inequality-check
So forget about the posting above ;)
Setup a jsperf test case here:
http://jsperf.com/javascript-array-length
for (i = 0; i < arr.length; i++) {
//nothing
}
var arrlength = arr.length;
for (i = 0; i < arrlength; i++) {
//nothing
}
var arrlength = arr.length,
i = 0;
while (arrlength > i++) {
//nothing
}
var arrlength = arr.length;
while (arrlength--) {
//nothing
}
If the test cases can be improved upon, please let me know in the comments. With a small number of tests, it seems IE11 is better optimized for the while cases, while Chrome 31 appears to prefer the second for loop (which is fairly similar to the while cases).
Just wondering what is the difference in the following 2 methods?
var a = 0;
var b = 0;
var c = 0;
for(var i = 0; i < 6; i++ ){
a+=i;
b+=i;
c+=i;
}
and
var a = 0;
var b = 0;
var c = 0;
for(var i = 0; i < 6; i++ ){
a+=i;
}
for(var i = 0; i < 6; i++ ){
b+=i;
}
for(var i = 0; i < 6; i++ ){
c+=i;
}
*edited thanks locrizak for the correction
The second one is doing 3X the amount of iterations it needs to. In the second one there are 18 iterations through the loops while the first there is only 6 making the script run faster. (In these circumstances you will not notice a difference because you are not doing much in the loops but once you want to do more it will be a performance issue)
Ps. a+i isn;'t doing anything you probably want a+=i
When you are in doubt about JavaScript peformance, have an objective opinion:
http://jsperf.com/testing-snippets
Well, you are doing 3 times the work.
In the grand of scheme of things, 18 iterations of what your doing isn't going to have much impact, however comparitively it is much worse.
Without knowing any of the details of the javascript interpreter, assume that the second code block is marginally worse than the first, but definitely not worth refactoring if it makes the code harder to read. Think about it this way:
for(var i = 0; i < 6; i += 1) {
doSomeExpensiveThing(); // takes 500ms to process
doSomeExpensiveThing();
doSomeExpensiveThing();
}
And:
for(var i = 0; i < 6; i += 1) {
doSomeExpensiveThing(); // takes 500ms to process
}
for(var i = 0; i < 6; i += 1) {
doSomeExpensiveThing();
}
for(var i = 0; i < 6; i += 1) {
doSomeExpensiveThing();
}
The two are going to be effectively identical because the overhead of running the loop will disappear compared to the cost of doing the inner computation.
I disagree with locrizak. The second is definitely not doing 3 times the work since each loop has a third of the statements as the first example. The extra work on the second example is that it needs to run the loop iteration steps 2 times as often as the first example.
initalize i (only once)
increment i (every iteration)
check if i < 6; (every iteration)
Therefore, in any real world example where the loop has more statements and the loop overhead gets smaller and smaller, you're very unlikely to notice a difference. That means you shold use multiple loops if it makes the code more readable.
I created this more real-life example to prove my point that both loops are, for most intents and purposes, the same: http://jsperf.com/testing-snippets/3
The only difference is the number of assignments, additions and comparisons on the variable i - and unless you're programming for a 1970s embedded computer (which you're not, as this is JavaScript), the speed difference is effectively zero; do not waste time on trying to nanooptimize it (e.g. the speed of computers makes this a non-issue, and modern JS interpreters may compile it anyway, so the difference is lost altogether).
If you're doing anything meaningful inside those loops, that will be your bottleneck, not the looping itself.
The only significant difference is maintenance - so use whichever form is easier to understand for the next person down the line who will inherit this.
Paste it into the firebug console and time it. Making it work with large loops and you can see the differences easier.
console.time("group");
for(var x = 0; x<1000; x++){
var a = 0;
var b = 0;
var c = 0;
for(var i = 0; i < 6; i++ ){
a+i;
b+i;
c+i;
}
}
console.timeEnd("group");
console.time("sep");
for(var x = 0; x<1000; x++){
var a = 0;
var b = 0;
var c = 0;
for(var i = 0; i < 6; i++ ){
a+i;
}
for(var i = 0; i < 6; i++ ){
b+i;
}
for(var i = 0; i < 6; i++ ){
c+i;
}
}
console.timeEnd("sep");
I get
group: 8ms
sep: 13ms