Recursion in jQuery - Numerology - javascript

I'm trying to get a recursive function to work in jQuery but I'm getting the following exception:
'Uncaught RangeError: Maximum call stack size exceeded'
My understanding is that the recursive function must somehow be running infinitely but I can't work out why that's happening. Thanks...
jQuery.fn.reduceNumber = function(numberToReduce) {
if (numberToReduce < 10 || numberToReduce == 11 || numberToReduce == 22 || numberToReduce == 33){
return numberToReduce;
} else {
var newNumberToReduce = numberToReduce.toString().substring(0,1) + numberToReduce.toString().substring(1,2);
return ($(this).reduceNumber(newNumberToReduce));
}
}
$(document).ready(function(){
$("#foo").html($(this).reduceNumber(12));
});

Because you are stuck in an infinite loop. You are calling reduceNumber(12). Since it does not match the first if() statement, it goes to the second:
var newNumberToReduce = numberToReduce.toString().substring(0,1) + numberToReduce.toString().substring(1,2);
Leading newNumberToReduce to be.... 12! Which then calls reduceNumber(12), which does the same thing again and again and again, until the maximum stack size is exceeded.

When you call reduceNumber the first time and pass 12
It goes to the function
It isn't smaller than 10, or equals to 11 or 22 or 33
So does the else
The newNumberToReduce is the first character of 12 (1) and second character of 12 (2)
So newNumberToReduce is 12
Calls the reduceNumber function again passing in 12 (again)
Therefore infinte loop

change this line:
var newNumberToReduce = numberToReduce.toString().substring(0,1) + numberToReduce.toString().substring(1,2);
to this:
var newNumberToReduce = (numberToReduce.toString().substring(0,1) | 0) + (numberToReduce.toString().substring(1,2) | 0);
that will create a new number combined from your digits (1 + 2 = 3)

Related

Loop logic formatting number

I'm new at javascript and trying to do some loop that will automaticly will format a number (1000 = 1K , 10000 = 10k 100000 = 100k )
formatting to 1K works and then it stops for some reason...
for me this loop makes sense :
loop will cycle once so the condition will be true , this will give me the first 2 integers and a 'K', after that the loop will break
if condition is not true , loop should be continue...
this is probaly not the ideal way to do it , but i wondering why my logic thinking is wrong
thanks advanced and sorry for my bad english.
<body >
<p>Number: <span id="number"></span></p>
<script>
len=1;
thousand=1000;
million =1000000;
num= 10001;
for(thousand;thousand<million;thousand*=10){ //when thousand is less then a million , multiply thousand times 10
if(num>=thousand && num<(thousand*10)){ // should cycle the loop twice so i got num>=10000 && num<100000
document.getElementById("number").innerHTML = num.toString().substring(0,len)+" K";
len+=1; // increase by 1 , so i will get 10 K instead of 1 K
break; // should break now since condition is true after second cycle
}
}
// probaly not the ideal method to do this , i just want to know my problem because this loop makes sense to me....
</script>
</body>
A loop just makes no sense in this case, because you don't have an array type to iterate over.
Additionally generating a range to loop, like you are tyring to do isn't worth, since you could just
n = Math.floor(n / 1000) + 'k';
see chrisz answer for a working 'number to k' filter.
If you really want to loop. Try this:
let n = 3024;
for (let i = 0; i < 1000; i++) {
if (n >= i * 1000 && n < (i + 1) * 1000) {
console.log(i + 'k');
break;
}
}

Javascript: Basic for loop?

