javascript for loop with decimals - javascript

I'm trying to use this for loop in order to show divs. But I get a strange error from the jQuery lib.
Error: Syntax error, unrecognized expression: =10]
I have read about the problems with javascript decimals, but I still can't understand why this won't work:
for (var i = 10.00; i >= ui.value; i -= 0.25) {
$("data_id=" + Math.floor(i) + "]").show();
}
When hiding the divs, I use this and it works fine:
for (var i = 0.00; i < ui.value; i += 0.25) {
$("[data_id=" + Math.floor(i) + "]").hide();
}

You forgot the [ in the first loop, this will work:
for (var i = 10.00; i >= ui.value; i -= 0.25) {
$("[data_id=" + Math.floor(i) + "]").show();
}
You should transform this into an integer loop, if you are .floor()-ing the numbers, anyway.

You're missing your opening square bracket for the attribute equals selector:
for (var i = 10.00; i >= ui.value; i -= 0.25) {
$("[data_id=" + Math.floor(i) + "]").show();
}
As others have mentioned, however, there is absolutely no reason to be using floats for this, since the call to .floor() essentially means you are calling .show() on each of the divs 4 times unnecessarily:
for (var i = 10; i >= ui.value; i--) {
$("[data_id=" + i + "]").show();
}
This should accomplish exactly you want, in about a quarter of the work.

You are missing a [ in your selector here:
$("data_id=" + Math.floor(i) + "]").show();
Which should be:
$("[data_id=" + Math.floor(i) + "]").show();
You should probably add ' around the value of data_id as well, so the final result should be:
$("[data_id='" + Math.floor(i) + "']").show();

You should never, ever rely on floating point arithmetic for iteration/indexing variables. They may run you into strange situations, and even worse, different processors handle floating points differently. Your example doesn't seem to have any side-effects of floating points, but using floating points is really a bad practice.

Related

How can I prepend characters to a string using loops?

I have an input field that expects a 10 digit number. If the user enters and submits a number less than 10 digits, the function would simply add a "0" until the inputed value is 10 digits in length.
I haven't really used, or understand how recursive functions really work, but I'm basically looking at an efficient way of doing this. One minor issue I'm having is figuring out how to prepend the "0"s at the beginning of the string rather than appended to the end.
My thinking:
function lengthCheck(sQuery) {
for (var i = 0; i < sQuery.length; i++) {
if (sQuery.length !== 10) {
sQuery += "0";
//I'd like to add the 0s to the beggining of the sQuery string.
console.log(sQuery);
lengthCheck(sQuery);
} else return sQuery
}
}
Change:
sQuery += "0"; // added at end of string
to:
sQuery = "0" + sQuery; // added at start of string
To remove the for loop/recursion, you could slice out the desired length in one step:
function padZeros(sQuery) {
// the max amount of zeros you want to lead with
const maxLengthZeros = "0000000000";
// takes the 10 rightmost characters and outputs them in a new string
return (maxLengthZeros + sQuery).slice(-10);
}
Simple generic function using ES6 repeat:
// edge case constraints not implemented for brevity
function padZeros(sQuery = "", maxPadding = 10, outputLength = 10) {
// the max amount of zeros you want to lead with
const maxLengthZeros = "0".repeat(maxPadding);
// returns the "outputLength" rightmost characters
return (maxLengthZeros + sQuery).slice(-outputLength);
}
console.log('padZeros: ' + padZeros("1234567890"));
console.log('padZeros: ' + padZeros("123"));
console.log('padZeros: ' + padZeros(""));
Alternate version that doesn't affect strings over your set limit:
function padZerosIfShort(inputString = "", paddedOutputLength = 10) {
let inputLen = inputString.length;
// only padded if under set length, otherwise returned untouched
return (paddedOutputLength > inputLen)
? "0".repeat(paddedOutputLength - inputLen) + inputString
: inputString;
}
console.log('padZerosIfShort: ' + padZerosIfShort("1234567890", 5));
console.log('padZerosIfShort: ' + padZerosIfShort("123", 5));
console.log('padZerosIfShort: ' + padZerosIfShort("", 5));
It will ultimately depend on your needs how you want to implement this behavior.
The += operator adds things to the end of strings similar to:
sQuery=sQuery+"0"
You can add characters to the front of a string like this
sQuery="0"+sQuery
I also found something interesting here. it works like this:
("00000" + sQuery).slice(-5)
You would add zeros to the front then slice off everything except the last 5. so to get 10 characters you would use:
("0000000000" + n).slice(-10)
You don't need recursion to solve this, just a simple for loop should do the trick. Try this:
function lengthCheck (sQuery) {
for (var i = sQuery.length; i<10; i++) {
sQuery = "0" + sQuery;
}
return sQuery;
}
You're looking to pad the string with zeroes. This is an example I've used before from here and will shorten your code a little bit:
function lengthCheck (sQuery) {
while (sQuery.length < 10)
sQuery = 0 + sQuery;
return sQuery;
}
I believe this has already been answered here (or similar enough to provide you the solution): How to output integers with leading zeros in JavaScript

Regex: How to return matches that are not in the bracket

So I technically already solved this issue, but I was hoping for a better solution using some funky regex.
The issue is:
We got strings this:
2+{2+(2)},
10+(20+2)+2
The goal is to match the 'plus' signs that are not in any sort of bracket.
i.e. in the previous strings it should match
2 + {2+(2)} ,
10 + (20+2) + 2
at the moment what I am doing is matching all plus signs, and then checking to see if the sign has any bracket in front of it (using regex), if it does then get rid of it.
I was hoping for a neater regex solution, is that possible?
To reiterate, I need the location of the strings, at the moment I am using javascript to do this, so ideally a js solution is preferred, but the pattern is really what I am looking for.
You could perhaps just replace everything inside () or {} with spaces:
'10 + (20+2) + 2'.replace(/\([^)]*?\)|\{[^}]*?\}/g, m => ' '.repeat(m.length));
This would result in
10 + + 2
Meaning the position of the strings aren't changed.
Note: It won't work well with nested things of the same type, ex (1 + (1 + 1) + 1), but it works with (1 + { 1 + 1 } + 1).
Bigger solution, using the same logic, but that works with nested stuff
var input = '10 + { 1 + (20 + (1 + { 3 + 3 } + 1) + 2) + 2 }';
var result = [];
var opens = 0;
for (var i = 0; i < input.length; ++i) {
var ch = input[i];
if (/\(|\{/.test(ch)) {
opens++;
result[i] = ' ';
}
else if (/\)|\}/.test(ch)) {
opens--;
result[i] = ' ';
}
else {
if (!opens) result[i] = input[i];
else result[i] = ' ';
}
}
result = result.join('');
// "10 + "

