Allow decimal with isNaN - javascript

I have a script where i can put in a number in one text box and it will calculate the equivalent in the other textboxes.
$("input[type=text]").keyup(function () {
var number = parseFloat($(this).val());
var inc = parseFloat($(this).attr("inc"));
var newValue = number / inc;
$("input[type=text]").each(function () {
if(isNaN(newValue * parseFloat($(this).attr("inc"))))
$(this).val(0);
else
$(this).val(newValue * parseFloat($(this).attr("inc")));
});
});
Can check : JSFiddle Here
At the moment it doesn't allow for decimal numbers. But i really need it to. And i don't know how to allow a decimal.
Also i need the box's to have a limit of 2 numbers ofter the decimal point.

TL;DR: Skip to the actual code if you just want the fix. The following paragraphs explains why it is happening.
The reason the decimal numbers aren't working is every single time the text box get edited by a single character, all numbers in all text boxes are converted to a float. If you type 1 into one of the boxes, the value gets passed to parseFloat and gets converted to 1 (the same value). If you then press the 3 character, the text box says 13, which gets passed to parseFloat and returns the same value, 13.
However, if you start typing 13., that gets passed to parseFloat; JavaScript realizes the period is unnecessary*, and places the value 13 in the text box. No matter how fast you type, JavaScript will keep wanting to trim off that "unnecessary" period before you can add extra digits to the end.
You can solve this by only running parseFloat function (or changing the value in any way) on the text fields you are not currently typing in. I have emphasized the two lines in which "the magic happens":
$("input[type=text]").keyup(function () {
var number = parseFloat($(this).val());
var inc = parseFloat($(this).attr("inc"));
var newValue = number / inc;
var current = this; // <---- "current" is the text field that is currently being edited
$("input[type=text]").each(function () {
if(this != current) { // <--------------
if (isNaN(newValue * parseFloat($(this).attr("inc"))))
$(this).val(0);
else
$(this).val(newValue * parseFloat($(this).attr("inc")));
}
});
});
And a JS Fiddle of the code so you can test it: http://jsfiddle.net/RX2sL/27/
* Technically the period gets trimmed off due to the String -> Float -> String conversion, but it's easier to think of the period as being "unnecessary".

Related

Handling very large numbers in input tag in angular

I'm brand new to Angular.
I tried several approaches to dealing with large numbers using the input number type.
<input type="number" step="1" (change)="handleChange($event)"/>
When I enter the number 1234567890123456789 (a very large number) into this input box and click the arrow up or arrow down, it is frozen as scientific notation.
For exmaple:
I put this number 1234567890123456789.
When I click the arrow up to increase the value, it will look like this, and the value 1234567890123456800 will be returned to my handleChange function (already lost precision).
As a result, text-type input is the solution. However, if I change the type from number to text, my spin box (arrows up and down) will disappear. I want to use text input while keeping the spin box and modifying its behavior. Is this something that can be done?
Thank you in advance.
A proper solution will likely avoid numeric <input> fields for numbers that are larger than Javascript precision allows (as suggested in Eliseo's comment).
But, just for completeness, here is an approach that works with a numeric <input> and the native spinner. It manipulates the step so that a change in the value by one step can be detected although a change of +/- 1 is beyond the precision of a Javascript number. And based on whether it has detected an "up" or "down" spin, it increases the BigInt value of the input by +/- 1.
After each value change, the step is the numeric value, as seen by Javascript, even if this does not exactly match the string value (which is what counts when the form is submitted). But it matches closely enough to avoid a step mismatch.
This is probably more of a curiosity, especially since intermediate numbers during the "step detection" are visible.
function xstep(input) {
input.oldValue = input.value;
input.step = Number(input.value);
}
function nstep(input) {
var delta = input.valueAsNumber - (Number(input.oldValue) || 0);
if (delta > 0) delta = 1n;
else if (delta < 0) delta = -1n;
else return;
try {
var v = BigInt(input.oldValue);
} catch(e) {
v = BigInt(Number(input.oldValue));
}
input.value = (v + delta).toString();
xstep(input);
}
<html>
<body>
<input type="number" onkeyup="xstep(this)" onchange="nstep(this)"/>
</body>
</html>

I need help determining the difference between my code that I believe produces the same result as another, but won't be accepted

I am stuck on how my code will not be accepted by freeCodeCamp's auto-grader. The objective was to create a function without any parameters that will generate a random number using Math.random(). Then we would have to multiply the randomly generated number by 10. After multiplying the randomly generated by 10, I would have to use Math.floor() to round it up or down.
Link to challenge: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-javascript/generate-random-whole-numbers-with-javascript
These are the objectives given to me, quoted directly from freeCodeCamp's challenge:
1.) The result of randomWholeNum should be a whole number.
2.) You should use Math.random to generate a random number.
3.) You should have multiplied the result of Math.random by 10 to make it a number that is between zero and nine.
4.) You should use Math.floor to remove the decimal part of the number.
Here is my code:
function randomWholeNum() {
var x = Math.random();
var z = x * 10;
var y = Math.floor(z);
return y;
}
As you can see, I used multiple variables to complete this task. x would generate the random number, z would store the random number multiplied by 10, y would round z, resulting in all objectives passed. However, when running the code, all objectives were ticked except for Number 3. I don't understand what went wrong, and after looking at the answer for the challenge, which is:
function randomWholeNum() {
// Only change code below this line.
return Math.floor(Math.random() * 10);
}
I don't understand why the code I wrote doesn't produce the same result of freeCodeCamp's own.