I just completed some form of a competency exam for a programming school, and I got every question correct except this, although it appears really quite easy, yet I couldn't get it. Any ideas?
Observe the code below.
var x = [1,5,7,13];
for(i=0; i < x.length; i++)
{
x[i] = x[3-i] + 2;
}
Once the program is done, what would be in x?
a [3,7,9,15]
b [15,9,11,3]
c [15,9,7,3]
d [15,9,11,17]
The answer is d
first loop
x[0] = 13 + 2 = 15
second loop
x[1] = 7 + 2 = 9
third loop
x[2] = 9 + 2 = 11
fourth loop
x[3] = 15 + 2 = 17
x = {15, 9, 11, 17}
To figure this out, you'll have to understand that x[] is used to refer to a specific index of the array. For example:
var x = [5,6,7];
In this case, x[0] would be equal to 5, assuming a 0-index based array.
Knowing this, let's break down your loop. We'll start by filling in the variable name instead of the variable value step by step, to leave out confusion of following variables in your head.
var x = [1,5,7,13];
for(0=0; 0 < x.length; 0++)
{
x[0] = x[3-0] + 2;
}
For the first iteration, everything starts to become a little clearer as you can tell that now it's setting x[0] (the first value in the array) to equal x[3-0] (which would be x[3], which in turn would be 13 due to the 0-index array), plus 2. 13 + 2 = 15. The first number is 15.
var x = [1,5,7,13];
for(1=1; 1 < x.length; 1++)
{
x[1] = x[3-1] + 2;
}
Let's try one more! x[3-1] is the same as x[2] which is 7; 7 + 2 = 9. Your second number is 9.
Following the same logic you can see how the loop functions and understand how it's referencing the array's values.
The key here is that you're updating the same array you're reading from as you go through it. (Note: generally I'd consider this bad practice and I've seen a lot of programmers fall into this trap - it's very easy to misunderstand the code).
First thing to realize is that x[3-i] basically reads the opposite end of the current index. To be more generic, it should really have been x[(x.length-1)-i] but the 3 is hardcoded in this case.
Now, the first round is easy: 13+2 = 15. 13 because the opposite end of the first element is the last element:
x = [15,5,7,13]
▲ │ this+2
└──────┘
In the second round we replace 5 with 7+2 = 9:
x = [15,9,7,13]
▲ │ this+2
└─┘
In the third round we find ourselves doing something not initially obvious. Instead of replacing 7 with 5+2 we replace it with 9+2 instead because we've already replaced 5 with 9:
x = [15,9,11,13]
│ ▲
this+2 └─┘
Now finally we replace the last element with 15+2 using the same reasoning above:
x = [15,9,11,17]
│ ▲
└───────┘
this+2

number incrementing in Angular.js

I'm attempting to build an app that calculates sales metrics. I have run into an unusual problem in my build.
Part of the app allows users to increase/decrease a variable by 5% and then see how that will effect an overall metric. It also allows the user to see the percentage increase/decrease.
I have the functionality working roughly as intended, however if I enter a number lower than 20 into the input and then try in increase it with my incrementing function it only increments once and then stops.
If the number I enter into the input is 20 or greater it increments in the intended way.
Below is my angular code:
function controller ($scope) {
$scope.firstNumber = 0;
$scope.firstPercent = 0;
$scope.increase = function(id) {
var A = parseInt(id);
var B = A * 5/100;
var C = 0;
var C = A + B;
if (id === $scope.firstNumber) {
$scope.firstNumber = C;
$scope.firstPercent = $scope.firstPercent + 5;
}
};
$scope.decrease = function(id) {
var A = parseInt(id);
var B = A * 5/100;
var C = 0;
var C = A - B;
if (id === $scope.firstNumber) {
$scope.firstNumber = C;
$scope.firstPercent = $scope.firstPercent - 5;
}
};
I can't see anything wrong with my maths, my thinking is that perhaps I'm approaching angular in the wrong way. However I'm not sure.
I have put together a fiddle that shows the full code.
jsFiddle
I have updated the fiddle to use parseFloat. Seems like the numbers are incrementing now.
var A = parseFloat(id);
http://jsfiddle.net/kjDx7/1/
The reason why it was working with values above 20 was that it was just reading the part before decimals each time it tried to increase. So 20 became 21 and 22.05 and so on. As long the the value before decimal kept changing, it showed different (but incorrect) answers.
On the other hand, 10 became 10.5 which when parsed yielded 10. As you can see, this cycle continued endlessly.
The reason why you face the issue is because 5% of anything less than or equal to 20 is less than or equal to 1.
When you parseInt() the value, you always end up with the same number again.
Take 15 for example.
5% of 15 = 15.75
After parseInt(), you get the value 15 again.
You use the same value to increment / decrement each time.
Hence for values below 20, you don't get any changes.
As #Akash suggests, use parseFloat() instead - or why even do that when the value that you get is float anyway
I made a fork of your fiddle. I'm not completely sure what you want to achive.
Take a look at this fiddle.
$scope.increase = function() {
$scope.firstPercent = $scope.firstPercent + 5;
var A = $scope.firstNumber;
var B = (A / 100) * $scope.firstPercent;
var C = A + B;
$scope.firstNumberWithPercent = C;
};
update
After posting, i see that question is already answered. But is this what you really want? When you hit increase, it takes 5 % off of the number in the input field. That is ok, but when you hit decrease after that, it takes 5 % off the number in the same field. So your starting point is different.
100 + 5/100 = 105
105 - 5/105 = 99,75

Why is this bang in the If Then Failing Here

The value in div PermanentHiddenDiv3 can be -11, 1, 6, 12, 17, 18 or 29.
However, at the point in the script where this code exists, the value should
only ever be 18. So, I could go with that.
On the other hand, if I could get this to work with other values being
handled as well, it would be better.
var OMGxAlgebra = function(evt){
var AltReality = document.getElementById("Latent29");
var AreYouSAVED;
var SingleEval = document.getElementById("PermanentHiddenDiv3");
var ThinkingIsAntiSocial = SingleEval.textContent;
OhItIS = ThinkingIsAntiSocial*1;
// You can write this ::
// if(OhItIS==18){
// AreYouSAVED="";
// AltReality.textContent=AreYouSAVED;
// }
if(OhItIS==18){
AreYouSAVED="";
AltReality.textContent=AreYouSAVED;
}
};
The code above works, but the next does not. I thought that in JavaScript
this syntax was valid ???
if(!somevar==X){}
if(!OhItIS==29){
AreYouSAVED="";
AltReality.textContent=AreYouSAVED;
}
The code in context : http://jsfiddle.net/MountainMan72/4gySs/ ... just in case
I am missing some external tripwire.
Use
if (OhItIS != 29){
AreYouSAVED="";
AltReality.textContent=AreYouSAVED;
}
The bang goes before the =
!=
I'm pretty sure you want to use OhItIS != 29
Using !OhItIS == 29 converts OhItIs to a boolean value and compares that to 29. Obviously ends in results that you don't want.
Try this in your browser for verification:
var ohitis = 29;
console.log(!ohitis);
This should print out false;
The precedence rules mean that !x==y parses as (!x) == y, not !(x == y). As the other answers said, use x != y to avoid the problem.

Javascript record keystroke timings

I want to record the time between each keystroke (just one key to start with, the 'A' key) in millseconds.
After the user finishes his thing he can submit and check out the timings between each key stroke. Like:
1: 500
2: 300
3: 400
4: 500
5: 100
6: 50
7: 50
8: 25
I believe this is possible with Javascript, is it?
Sure:
var times = [];
// add an object with keycode and timestamp
$(document).keyup(function(evt) {
times.push({"timestamp":evt.timeStamp,
"keycode":evt.which})
});
// call this to get the string
function reportTimes() {
var reportString = "";
for(var i = 0; i < times.length - 1; ++i) {
reportString += (i+1) + ": " + (times[i+1].timestamp - times[i].timestamp) + " ";
}
return reportString; // add this somewhere or alert it
}
I added the keycode just in case you wanted it later; it's not necessary for your exact problem statement.
Clarification from comments discussion:
The for loop only goes to up to times.length - 2 (since i is always strictly less than times.length - 1), so there is no issue about times[i+1] being outside the bounds of the array. For example, if you do five key presses and therefore have a times array with five elements (indexed from 0 to 4):
1st pass: times[1].timestamp - times[0].timestamp
2nd pass: times[2].timestamp - times[1].timestamp
3rd pass: times[3].timestamp - times[2].timestamp
4th pass: times[4].timestamp - times[3].timestamp
Then the loop terminates, because setting i to 4 triggers the termination condition:
= i < times.length - 1
= 4 < 5 - 1
= 4 < 4
= false [i cannot be set to 4 by this loop]
Thus, times[i+1] is always a validly indexed element, because i is at most one less than the maximum index.

Categories

Resources