Strange behavior when dividing inputs - javascript

I am building a basic application to learn more, but have came across an issue.
I have 3 input boxes. people, bill, tip. the maths is as follows:
(bill + tip) / people. When i try to divide in my code it seems to add onto the end of my total.
So far i have this. http://jsfiddle.net/ma9ic/a8eJT/
var updateTotal = function () {
var people = parseInt($('#people').val());
var bill = ($('#bill').val());
var tip = ($('#tip').val());
var billTip = bill + tip;
var billTipPeople = billTip / people;
$('#total').text("£" + billTipPeople)
If i could get pointed in the right direction that would be great :)

You're pretty close. I got it working like this
var updateTotal = function () {
var people = parseInt($('#people').val(),10);
var bill = parseFloat($('#bill').val());
var tip = parseFloat($('#tip').val());
var billTip = bill + tip;
var billTipPeople = billTip / people;
if (isNaN(billTipPeople)) billTipPeople = 0; // output zero if NaN
$('#total').text("£" + billTipPeople.toFixed(2))
The issue is that javascript has some weird rules about string concatenation. "1"+"1" == "11". You need to be explicit every time.
parseInt GOTCHA: ALWAYS use the second (optional) base parameter of parseInt. Values like "015" will be parsed as octal into the decimal number 13 otherwise. Hence the popular joke, "Why do programmers confuse Halloween and Christmas? Because OCT31 == DEC25!"

bill + tip will perform string concatenation, not addition, because they are both string. At least one of the operands has to be a number if you want to perform addition.
While parseFloat and parseInt work, using the unary plus operator is shorter to write and you don't have to worry about the type of number:
var people = +$('#people').val();
var bill = +$('#bill').val();
var tip = +$('#tip').val();
This works as long as the input value only consists of a number. But if the input only starts with a number, e.g. "5 foo" and you want to extract the number from the beginning of the string, you really have to use parseInt or parseFloat.

Your bill and tip variables are strings. Try using parseFloat(). Using the addition sign (+) on two strings will simply concatenate them.
var bill = parseFloat($('#bill').val());
var tip = parseFloat($('#tip').val());

While you used parseInt() in one case, why didn't you follow same path in similar situations?
Anyway, here's how I have modified your code:
$(document).ready(function () {
$('input#bill, input#tip').blur(function () {
var num = parseFloat($(this).val());
if (isNaN(num)) {
return;
}
var cleanNum = num.toFixed(2);
$(this).val(cleanNum);
if (num / cleanNum < 1) {}
});
$('#people, #bill, #tip').keyup(function () {
updateTotal();
});
var updateTotal = function () {
var people = parseInt($('#people').val());
if (isNaN(people) || people === 0) {
return;
}
var bill = parseFloat($('#bill').val());
if (isNaN(bill)) {
bill = 0;
}
var tip = parseFloat($('#tip').val());
if (isNaN(tip)) {
tip = 0;
}
var billTip = bill + tip;
var billTipPeople = billTip / people;
$('#total').text("£" + billTipPeople);
// round up to 2 d.p. like below:
// $('#total').text("£" + billTipPeople.toFixed(2));
};
});
To save you from coming back again and asking why your app has decided to come up another crazy behaviour, I've added the following checks:
When user enters number of people, even though we are not ready to enter total cost of bill, it is updated as NaN. We prevent this nasty behaviour by...
if (isNaN(num)) {
return;
}
We take same precaution in the updateTotal() function. Moreover, watch out for division by 0!* I give tips onle when I'm with my gf, otherwise, a person like me will break your app...
if (isNaN(people) || people === 0) {
return;
}
Here's the fiddle >> http://jsfiddle.net/a8eJT/11/

Try to use parseInt() and parseFloat() in javascript.When you did with out using these then it will treat as strings.

try
var updateTotal = function () {
var people = parseInt($('#people').val());
var bill = parseInt($('#bill').val());
var tip = parseInt($('#tip').val());
var billTip = bill + tip;
var billTipPeople = billTip / people;
$('#total').text("£" + billTipPeople)
I have added parseint to both bill & tip

Related

Random lottery number generator

What I'm trying to do is generate 6 random numbers, five in a range of 1-45 and one in a range of 1-25 for a Greek lottery game (Tzoker). The first 5 numbers should be unique. By pressing a button, I want to add these numbers to a div using jQuery (I have some working code for this part).
I thought it would be pretty easy using a loop, but I've found myself unable to check if the number generated already exists. The loop would only contain the first 5 numbers, because the last number can be equal to one of the other 5.
Let me propose you some simpler solution.
Make a list of all numbers from 1 to 45.
Sort the list using Math.random (plus minus something, read the docs of Array.sort to find out) as the comparison function. You will get the list in random order.
Take 5 first items from the list.
Then, when you already have the numbers, put them all into your div.
This way you don't mix your logic (getting the numbers) with your presentation (putting stuff into the DOM).
I leave the implementation as an exercise for the reader. :)
Like this?
$(function() {
$('button').on('click', function(e) {
e.preventDefault();
var numArray = [];
while( numArray.length < 5 ) {
var number = Math.floor((Math.random() * 45 ) + 1);
if( $.inArray( number, numArray ) == -1 ) {
numArray.push( number );
}
}
numArray.push( Math.floor((Math.random() * 25 ) + 1) );
$('div').html( numArray.join("<br />") );
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Generate</button>
<div></div>
While this might be not exactly what you were asking for, if you would use lodash, this would be as simple as:
_.sample(_.range(1, 46), 5) // the 5 numbers from 1..45
_.random(1, 26) // one more from 1..25
This is why functional programming is so cool. You can read for example Javascript Allonge to find out more.
http://jsfiddle.net/015d05uu/
var tzoker = $("#tzoker");
var results = $("#results");
tzoker.click(function() {
results.empty();
var properResults = [];
var rand = 0;
var contains = false;
for (i = 1; i < 7; i++) {
do
{
(rand = Math.floor((Math.random() * (i != 6 ? 45 : 25)) + 1));
contains = properResults.indexOf(rand) > -1;
} while(contains)
results.append("<br />", rand, "<br />");
properResults.push(rand);
}
});
Here is the main idea of a solution. You can define the max value as a parameter for the random.
Then, check the existence of the item in a simple array with only the data you want.
You may use a general function which generates random numbers from 1 to maxValue, and adds them to an array only if they don't exist. Then, to display, cycle through the array items and append them to #randomNumbers.
HTML
<div id="randomNumbers"></div>
JS (with jQuery)
var randomNumbersArray = [];
$(function() {
generateRandomNumbers();
displayRandomNumbers();
});
function generateRandomNumbers() {
for (i = 0; i < 5; i++) {
generateRandomNumberFrom1To(45);
}
generateRandomNumberFrom1To(25);
}
function generateRandomNumberFrom1To(maxValue) {
var randomNumber;
do {
randomNumber = Math.ceil(Math.random() * maxValue);
} while ($.inArray(randomNumber, randomNumbersArray) > -1);
randomNumbersArray.push(randomNumber);
}
function displayRandomNumbers() {
for (i in randomNumbersArray) {
$("#randomNumbers").append(randomNumbersArray[i] + "<br>");
}
}

Fibonacci Sequence - Find the number of digits - JavaScript

So, I have successfully written the Fibonacci sequence to create an array with the sequence of numbers, but I need to know the length (how many digits) the 500th number has.
I've tried the below code, but its finding the length of the scientific notation (22 digits), not the proper 105 it should be returning.
Any ideas how to convert a scientific notation number into an actual integer?
var fiblength = function fiblength(nth) {
var temparr = [0,1];
for(var i = 2; i<=nth; i++){
var prev = temparr[temparr.length-2],
cur = temparr[temparr.length-1],
next = prev + cur;
temparr.push(next);
}
var final = temparr[temparr.length-1].toString().length;
console.log(temparr[temparr.length-1]);
return final;
};
a = fiblength(500);
console.log(a);
Why not use the simple procedure of dividing the number by 10 until the number is less than 1.
Something as simple as this should work (a recursive def obv works as well)
function getDigits(n) {
var digits = 0;
while(n >= 1) {
n/=10;
digits += 1;
}
return digits;
}
getDigits(200);//3
getDigits(3.2 * 10e20);//=>22
Here's a solution in constant time:
function fiblength(n) {
return Math.floor((n>1)?n*.2089+.65051:1);
}
Let's explain how I arrived to it.
All previous solutions will probably not work for N>300 unless you have a BigNumber library in place. Also they're pretty inneficient.
There is a formula to get any Fibonacci number, which uses PHI (golden ratio number), it's very simple:
F(n) = ABS((PHI^n)/sqrt(5))
Where PHI=1.61803399 (golden ratio, found all over the fibonacci sequence)
If you want to know how many digits a number has, you calculate the log base 10 and add 1 to that. Let's call that function D(n) = log10(n) + 1
So what you want fiblength to be is in just the following function
fiblength(n) = D(F(n)) // number of digits of a fibonacci number...
Let's work it out, so you see what the one liner code will be like once you use math.
Substitute F(n)
fiblength(n) = D(ABS((PHI^n)/sqrt(5)))
Now apply D(n) on that:
fiblength(n) = log10(ABS((PHI^n)/sqrt(5))) + 1
So, since log(a/b) = log(a) - log(b)
fiblength(n) = log10(ABS((PHI^n))) - log10(sqrt(5))) + 1
and since log(a^n) = n * log(a)
fiblength(n) = n*log10(PHI) - log10(sqrt(5))) + 1
Then we evaluate those logarithms since they're all on constants
and add the special cases of n=0 and n=1 to return 1
function fiblength(n) {
return Math.floor((n>1)?n*.2089+.65051:1);
}
Enjoy :)
fiblength(500) => 105 //no iterations necessary.
Most of the javascript implementations, internally use 64 bit numbers. So, if the number we are trying to represent is very big, it uses scientific notation to represent those numbers. So, there is no pure "javascript numbers" based solution for this. You may have to look for other BigNum libraries.
As far as your code is concerned, you want only the 500th number, so you don't have to store the entire array of numbers in memory, just previous and current numbers are enough.
function fiblength(nth) {
var previous = 0, current = 1, temp;
for(var i = 2; i<=nth; i++){
temp = current;
current = previous + current;
previous = temp;
}
return current;
};
My Final Solution
function fiblength(nth) {
var a = 0, b = 1, c;
for(var i=2;i<=nth;i++){
c=b;
b=a+b;
a=c;
}
return Math.floor(Math.log(b)/Math.log(10))+1;
}
console.log(fiblength(500));
Thanks for the help!!!
The problem is because the resulting number was converted into a string before any meaningful calculations could be made. Here's how it could have been solved in the original code:
var fiblength = function fiblength(nth) {
var temparr = [0,1];
for(var i = 2; i<=nth; i++){
var prev = temparr[temparr.length-2],
cur = temparr[temparr.length-1],
next = prev + cur;
temparr.push(next);
}
var x = temparr[temparr.length-1];
console.log(x);
var length = 1;
while (x > 1) {
length = length + 1;
x = x/10;
}
return length;
};
console.log ( fiblength(500) );

Advice on how to code Luhn Credit Card validation with Javascript?

I'm pretty awful at Javascript as I've just started learning.
I'm doing a Luhn check for a 16-digit credit card.
It's driving me nuts and I'd just appreciate if someone looked over it and could give me some help.
<script>
var creditNum;
var valid = new Boolean(true);
creditNum = prompt("Enter your credit card number: ");
if((creditNum==null)||(creditNum=="")){
valid = false;
alert("Invalid Number!\nThere was no input.");
}else if(creditNum.length!=16){
valid = false;
alert("Invalid Number!\nThe number is the wrong length.");
}
//Luhn check
var c;
var digitOne;
var digitTwo;
var numSum;
for(i=0;i<16;i+2){
c = creditNum.slice(i,i+1);
if(c.length==2){
digitOne = c.slice(0,1);
digitTwo = c.slice(1,2);
numSum = numSum + (digitOne + digitTwo);
}else{
numSum = numSum + c;
}
}
if((numSum%10)!=0){
alert("Invalid Number!");
}else{
alert("Credit Card Accepted!");
}
</script>
The immediate problem in your code is your for loop. i+2 is not a proper third term. From the context, you're looking for i = i + 2, which you can write in shorthand as i += 2.
It seems your algorithm is "take the 16 digits, turn them into 8 pairs, add them together, and see if the sum is divisible by 10". If that's the case, you can massively simplify your loop - you never need to look at the tens' place, just the units' place.
Your loop could look like this and do the same thing:
for (i = 1; i < 16; i +=2) {
numSum += +creditNum[i];
}
Also, note that as long as you're dealing with a string, you don't need to slice anything at all - just use array notation to get each character.
I added a + in front of creditNum. One of the issues with javascript is that it will treat a string as a string, so if you have string "1" and string "3" and add them, you'll concatenate and get "13" instead of 4. The plus sign forces the string to be a number, so you'll get the right result.
The third term of the loop is the only blatant bug I see. I don't actually know the Luhn algorithm, so inferred the rest from the context of your code.
EDIT
Well, it would have helped if you had posted what the Luhn algorithm is. Chances are, if you can at least articulate it, you can help us help you code it.
Here's what you want.
// Luhn check
function luhnCheck(sixteenDigitString) {
var numSum = 0;
var value;
for (var i = 0; i < 16; ++i) {
if (i % 2 == 0) {
value = 2 * sixteenDigitString[i];
if (value >= 10) {
value = (Math.floor(value / 10) + value % 10);
}
} else {
value = +sixteenDigitString[i];
}
numSum += value;
}
return (numSum % 10 == 0);
}
alert(luhnCheck("4111111111111111"));
What this does is go through all the numbers, keeping the even indices as they are, but doubling the odd ones. If the doubling is more than nine, the values of the two digits are added together, as per the algorithm stated in wikipedia.
FIDDLE
Note: the number I tested with isn't my credit card number, but it's a well known number you can use that's known to pass a properly coded Luhn verification.
My below solution will work on AmEx also. I submitted it for a code test a while ago. Hope it helps :)
function validateCard(num){
var oddSum = 0;
var evenSum = 0;
var numToString = num.toString().split("");
for(var i = 0; i < numToString.length; i++){
if(i % 2 === 0){
if(numToString[i] * 2 >= 10){
evenSum += ((numToString[i] * 2) - 9 );
} else {
evenSum += numToString[i] * 2;
}
} else {
oddSum += parseInt(numToString[i]);
}
}
return (oddSum + evenSum) % 10 === 0;
}
console.log(validateCard(41111111111111111));
Enjoy - Mitch from https://spangle.com.au
#Spangle, when you're using even and odd here, you're already considering that index 0 is even? So you're doubling the digits at index 0, 2 and so on and not the second position, fourth and so on.. Is that intentional? It's returning inconsistent validations for some cards here compared with another algorithm I'm using. Try for example AmEx's 378282246310005.

Javascript rounding failure

This is the rounding function we are using (which is taken from stackoverflow answers on how to round). It rounds half up to 2dp (by default)
e.g. 2.185 should go to 2.19
function myRound(num, places) {
if (places== undefined) {
// default to 2dp
return Math.round(num* 100) / 100;
}
var mult = Math.pow(10,places);
return Math.round(num* mult) / mult;
}
It has worked well but now we have found some errors in it (in both chrome and running as jscript classic asp on IIS 7.5).
E.g.:
alert(myRound(2.185)); // = 2.19
alert (myRound(122.185)); // = 122.19
alert (myRound(511.185)); // = 511.19
alert (myRound(522.185)); // = 522.18 FAIL!!!!
alert (myRound(625.185)); // = 625.18 FAIL!!!!
Does anyone know:
Why this happens.
How we can round half up to 2 dp without random rounding errors like this.
update: OK, the crux of the problem is that in js, 625.185 * 100 = 62518.499999
How can we get over this?
Your problem is not easily resolved. It occurs because IEEE doubles use a binary representation that cannot exactly represent all decimals. The closest internal representation to 625.185 is 625.18499999999994543031789362430572509765625, which is ever so slightly less than 625.185, and for which the correct rounding is downwards.
Depending on your circumstances, you might get away with the following:
Math.round(Math.round(625.185 * 1000) / 10) / 100 // evaluates to 625.19
This isn't strictly correct, however, since, e.g., it will round, 625.1847 upwards to 625.19. Only use it if you know that the input will never have more than three decimal places.
A simpler option is to add a small epsilon before rounding:
Math.round(625.185 * 100 + 1e-6) / 100
This is still a compromise, since you might conceivably have a number that is very slightly less than 625.185, but it's probably more robust than the first solution. Watch out for negative numbers, though.
Try using toFixed function on value.
example is below:
var value = parseFloat(2.185);
var fixed = value.toFixed(2);
alert(fixed);
I tried and it worked well.
EDIT: You can always transform string to number using parseFloat(stringVar).
EDIT2:
function myRound(num, places) {
return parseFloat(num.toFixed(places));
}
EDIT 3:
Updated answer, tested and working:
function myRound(num, places) {
if (places== undefined) {
places = 2;
}
var mult = Math.pow(10,places + 1);
var mult2 = Math.pow(10,places);
return Math.round(num* mult / 10) / mult2;
}
EDIT 4:
Tested on most examples noted in comments:
function myRound(num, places) {
if (places== undefined) {
places = 2;
}
var mult = Math.pow(10,places);
var val = num* mult;
var intVal = parseInt(val);
var floatVal = parseFloat(val);
if (intVal < floatVal) {
val += 0.1;
}
return Math.round(val) / mult;
}
EDIT 5:
Only solution that I managed to find is to use strings to get round on exact decimal.
Solution is pasted below, with String prototype extension method, replaceAt.
Please check and let me know if anyone finds some example that is not working.
function myRound2(num, places) {
var retVal = null;
if (places == undefined) {
places = 2;
}
var splits = num.split('.');
if (splits && splits.length <= 2) {
var wholePart = splits[0];
var decimalPart = null;
if (splits.length > 1) {
decimalPart = splits[1];
}
if (decimalPart && decimalPart.length > places) {
var roundingDigit = parseInt(decimalPart[places]);
var previousDigit = parseInt(decimalPart[places - 1]);
var increment = (roundingDigit < 5) ? 0 : 1;
previousDigit = previousDigit + increment;
decimalPart = decimalPart.replaceAt(places - 1, previousDigit + '').substr(0, places);
}
retVal = parseFloat(wholePart + '.' + decimalPart);
}
return retVal;
}
String.prototype.replaceAt = function (index, character) {
return this.substr(0, index) + character + this.substr(index + character.length);
}
OK, found a "complete" solution to the issue.
Firstly, donwnloaded Big.js from here: https://github.com/MikeMcl/big.js/
Then modified the source so it would work with jscript/asp:
/* big.js v2.1.0 https://github.com/MikeMcl/big.js/LICENCE */
var Big = (function ( global ) {
'use strict';
:
// EXPORT
return Big;
})( this );
Then did my calculation using Big types and used the Big toFixed(dp), then converted back into a number thusly:
var bigMult = new Big (multiplier);
var bigLineStake = new Big(lineStake);
var bigWin = bigLineStake.times(bigMult);
var strWin = bigWin.toFixed(2); // this does the rounding correctly.
var win = parseFloat(strWin); // back to a number!
This basically uses Bigs own rounding in its toFixed, which seems to work correctly in all cases.
Shame Big doesnt have a method to convert back to a number without having to go through a string.

JavaScript issue in IE when adding numbers

I have a simple form, with 5 textboxes and 3 answers (also textboxes). The form calculates a result for the user with number inputs. My problem is my calculation does not work in IE, but works fine in both Chrome and Firefox.
What's wrong?
Here is my function:
function addNumbers()
{
var val1 = Number(document.getElementById("value1").value);
var val2 = Number(document.getElementById("value2").value);
var val3 = Number(document.getElementById("value3").value);
var val4 = Number(document.getElementById("value4").value);
var val5 = Number(document.getElementById("value5").value);
var val6 = '100';
var ansD1 = document.getElementById("answer1");
ansD1.value = Number((val1 * val2) * (val4 / val6));
var ansD2 = document.getElementById("answer2");
ansD2.value = Number((val1 * val3) * (val5 / val6));
var ansD3 = document.getElementById("answer3");
ansD3.value = Number (ansD1.value - ansD2.value);
}
Change this line:
var val6 = '100';
to this:
var val6 = 100;
You want all your values to be actual numbers (not strings) so you can do math on them.
Also, you don't need the Number() in these lines because the result of the numeric math is already a number. Plus the assignment to the answer fields is just going to convert the result to a string anyway:
ansD1.value = Number((val1 * val2)*(val4/val6));
They can just be this:
ansD1.value = (val1 * val2)*(val4/val6);
The modified code works fine in IE here: http://jsfiddle.net/jfriend00/5WFRA/.
Instead of Number use parseInt, otherwise they are treated as strings

Categories

Resources