Why is for-loop sometimes skipping some iterations? - javascript

In the function below, the for loop sometimes skips one iteration.
In some rare cases, I've also found it skipping two iterations.
This sometimes breaks my code and would probably affect my future codes, if my understanding of the for loop remains incomplete.
I further looked into the matter and tried the same with a while loop and found out that this problem doesn't happens if a while loop is used.
Why is the for-loop sometimes skipping some iterations ?
function forLoopString(len)
{
var string = 'abcdefghijklmnopqrstuvwxyz0123456789';
var character = '',
randomString = '';
for (var i = 0; i < len; i++)
{
character = string.charAt(Math.floor(Math.random() * string.length-1) + 0);
randomString += character;
}
if(randomString.length < len)
{
console.log('Less than required length!');
randomString = randomString + '5';
}
return randomString;
}
JSFiddle

The loop shown won't "skip" any iterations, but will iterate from [0, len) as told to do.
However, a negative argument to charAt makes it seem like it "skips" because "foo".charAt(-1) == "". The same empty-string result holds for any out-of-bounds to String.charAt:
.. If the index you supply [to charAt] is out of range, JavaScript returns an empty string.
A correction that yields an always-valid index would merely be Math.floor(Math.random() * string.length), without the -1.
Although this is slightly biased (for anyone that really cares) this is 'correct' because Math.random returns a number in the range [0, 1). Thus Math.random() * len returns a value from [0, len); and as an Integer in the same interval after the floor.
Also, it would be good to choose more useful variable names.. and, as Ed points out the +0 is irrelevant because Math.floor returns a (integer) number.

The random number is sometimes negative, that's why a character is skipper from randomString in those cases.
https://jsfiddle.net/ojbp0evz/3/
Use Math.abs for example.

Your problem is HERE:
character = string.charAt(Math.floor(Math.random() * string.length-1) + 0);
if your rand is less than 0, you will get a negative number, and therefor, you won't get any character. You must encapsulate your string.length-1 like so:
character = string.charAt(Math.floor(Math.random() * (string.length-1)));
Updated fiddle: DEMO
Always remember: MULTIPLICATIONS GOES FIRST!!
EDIT: string.length is 36, you dont need to substract 1 to it, just multiply
character = string.charAt(Math.floor(Math.random() * string.length));

Related

Extending a Variable's Length With Random Numbers Doesn't Work

I am making an AI that tries to solve a user-inputted "numberle" in JavaScript. I don't want the user to do extra work just to see an AI do it's thing, so on the input field, if the user inputs a number that has less than 5 digits, the JavaScript should add random numbers at the end of the variable, until it has a total of five digits.
I used all the loops I had experience with, under an if statement, so if the length of the input was less than 5 (like 3), the loop will add 5 - the number of digits of the input (2) digits that are random, using the Math.random attribute.
Here is the code I currently have:
if (input.length < 5)
do {
input = (input * 10) + Math.floor(Math.random() * 9) + 1;
} while (input.length < 5);
}
console.log(input)
I have also used the for and while loops with basically the same condition (obviously modified for the if loop; made a variable for input.length so that it has the same value).
Here is what I get in the console:
5 // Inputted number (1 digit)
52 // Inputted digit + random number
As you can see, the loop only runs once, although it should've ran 3 more times. I am using strict mode also. My code editor is github.dev, and I am using the CodeSwing console.
If input is a number, it will not have "length", since it is not a string.
You can achieve the desired result like this:
let input = 5;
let digits = 2;
while (input < 10**(digits-1)) input = ~~((input+Math.random())*10);
console.log(input);
Note that ~~ is a compact way of doing Math.floor()
Alternatively, without a while loop:
let input = 5, digits = 2, M = Math; L = x=>~~(M.log(x)/M.log(10))+1;
input = ~~((input+M.random())*10**(digits - L(input)));
console.log(input);

Decode a byte array to a signed integer up to 64 bit

I know that JavaScript can't precisely represent all 64 bit integer numbers. But it can precisely represent numbers larger than 32 bit. And that's what I need. With whatever precision JavaScript can give me.
I have a byte array of known length. It has 1, 2, 4, 8 or 16 bytes. And it can contain a signed or unsigned integer, I know which it is. The data is big-endian (network byte order).
How can I get the number value from that byte array?
There are simple solitions that completely fail on negative numbers. There's DataView that isn't of any help with more than 32 bits. I'm interested in a nice and simple and preferable efficient pure JavaScript solution to handle this. There doesn't seem to be any solution for this in the part of the web that's visible to me.
In case somebody wants to see wrong code, here is my version of positive numbers:
function readInt(array) {
var value = 0;
for (var i = array.length - 1; i >= 0; i--) {
value = (value * 256) + array[i];
}
return value;
}
This page explains a good and simple solution:
Add up all bits from the right end, up to the second most significant bit.
The most significant bit is not added as 2^i but as -2^i.
My code works in a larger scope that has an array and a pos to read from.
function readInt(size) {
var value = 0;
var first = true;
while (size--) {
if (first) {
let byte = array[pos++];
value += byte & 0x7f;
if (byte & 0x80) {
value -= 0x80; // Treat most-significant bit as -2^i instead of 2^i
}
first = false;
}
else {
value *= 256;
value += array[pos++];
}
}
return value;
}
The raw bytes are provided in array (a Uint8Array) and pos is the next index to read. This function starts to read at the current pos and advances pos as it reads one of the size bytes.

JavaScript random number one/zero implementation