Logic for my land size calculator application

I'm making this acres and karats calculator for my uncle to help him in his work.
I'll explain the whole idea of this thing with this example. So if you add 3.22 + 2.2 it should be = 5.42 but in this calculator 3.22 + 2.2 should = 6, because 3 acres + 2 acres = 5 acres and 22 karats + 2 karats = 1 acre, so the total would be 6 acres.
The way I'm doing it in the code is that I'm splitting a number like 3.22 to two, 3 and 22 and the other number to 2 and 2 and I add the whole numbers together and the fractions together and if the fractions are >= 24 I add one to the whole numbers and if there're fractions left from the whole calculation I leave it. For example 3.15 + 2.15 = 6.6, but I'm stuck on how I can add the numbers, there's also an error in there that I don't know how to resolve.
Anyway here's the code
function getValue(v) {
return +v.toString().match(/\.(\d*)/)[1] || 0;
}
function getTotal() {
d += Math.floor(num);
p += getValue(num);
if (p >= 24) {
p -= 24;
++d;
}
total = d + p / 100;
ptag.textContent = total;
}
I added the part of the code where I'm stuck.
Note: I'm trying to make the thing able to add multiple numbers not only two. Also I'm trying to add subtraction but I have no idea how to start working on the subtraction because I haven't even finished the addition.
If the error you are talking about is something like this:
Uncaught TypeError: Cannot read property '1' of null
It is because of your getValue function.
My suggestion is, instead of using something as complicated as
function getValue(v) {
return +v.toString().match(/\.(\d*)/)[1] || 0;
}
use
function getValue(v) {
return floor((v % 1) * 100);
}
This has the same effect as the code you wrote. Which for example, from input 3.13, returns 13.
But there are few other problems.
First, you should update your num variable every now and often, otherwise, it is always going to stay as an empty string (you only defined it on line 20, and you didn't update it after that).
Second, you should clear the d and p variable after you use. As of right now, both of these variables just keeps on increasing every time you run the getTotal function
For your question of how you can add two numbers, I suggest you to create a variable where you can store the first number that the user typed.
For example, when the user typed in 4.19 and pressed the plus button, save that 4.19 into a variable (let's say firstNum).
Then when the user pressed equal button, add the number from the current input field with the firstNum variable.
On how exactly you are going to add two different numbers, break two numbers you want to add into Acres part and Karats parts. Then add them separately, then use your getTotal.
So if the number is 3.21 and 5.18, add 3 and 5, add 21 and 18, then add both of them.
you'll get 8.39. Finally, convert 8.39 into 9.15.
Sorry if my calculation is not correct. It is my first time with this concept!
But I believe this is the way to go.

How to compare a number string and it's reverse to find the next highest palindrome?

I am trying to build a function that takes a price with 2 decimal points and finds the next highest palindrome. I know there are several other ways to approach this, but I am curious why my method is not working. I am new to JS so this might be a simple one. Any advice would be great.
I broke it into smaller chunks with explanations of what I want it to do below:
var ask = prompt("Enter a price");
var reverseIt = function (x) {
x = (parseFloat(x) * 100).toString();
for (var i = (x.length - 1); i >= 0; i--) {
x.substr(i, 1);
}
return
};
The reverseIt function takes an argument removes the decimal (* 100) and reverses the number.
var removeDec = function (j) {
return (parseFloat(j) * 100).toString();
}
The removeDec function takes an argument, removes the decimal point (* 100), and converts it back to a string. Is this redundant for comparing two "number" strings? Should I use the Number() and String() functions instead?
var findDrome = function (i) {
for (var i; removeDec(i) != reverseIt(i); i += (1 / 100)) {
if ((removeDec(i) + 1).toString() == reverseIt(i)) {
document.write(i + (1 / 100));
}
} return
};
findDrome(ask);
The findDrome function takes the ask prompt at the start as an argument. If the number without a decimal doesn't match the reverse without a decimal, then increments it by 0.01. Right before the loop ends, I wanted it to check if the number prior +1 (since it is * 100) is equal to the reverse and if so write the next number.
It wasn't working, so I tried adding parseFloat and toString to specify stricter/more explicit conversions. I also used the loose equality operators, but it's still not working.
My questions: Is this a conversion or syntactical problem or can you not compare the output of 2 functions? Should I instead compare 2 variables and if so how do I assign the for loop in the reverseIt function to a variable?
Your program has a number of issues. First, your reverseIt function never returns a reversed value. The variable x is passed in but it's never updated in the for loop - x.substr() creates a new string instance but it's never assigned back to x so its value never changes. As it is, your for loop in findDrome goes infinite since reverseIt returns undefined.
Another - possible - problem is that you're incrementing a floating-point number by 1/100 but floating point values have no exact representation. I don't know if this is actually affecting your code (since it currently never returns a proper value) but it's something you may have to worry about. This would likely affect parseFloat (which may return a slighly different floating-point value than the string it parses).
Using toFixed() would truncate the number to 2 decimal digits. You could then turn the number to a string and remove the decimal dot character, rather than converting the number back and forth between string and number.
You may want to read up on floating-point arithmetic (if you're not already familiar with it).
As a last comment, you should never, ever rely on Javascript terminating your statements - you should always use ; to terminate a statement like in other proper C-style languages. Leaving out ;-s (even if Javascript lets you get away with it) is considered very poor practice.
I figured it out thanks to the help above! Here is how the fixed program works:
var ask = prompt("Enter a price to find the next palindromic price");
var removeDec = function (j) {
return parseInt(j * 100);
};
var c = removeDec(ask);
This prompts a price and multiplies it by 100 to remove the decimal point and avoid floating point arithmetic. The parseInt removes any decimals smaller than the hundredths place.
var reverseIt = function (x) {
var a = ""
x = x.toString();
for (var i = (x.length - 1); i >= 0; i--) {
a = (a + String(x.substr(i, 1)));
}
return Number(a);
};
var b = reverseIt(c);
The reverseIt function takes an argument, converts it to string and adds each character in reverse to an empty string (a=""). Var a is then returned as a number. The empty string is important for storing the reverse number and is a big reason why my code wasn't working before.
var e = Math.pow(10, (String(c).length - 1));
Var e was added to take into account varying place values to left side of the decimal. Later this helps check if a number is equal to its reverse by adding a 1 to both sides of the number. Var e counts the length of var c (entered value with decimal removed) and finds the appropriate power of 10 to add later. So if you entered 14.40 * 100 then later it will check if 1440 + 1 is equal to 0441 + 1000.. or 10^3. This test is important later in order to exit the loop. This is where my code was failing before because I didn't take adding a number to the reverse into account and I was trying to add decimals which aren't as predictable.
if (c == b) {
document.write("$" + (c / 100) + "... This price is already palindrome!")
} else {
for (c; c !== b; c++) {
b = reverseIt(c);
if ((c + 1) == (b + e)) {
document.write("The next palindromic price is $" + ((Number(c) + 1) / 100));
break;
}
}
}
Here, If the original number and it's reverse are not equal then a loop begins that increments the value by 1 until the entered number + 1 is equal to the reversed number + e. So effectively the loop finds the number right before the loop ends, writes it and then breaks out of the loop. This palindrome finder seems to work smoothly with values big and small, no matter where you put the decimal point. Glad I got it working... it was a great learning experience figuring it out!

Optimise my Javascript percentage calculator

I have a javascript that calculates the percentage from two fields (retail and network) and then dumps that percentage into another field (markup).
As I am relatively new to the world of JS I have ended up reusing the code for several rows of fields. This goes against DRY and KISS principles so I was wondering if you could give me some input on how to optimise my code so that it can handle any two fields and then dump a value to a third field.
Here is a screenshot of my form segment that is using it.
http://i.imgur.com/FHvDs.png
Here is my code I am using, I have had to reuse it four times and place the code in four functions e.g. (percentage1, percentage2, percentage3, percentage4) each one of these functions deals with a row of fields show in the screenshot.
function percentage1()
{
//the dividee
x = document.getElementById('tariff_data');
//the divider
y = document.getElementById('network_data');
//if the first value is lower than the second, append a "-" sign
if (x.value < y.value)
{
z = "-"+(x.value/y.value)*100;
document.getElementById('markup_data').value = z;
}
//not a negative percentage
else
{
z = (x.value/y.value)*100;
document.getElementById('markup_data').value = z;
}
}
function percentage2()
{
//the dividee
x = document.getElementById('tariff_rental');
//the divider
y = document.getElementById('network_rental');
//if the first value is lower than the second, append a "-" sign
if (x.value < y.value)
{
z = "-"+(x.value/y.value)*100;
document.getElementById('markup_rental').value = z;
}
//not a negative percentage
else
{
z = (x.value/y.value)*100;
document.getElementById('markup_data').value = z;
}
}
etc etc....
These functions are called using the onchange HTML attribute
Also when I divide by a decimal number it gives the wrong value, any Ideas how to make it calculate the correct percentage of a decimal number?
My code also gives out these strange outputs:
NaN , Infinity
Thanks
Rather than optimization, let's focus on correctness first =)
Note that the HTMLInputElement.value property has type "string", so your arithmetic operators are doing implicit type conversion which means you are likely often doing string concatenation instead of the numeric operations you expect.
I strongly recommend explicitly converting them to numbers first and checking for invalid input, also, don't forget to declare your variables first using var so they don't potentially clobber globals, e.g.:
var x = Number(document.getElementById('tariff_data'));
var y = Number(document.getElementById('network_data'));
if (!isFinite(x) || !isFinite(y)) {
// Handle non-numerical input...
}
You can also use the parseFloat function if you prefer, e.g.:
var x = parseFloat(document.getElementById('tariff_data'), 10);
I highly recommend doing some formal learning about the JavaScript language; it is full of pitfalls but if you stick to the "good parts" you can save yourself a lot of hassle and headache.
With regard to DRYing your code out; remember that you can:
Pass parameters to your functions and use those arguments within the function
Return values using the return keyword
In your case, you've got all your multiplication code repeated. While trying to fix the string vs. number problems maerics has already mentioned, you could do something like this:
// We're assuming 'dividee' and 'divider' are numbers.
function calculatePercentage(dividee, divider) {
var result;
// Regardless of the positive/negative result of the calculation,
// get the positive result using Math.abs().
result = Math.abs((dividee.value / divider.value) * 100);
// If the result was going to be negative...
if (dividee.value < divider.value) {
// Convert our result to negative.
result = result * -1;
}
// Return our result.
return result;
}
Then, in your percentage functions, you can just call this code like so:
function percentage1() {
var tariff, network, markup;
tariff = parseFloat(document.getElementById('tariff_data').value, 10);
network = parseFloat(document.getElementById('network_data').value, 10);
markup = document.getElementById('markup_data');
markup.value = calculatePercentage(tariff, network);
}
Obviously, you could take this further, and create a function which takes in the IDs, extracts the values from the elements etc., but you should try and build that yourself based on these tips.
Maerics also makes a very good point which you should take note of; learn more about the Good Parts of JavaScript. Douglas Crockford's book is excellent, and should be read and understood by all JS developers, IMHO.
Hope this helps you clean your code up!

Categories