How do I print out a block of repeating numbers in a rectangle shape?

I am trying to repeat an exercise I learned a while ago in C++. It has been a few years since I last built a function like this. I would like to write this in JavaScript.
I am trying to write a program, that in ONE loop, it prints this to the screen/console/document:
11111
22222
33333
44444
55555
The code I have so far isn't working at all, I know I am doing something wrong.
function generate(){
for( var i = 0; i < 5; i++){
console.log( i + i + i + i +i +"<br>");
}
}
It gives me an output of this:
0
5
10
15
20
Can anyone point me in the right direction or help me out? Thank you!
The problem is that the line:
console.log( i + i + i + i +i +"<br>");
sums the values of i instead of concatenating. Starting with an empty string forces concatenation instead of addition:
console.log("" + i + i + i + i +i +"<br>");
I am going to answer my own question. It appears my mind is tired and making dumb mistakes haha.
The answer is:
function generate(){
var i = 1;
while (i < 6){
console.log( i, i, i, i, i + '<br>');
i++;
}
}

Rounding to Significant Figures - Missing Zeros

I'm currently producing a JavaScript driven mathematics package, which focuses on rounding to various significant figures (S.F.) but I've run into a problem that I'm struggling to solve.
More on this problem later, but first some background for you.
The program is designed to select a completely random number within a given range and then automatically work out that number's relevant significant figures; for example:
Random Number: 0.097027 S.Fs: 9, 7, 0, 2, 7
Here is a screenshot of what I have produced to give you a visual representation:
As you can see, once the user has selected their number, they are then given the opportunity to click on four separate 'SF' buttons to view their random number presented to 1, 2, 3 and 4 S.Fs respectively.
For each S.F (1-4) the random number is rounded down, rounded up and rounded off to X SF and a scale below gives the user a more visual presentation to show why the SF value has been chosen by the program.
I've already written the vast majority of the code for this and tested it and so far the numbers are coming out how I'm expecting them to. Well nearly...
In the example I've given (0.097027); as you can see on the image I've included, the data for 4 S.F is absolutely correct and outputted accurately.
When I click on to the 3 SF button, I'd expect to see the following:
Random Number: 0.097027 3 S.F Rounded Up/Down/Off: 0.0970
However, what I'm actually getting is:
Random Number: 0.097027 3 S.F Rounded Up/Down/Off: 0.097
The program hasn't displayed the additional zero. This is a perfect example of a number in my program ending in a zero and in this case the zero is really significant and must be displayed.
The data is usually correct but there appears to be an issue with outputting significant zeros at the right time. I've researched the toFixed(x) method and if I assign toFixed(4) I get the correct required output, but because my numbers are generated randomly each time, they can range from a length of 5 figures, e.g. 89.404 up to > 10, e.g. `0.000020615.
So it looks like the toFixed method needs to be flexible/dynamic, e.g. toFixed(n) with a function run beforehand to determine exactly how many trailing zeros are needed?
Here are some key excerpts from my current solution for your consideration:
function generateNum() {
do {
genNumber = Math.random() * Math.pow (10, randomRange(-5, 5));
//Round
genNumber = roundToNSF(genNumber, 5, 0);
// This number must contain >1 digit which is 1 to 9 inclusive otherwise we may have e.g. 100. Rounding 100
}
while (!countNonZero(genNumber) || genNumber < 1E-05 || genNumber == 0);
//Round
genNumber = roundToNSF(genNumber, 5, 0);
genNumber = String(genNumber);
genNumber = Number(genNumber);
}
//----------------------------------------------------------------------------
function randomRange(min, max) {
/**
* Returns a random integer between min (inclusive) and max (inclusive)
* Using Math.round() will give you a non-uniform distribution!
*/
return Math.floor(Math.random() * (max - min + 1)) + min;
}
//---------------------------------------------------------------------------
//Click SF3 Button to reveal the data
function showSF3() {
//Remove any CSS properties on the buttons from previous use
removeButtonCSS();
document.getElementById('SFRounded').style.display = "block";
document.getElementById('scale').style.display = "block";
document.getElementById("SF3").className = document.getElementById("SF3").className + "buttonClick"; // this removes the blue border class
//Clear text
deleteRounded();
deleteScale();
//Run calculation
calculateAnswer();
//alert(genNumber.toFixed(4));
for (i = 3; i < 4; i++)
{
//Add The new data
sfRoundedTextBlock = document.getElementById('SFRounded');
//alert(downArray[i].toFixed(4));
//Data output to HTML.
sfRoundedTextBlock.innerHTML = sfRoundedTextBlock.innerHTML + '<p><strong>Number: </strong></br>' + String(genNumber) +
'</br>' + '<strong>Rounded down to ' + i + ' SF:</br></strong>' + downArray[i] + '</br>' +
'<strong>Rounded up to ' + i + ' SF:</br></strong>' + upArray[i] + '</br><strong>Rounded off to ' + i + ' SF:</br></strong>'
+ roundedArray[i] + '</br>' + '(See the scale below for why we choose <strong>' + roundedArray[i] + '</strong> as the rounded off value.)</p>';
}
}
//----------------------------------------------------------------------
var roundedArray = [];
var upArray = [];
var downArray = [];
var temp;
function calculateAnswer() {
//Clear Arrays
roundedArray = [];
upArray = [];
downArray = [];
// Work out the answer:
for (i = 0; i < 4; i++) {
var nSF = i + 1;
// Round OFF ...
temp = roundToNSF(genNumber, nSF, 0);
// We actually have to do this twice ...
roundedArray[nSF] = roundToNSF(temp, nSF, 0);
// Round UP ...
upArray[nSF] = roundToNSF(genNumber, nSF, 1);
// Round DOWN ...
downArray[nSF] = roundToNSF(genNumber, nSF, -1);
// e.g. x = 0.0098 rounded to 1SF is 0.010 initially (take the log of 0.0098 and try it!).
};
};
//-------------------------------------------------------------------------
//Globals
var aNumber;
var digits;
var way;
function roundToNSF(aNumber, digits, way){
// Round a number to n significant figures (can use roundToNDP provided we know how many decimal places):
if (way == undefined) { way = 0; }; // default is round off
if (aNumber !=0) {
if (aNumber > 0)
{
z = log10(aNumber);
}
else
{
z = log10(-aNumber);
};
z = Math.floor(z);
var nDP = digits - z - 1; // Rounding to nDP decimal places is equivalent to rounding to digits significant figures ...
var roundedNumber = roundToNDP(aNumber, nDP, way);
}
else {
roundedNumber = aNumber; // Number is zero ...
};
return Number(roundedNumber);
};
//---------------------------------------------------------------------------------
Update:
I'm still continuing to try and find a solution for this problem and an approach I have recently taken is to convert my randomly generated number into a searchable string variable and then use the indexOf(".") command to find the position of the decimal point (dp).
Then I've searched through my number, starting from the position of the dp to find the first instance of a significant, non-zero number [1-9].
var genNumber = 0.097027;
var rString = String(genNumber);
var positionofDP = rString.indexOf(".");
var regexp = /[1-9]/;
var positionofNonZero = Number(rString.search(regexp, positionofDP)); // Output would be '5'
I have then been able to target my search further, to determine whether my first significant number has any 'problematic' zeros in the immediate digits after it.
If there are any, then I set a Boolean variable to 'true' and then in a separate function create further text strings of my rounded off/down/up numbers, so I can then physically choose to add a '0' on to the end of the existing numerical characters.
This approach does work for me in isolated cases, but with my random number length ranging from 5-12 digits long, it still isn't dealing with all scenarios.
Maybe I need to create a dynamic toFixed(i) function? Any ideas would be greatly welcomed.
Instead of playing with the fixed points on an Int, you could manage the string directly.
Here's a link to a little fiddle: http://jsfiddle.net/5rw5G/4/
This not intended to completely/accurately solve your problem, but might help you see another solution.
function getRoundedSFs(num, SFCount) {
// Match every "leading zeros" before and after the .
var matches = num.toString().match(/^-?(0+)\.(0*)/);
// starting with "0."
if (matches) {
var firstIndex = matches[0].length;
var prefix = matches[0];
sf = Number(num.toString().substring(firstIndex, firstIndex + SFCount + 1));
sf = Math.round(sf / 10);
sf = prefix + sf.toString();
return Number(sf).toFixed(matches[2].length+SFCount);
}
// starting with something else like -5.574487436097115
else {
matches = num.toString().match(/^(-?(\d+))\.(\d+)/);
var decimalShift = SFCount - matches[2].length;
var rounded = Math.round(num * Math.pow(10, decimalShift));
rounded /= Math.pow(10, decimalShift);
return rounded.toFixed(decimalShift);
}
}
I've gone away again and I think I have now finally managed solve my initial problem.
There was a degree of confusion on my part surrounding when to use toFixed and toPrecision. I had previously attempted to convert my rounded up, down and off numbers into strings and then subsequently search through each of these to find the decimal point (".") and then work out the amount of trailing numbers, in order to then generate the correct toFixed point.
However, this was very hit and miss, given that my random number could be up to 12 digits, so what I've now done is to properly utilise toPrecision instead. For each 'SF button' (1-4) I have used the corresponding toPrecision point, e.g for SF1:
sfRoundedTextBlock.innerHTML = sfRoundedTextBlock.innerHTML + '<p><strong>Number: </strong></br>' + String(genNumber) +
'</br>' + '<strong>Rounded down to ' + i + ' SF:</br></strong>' + downArray[i].toPrecision(1) + '</br>' +
'<strong>Rounded up to ' + i + ' SF:</br></strong>' + upArray[i].toPrecision(1) + '</br><strong>Rounded off to ' + i + ' SF:</br></strong>'
+ roundedArray[i].toPrecision(1) + '</br>' + '(See the scale below for why we choose <strong>' + roundedArray[i].toPrecision(1) + '</strong> as the rounded off value.)</p>';
//Add The new scale data (Rounded Down)
downTextBlock = document.getElementById('down');
document.getElementById("down").innerHTML = String(downArray[i].toPrecision(1));
//Add The new scale data (Rounded Up)
upTextBlock = document.getElementById('up');
document.getElementById("up").innerHTML = String(upArray[i].toPrecision(1));
This was now giving me accurate results on every occasion, but there was still one hurdle left to jump. Occasionally I would reach a random scenario where scientific notation would have to be included in my outputted answer, e.g. 21819 rounded down to 1 SF, would read out at 2e+4 instead of 20000.
To combat this I setup my up, down and rounded figures into searchable strings, and then looked through these to find any illegal/scientific characters [a-z]. If I found any, I executed a slightly different version of my output which made use of parseFloat, which stripped out the scientific notation and displayed the correct figures:
//Convert Up, Down and Rounded into Strings based on their precision
var upString = String(upArray[i].toPrecision(1));
var downString = String(downArray[i].toPrecision(1));
var roundedString = String(roundedArray[i].toPrecision(1));
//Set up a regexp to search for characters [a-z], i.e. non-numeric
var regexp = /[a-z]/g;
//Search the up, down and rounded strings for non-numeric characters
var upResult = upString.match(regexp);
var downResult = downString.match(regexp);
var roundedResult = roundedString.match(regexp);
//If any of these strings contain a letter (non-numeric) we need to add in parseFloat to strip away the scientific notation included.
var containsChar = false;
if (upResult != null || downResult != null || roundedResult != null)
{
containsChar = true;
//alert("There is SN included here");
}
//Add The new data
sfRoundedTextBlock = document.getElementById('SFRounded');
if (containsChar == true)
{
sfRoundedTextBlock.innerHTML = sfRoundedTextBlock.innerHTML + '<p><strong>Number: </strong></br>' + String(genNumber) +
'</br>' + '<strong>Rounded down to ' + i + ' SF:</br></strong>' + parseFloat(downArray[i].toPrecision(1)) + '</br>' +
'<strong>Rounded up to ' + i + ' SF:</br></strong>' + parseFloat(upArray[i].toPrecision(1)) + '</br><strong>Rounded off to ' + i + ' SF:</br></strong>'
+ parseFloat(roundedArray[i].toPrecision(1)) + '</br>' + '(See the scale below for why we choose <strong>' + parseFloat(roundedArray[i].toPrecision(1)) + '</strong> as the rounded off value.)</p>';
//Add The new scale data (Rounded Down)
downTextBlock = document.getElementById('down');
document.getElementById("down").innerHTML = String(parseFloat(downArray[i].toPrecision(1)));
//Add The new scale data (Rounded Up)
upTextBlock = document.getElementById('up');
document.getElementById("up").innerHTML = String(parseFloat(upArray[i].toPrecision(1)));
}
Having tested this extensively it seems to be working as hoped.

