why is this while loop causing an infinite loop? - javascript

For some reason I'm having difficulty getting this while loop to work. It keeps crashing my browser whenever I try to test it out, and in the one case that I was able to see the results of the loop in the console, all I saw was NaN printed several times. Is there something I've forgotten in my code?
<div id="output"></div>
<script>
var starting = prompt("What is your starting balance?");
var target = prompt("What is your target balance?");
var interest = prompt("What is your interest rate?");
var periods = 0;
var current = starting;
var greaterThan = false;
while (greaterThan === false) {
if (current < target) {
current = current + (current * interest);
periods++;
} else {
greaterThan = true;
alert("it took " + periods + " periods to make your starting balance greater than your target balance.");
document.querySelector('#output').textContent = "to grow an initial investment of " + starting + " to " + target + " at a " + interest + " interest rate will require " + periods + " investment periods.";
}
}
</script>

The one problem I could see is, all your input values are string, not numbers so they are doing string comparison not numeric
var starting = +prompt("What is your starting balance?") ||0;
var target = +prompt("What is your target balance?")||0;
var interest = +prompt("What is your interest rate?")||1;
The + in front of prompt() is the unary plus operator

You are forgetting to convert the result from prompt from a string into a number.
var starting = parseFloat(prompt("What is your starting balance?"));
Do the same thing to the other numbers that are input by the user from the prompt.

First you need to convert your input into an integer value. The input from the prompt is a string. even if you enter 1 or 10 or any number. You can use parseInt() for that. and because you are asking for interest rate, i think any user would enter something like 2. 5, or 10 as a percentile. not 0.1, or 0.05. Even if he does, the parseInt() function can't get it right because 0.05 is not an integer value. You can use parseFloat for that. so i suggest you look at my implementation of your code below. also, i have omitted the if else statements because they weren't necessary and would only make the code more complex.
<div id="output"></div>
<script type="text/javascript">
var starting = parseInt(prompt("What is your starting balance?"));
var target = parseInt(prompt("What is your target balance?"));
var interest = parseInt(prompt("What is your interest rate?"));
var periods = 0;
var intrate = interest/100;
var current = starting;
while (current< target) {
current += (current*intrate);
periods += 1;
}
alert("it took " + periods + " periods to make your starting balance greater than your target balance.");
document.querySelector('#output').textContent = "to grow an initial investment of " + starting + " to " + target + " at a " + interest + " interest rate will require " + periods + " investment periods.";
</script>

Related

To find how many characters are remaining from a total of 140, slice function

To do that I have written code below
var tweet = prompt("compose your tweet");
var tweetcount = tweet.length;
alert("you have written " + tweetcount + " characters you have " + (140 - tweetcount) + " characters remaining. ");
var tweet = "cut down your tweet";
tweetcount.slice(141, 1);
While it effectively gives a prompt to write and after that tells how many characters left + over limit of characters.
But in the console why does it say tweetcount.slice is not a function?
var tweet = prompt ("compose your tweet"); var tweetunder140 = tweet.slice(0,140); alert(tweetunder140);

Calculator for test scores javascript