Hi I found this piece of JS code which generates zero or one: I don't understand how the pipe (ORing) is involved here?
var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1​
I found another way
Math.floor(Math.random()*2)
which accomplishes the same goal. Which one is preferred?
"I don't understand how the pipe (ORing) is involved here?"
The pipe is the bitwise OR operator, and is just used here as a short way to get rid of the fractional part of the random number.
So the random number generates something from 0 to 1.9999999999, and dropping the decimal gives you 0 or 1.
"Which one is preferred?"
I'd say clarity if preferred in your general code, so Math.floor().
You could also do this:
var randomNum = Math.random() < 0.5 ? 0 : 1;
You could use Math.round(Math.random()), which makes rounding and returns zero and one only. It is equally distributed.
var i = 1e7,
count = [0, 0];
while (i--) {
count[Math.round(Math.random())]++;
}
console.log(count);

How to increment a numeric string by +1 with Javascript/jQuery

I have the following variable:
pageID = 7
I'd like to increment this number on a link:
$('#arrowRight').attr('href', 'page.html?='+pageID);
So this outputs 7, I'd like to append the link to say 8. But if I add +1:
$('#arrowRight').attr('href', 'page.html?='+pageID+1);
I get the following output: 1.html?=71 instead of 8.
How can I increment this number to be pageID+1?
Try this:
parseInt(pageID, 10) + 1
Accordint to your code:
$('#arrowRight').attr('href', 'page.html?='+ (parseInt(pageID, 10) + 1));
+ happens to be valid operator for both strings and numbers that gives different results when both arguments are numeric and when at least one is not. One of possible workarounds is to use operator that only have numeric context but gives same mathematical result, like -. some_var - -1 will always be same as adding 1 to some_var's numeric value, no matter if it is string or not.
$('#arrowRight').attr('href', 'page.html?='+ (pageID - -1));
All these solutions assume that your number you want to add 1 to is within the machine precision for an integer. So if you have a large enough number within that string when you add 1 to it won't change the number.
For Example:
parseInt('800000000000000000', 10) + 1 = 800000000000000000
So I wrote a quick solution to the problem
function addOne(s) {
let newNumber = '';
let continueAdding = true;
for (let i = s.length - 1; i>= 0; i--) {
if (continueAdding) {
let num = parseInt(s[i], 10) + 1;
if (num < 10) {
newNumber += num;
continueAdding = false;
} else {
newNumber += '0';
}
} else {
newNumber +=s[i];
}
}
return newNumber.split("").reverse().join("");
}
Now, using the same example above
addOne('800000000000000000') + 1 = '800000000000000001'
Note that it must stay as a string or you will lose that 1 at the end.
It needs to be a integer, not a string. Try this:
pageID = parseInt(pageID)+1;
Then you can do
$('#arrowRight').attr('href', 'page.html?='+pageID);
Simply, $('#arrowRight').attr('href', 'page.html?='+(pageID+1));
The parentheses makes the calculation done first before string concatenation.
let pageId = '7'
pageId++
console.log(pageId)
Nowadays, you just need to pageID++.
Just change your order of operations by wrapping your addition in parentheses; if pageID is already a number, parseInt() isn't necessary:
$('#arrowRight').attr('href', 'page.html?='+(pageID+1));
Demo
As long as your pageID is numeric, this should be sufficient:
$('#arrowRight').attr('href', 'page.html?='+(pageID+1));
The problem you were seeing is that JavaScript normally executes in left-to-right order, so the string on the left causes the + to be seen as a concatenator, so it adds the 7 to the string, and then adds 1 to the string including 7.

jQuery: why is an integer being added to a variable like a string?

So I'm trying to take the variable that increments in a for statement, and add an integer to it... but for some reason, it's adding the integer as though it were a string; other operations like subtraction or multiplication work as expected.
Why is this happening? Edit: I've added the whole function; the problem in question is where I try to add 2 to the variable x.
What confuses me is that I'm able to use x no problem, in an .eq() object for example...
$(function() {
$('textarea').bind('paste', function (e){
inputGroup = $(this).parent();
var ob = $(this);
if (e.type == 'paste'){
setTimeout(function(){
var data = ob.val();
var tabbed = data.replace(/\n/g, "\t");
var cells = tabbed.split("\t");
for(var x in cells) {
foo = x + 2;
alert(foo);
$(inputGroup).find('input').eq(x).val(cells[x]);
}
}, 1);
}
});
});
Why is this happening?
Because x is a string that just looks like a number. Cast to Number first and you'll get the result you expect:
"1" + 2 = "12"
Number("1") + 2 = 3
EDIT : Now that I see you are using split to turn a string into an array, your problem is definitely that you are concatenating strings. Cast to Number first, and your problem is solved.
Yes other arithmetic operations will work, since they will implicitly cast the operands to Numbers. Confusingly, "2" * 3 will in fact evaluate to the integer 6. Welcome to Javascript.
-tjw
Without more code, specifically the initialization of cells, I can't tell you the exact reason. But you can simply call parseInt() on x to turn it into an integer for addition
for(var x in cells) {
foo = parseInt(x, 10) + 2;
$(inputGroup).find('input').eq(foo).val(cells[x]);
}
Because + is a String concatenation but there is no equivalent String method for * or / so when using those it cast the value as a Number. Just cast x as an integer:
for(var x in cells) {
foo = parseInt(x, 10) + 2;
$(inputGroup).find('input').eq(foo).val(cells[x]);
}
The 10 in parseInt is saying to use a base 10 number system (as opposed to hex 16, e.g.).
As others have mentioned, x is a string. That's why.
There's a nice trick for casting strings as numbers in JavaScript that hasn't been mentioned though:
for(var x in cells) {
// Without the "var" here, you're setting a global
// variable during each loop iteration.
var foo = +x + 2;
$(inputGroup).find('input').eq(foo).val(cells[x]);
}

Categories

Resources