SetInterval slowing down

After finding out I cannot use vender prefixes in Javascript, I tried to make my own fade-to-blur. After about 5-10 seconds of the script running the console.log calls slow to around one per second. Is this something on my end?
Here's the code I've made
var i = 0;
var iv = setInterval(function(){
if(Number(i) > 2)
{
clearInterval(iv);
}
console.log(i);
r = i.toFixed(2);
$('#r').css('filter', 'blur(' + r + 'px)');
$('#r').css('-webkit-filter', 'blur(' + r + 'px)');
$('#r').css('-moz-filter', 'blur(' + r + 'px)');
$('#r').css('-o-filter', 'blur(' + r + 'px)');
$('#r').css('-ms-filter', 'blur(' + r + 'px)');
i += 0.01;
}, 1);
And a JSFiddle
I'm guessing it's the way JS deals with floating-point numbers, also is there any way to get the fade to blurry more smooth? It's quite jumpy once i gets to around 0.8. How do I fix the second delay on the setInterval? Can anyone else reproduce this?
Things to note
The same thing occurred while trying to do the same with a for-loop, but it also rendered the page useless until it got to 2 when the loop stopped.
You can make the script faster by caching the calculation of the string 'blur(' + r + 'px)' into a javascript variable and save unwanted calculation.
You can also cache the $('#r') object into a javascript variable or even use the jquery css multiple-word properties: $('#r').css({propertyName : value , propertyName : value})
Something like:
var calc = 'blur(' + r + 'px)';
$('#r').css({
'filter' : calc ,
'-webkit-filter' : calc,
'-moz-filter' : calc,
'-o-filter' : calc,
'-ms-filter' : calc
});
check it here: http://jsfiddle.net/gMq3P/3/

Categories