I'd like to create an average calculator for test scores. Have the user enter numbers. They can enter as many as they want. Once they enter “-1”, end the program. Display the lowest test score, the highest test score, the sum of all test scores, and the average of all test scores.
The following is my code. I've already figured out how to do the sum of the scores. However, I don't know how I can turn ALL my inputs into a string - possibly output the lowest (Math.min), highest (Math.max) and average of the test score.
I tried joining strings together but in the end I couldn't figure out how to work!
while (true) {
var itemGrade = parseFloat(prompt("Enter a grade!\n\n(enter -1 to quit)"));
var item = itemGrade + ", "
total += itemGrade;
if (itemGrade == -1) {
break;
}
}
document.write("Total: " + total)
Here is a short piece of code that should do the job. The syntax ${variable} with ` allows variables to become strings. Total score is how you've written it. Lowest and highest simply checks if the new score entered is a higher or lower number and replaces the variable as the new lowest/highest. A count is added to calculate the average of all scores.
var total_score = 0.0;
var average_score = 0.0;
var lowest_score = Infinity;
var highest_score = 0.0;
var count = 0.0;
while (true) {
var itemGrade = parseFloat(prompt("Enter a grade!\n\n(enter -1 to quit)"));
if (itemGrade == -1) {
break;
}
total_score += itemGrade;
if (lowest_score > itemGrade){
lowest_score = itemGrade;
}
if (highest_score < itemGrade){
highest_score = itemGrade;
}
count++;
}
average_score = total_score/count;
document.write("Total Score: " + `${total_score}`);
document.write("Average Score: " + `${average_score}`);
document.write("Lowest Score: " + `${lowest_score}`);
document.write("Highest Score: " + `${highest_score}`);
var item = []
item.push(itemGrade)
You can create an empty array and use push() inside the while loop to add value to end of an array or use unshift() in case you want to add in starting position of the array

Making the full sentence bold, even after added 'and' in javascript

I have a question regarding the message I'd like to display based on some values.
I have 4 categories that have some values and I need to display the message if they show high risk. The message is based on the number of risks which can be from 1 to 4 factors hence two messages where I'm using "factor IS" and "factors ARE".
My problem is I cannot make those factors bold after I add 'and' in my else statement. The beginning of the sentence is bold but not the last risk which comes after 'and'.
I'm adding 'and' before the last item of my array as I don't want comma (I found the code on: Array to Comma separated string and for last tag use the 'and' instead of comma in jquery).
Thanks for your help and suggestions!
function displayMessage() {
var getRiskFactors = calculateRisk();
var getRiskFactorsLength = getRiskFactors.length;
for (var i=0; i < getRiskFactorsLength; i++ ) {
if(getRiskFactorsLength === 1) {
var message = "Your main risk factor is your <b>" + getRiskFactors[0] + "</b>";
} else {
//this joins items from the array with comma if there's
//more than one factor.
//it also adds "AND" before the last item in the array
// instead of comma
var message = "Your main risk factors are your " + [getRiskFactors.slice(0, -1).join(", "), getRiskFactors.slice(-1)[0]].join(getRiskFactors.length < 2 ? "" : " and " + "</b>");
}
}
return message;
}
You are not starting and closing the bold tag
let getRiskFactors = [ 1,2,3,4 ];
var output = "Your main risk factors are your " + [ "<b>" + getRiskFactors.slice(0, -1).join(", "), getRiskFactors.slice(-1)[0]].join(getRiskFactors.length < 2 ? "" : "</b> and <b>") + "</b>";
document.body.innerHTML = output;
console.log(output);
You've misplaced your start <b> tag in the else clause and you are always adding a closing </b> tag after each and.
Just enclose the whole thing like this:
else {
var message = "Your main risk factors are your <b>" + [getRiskFactors.slice(0, -1).join(", "), getRiskFactors.slice(-1)[0]].join(getRiskFactors.length < 2 ? "" : " and ") + "</b>";
}
There is a balance between writing concise code and debuggable/readable code. This is a good illustration of trying to be too clever. I tried to make your code a little more readable.
In my experience I have found errors arise when using concatenation of strings and the ?: operator on the same line. Try the following code and edit as necessary.
var getRiskFactors = calculateRisk();
var getRiskFactorsLength = getRiskFactors.length;
for (var i=0; i < getRiskFactorsLength; i++ ) {
if(getRiskFactorsLength === 1) {
var message = "Your main risk factor is your <b>";
message+= getRiskFactors[0] + "</b>";
} else {
//this joins items from the array with comma if there's
//more than one factor.
//it also adds "AND" before the last item in the array
// instead of comma
var message = "Your main risk factors are your ";
var arraypart1 = getRiskFactors.slice(0, -1).join(", ");
var arraypart2 = getRiskFactors.slice(-1)[0];
var computation = getRiskFactors.length < 2 ? "" : " and ";
var joinedarray = [];
joinedarray.push(arraypart1);
joinedarray.push(arraypart2);
message += joinedarray.join(compution) + "</b>";
}
}
return message;

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.

Trying to get my JavaScript to work out the 2 numbers entered to get calculated by pc.

Just wondering if anyone can work out why I keep getting for eg. 3+3=33 and not 6.
The rest of the coding works fine for the divide and times its the addition that keeps stuffing up and wont come up with the correct answer.. please help if you can.
here is my code:
<html>
<head>
<title>Practical Task 8 </title>
</head>
<body>
<button onclick="myFunction()">Press & Enter First Digit & Second Digit</button>
<script type="TEXT/JavaScript">
function myFunction()
{
var x=prompt("Please enter first number","0");
var y=prompt("Please enter second number","0");
var sum = x;
var sum2 = y;
var n = (x * y);
var n2 = (x / y);
var n3 = (x + y);
document.write(sum + " + " + sum2 + " = " + n3);
document.write("<BR>" + sum + " * " + sum2 + " = " + n);
document.write("<BR>" + sum + " / " + sum2 + " = " + n2);
}
</script>
</body>
</html>
You're performing string concatenation, not integer addition.
Use parseInt first:
x = parseInt( x, 10 );
y = parseInt( y, 10 );
MDN recommends always specifying the radix (the 10 part) to avoid problems, such as if a user prepends a number with 0 (where it'll be parsed as octal), or if different browsers have a different default radix (wtf, I know!).
You have to do this because the output of prompt is always a string, even if it's a number (e.g. "10" or "0123"), you need to tell JavaScript to interpret the data as a number (use parseInt if it's an integer (a whole number), or use parseFloat if you'll accept numbers with decimal places). Confusingly the + operator works for both string and number types, where it performs either concatenation (i.e. joining strings together like glue) or addition depending on the type of its operands.
Because your code is adding strings.
User input is always string.
You need to parseInt(x, 10) and parseInt(y, 10) to parse the string value into int base 10.

Categories