JavaScript - wrong float values comparison - javascript

There are two fields - faceValue fv2 and askingPrice num2 - and askingPrice can't be less than faceValue.
The check is almost working, but with a face value of 10.00, the alert only triggers when the asking price is 1.00 (9.00, 8.00 etc etc don't trigger it). However, when fv2 reloads into the form it's correct - 10.00.
How to fix this issue? here's the code
// new askingPrice comparison
var fv2 = parseFloat($('.ticketFaceValue').val()).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
var num2 = parseFloat($(this).val()).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
if (num2 < fv2) {
alert('Sorry, your asking price can\'t be less than face value. Please change your asking price.');
$(this).val(fv2);
row.find('.askingPriceData').html(fv2);
recalculateFees();
}
// end new askingPrice comparison

Although you use parseFloat to convert the input string to a number type, you convert it back to string with toFixed, and so the comparison is character based, not by numerical value.
The thing you try to do with a replace (add thousands separators) can also be done with toLocaleString, but you need to take care to not to put that formatted string back into the input element, as it will not parse as a number. It is probably better to use separate variables for the numerical value and the formatted value. Maybe like this:
var fv2 = +$('.ticketFaceValue').val()
var num2 = +$(this).val();
var fv2Fmt =fv2.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2});
var num2Fmt =num2.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2});
if (num2 < fv2) {
alert('Sorry, your asking price can\'t be less than face value. Please change your asking price.');
$(this).val(fv2);
row.find('.askingPriceData').html(fv2Fmt);
recalculateFees();
}

toFixed() method returns string so you are comparing two strings. Try the below code.
var fv2_float = parseFloat($('.ticketFaceValue').val());
var num2_float = parseFloat($(this).val());
var fv2 = fv2_float.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
var num2 = num2_float.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
if (num2_float < fv2_float) {
// Do your staff
}
Or try below one, but this is not very efficient.
// Your code goes here
if (parseFloat(num2) < parseFloat(fv2)) {
// Do your staff
}

Related

How to format numeric values with pattern?

I'm finding an equivalent to Java's DecimalFormat in JavaScript. I would like to format given numeric values with given decimal pattern like
"#,###.00"
"###.##"
"#,###.##"
"$#,##0.00"
"###,###.00"
"$###,###.00"
"###,###.###"
"####,####.000"
Has there any way to achieve it?
Part 1 - formatting
I would recommend using the Intl.NumberFormat natively supported in javascript, although it may not be supported by older browsers. Looks like IE11 has it, but not android.
So if you wanted to support US Dollars you would simply use something like this
var dollarFormat = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
var amountInDollars = dollarFormat.format(123456.123);
// amountInDollars = "$123,456.12"
But this also rounds up for you, for example
var roundedDollars = dollarFormat.format(555.555);
// roundedDollars = "$555.56";
For the numeric cases just use a different formatter. The default 'en-US' adds commas, a decimal before fractional numbers, and limits to 3 fractional numbers. But this is configurable.
var numberFormat = new Intl.NumberFormat('en-US');
var formatted = numberFormat.format(123456.123456);
// formatted = "123,456.123"
var numberFormat2decimals = new Intl.NumberFormat('en-US', { maximumFractionDigits: 2 });
var formatted2 = numberFormat2decimals.format(123456.123456);
// formatted2 = "123,456.12"
You can set maximum and minimum for fraction, integer, and significant digits, and this also supports international formats. Since it's native javascript, I think it's a good way to go if your platforms support it.
MDN is an excellent reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
Part 2 - the 0's
To achieve the 0's in your formats you'll have to modify the value before passing to the formatter. If you require a minimum fractional amount, you're fine for things like .00, the currency formatter will do that by default. If you've got fractal numbers you don't want, just use Math.trun() to truncate the values.
var num = Math.trun(1234.1234);
// num = 1234
Now to change something like 12345 to 12340 we'll have to remove some of the numeric value. We can find out much by converting to a string, pulling the last character, and converting back.
var num = 123456.12345;
var wholeNum = Math.trunc(num);
// wholeNum = 123456;
var toRemove = Number.parseInt(wholeNum.toString().slice(-1), 10);
// toRemove = 6
// slice(-1) gives us the right-most character of a string.
// Notice the ', 10' at the end, this is important to indicate which number base to use for parseInt.
var wholeNumEnding0 = wholeNum - toRemove;
// wholeNumEnding0 = 123450
Hopefully that's what you're looking to accomplish? I didn't perform any rounding here.
Note: I typed this at speed, excuse any mistakes, there might be better ways to do it too.
If you don't want to rely on a library, you could do something like the following:
var number = 100000.00000000000012422;
function FormatNumber(no){
no = no.toFixed(2);
no = no.toString().split('.');
var p1 = no[0];
p1 = p1.substring(0, p1.length - 3) + ',' + p1.substring(p1.length - 3);
no = p1 + '.' + no[1];
console.log(no);
}
FormatNumber(number);
The FormatNumber function takes a number as a parameter (you would probably want to expand that to include e.g. decimal places). It converts the number to the required decimal places, the turns it into a string and splits it by the decimal separator '.'.
The next step is to add a thousands separator three characters from the back, then it's just a matter of joining the remaining characters back together.
JSFiddle
If you wanted to get a ',' every 3 characters you could write a little more 'complex' formatter, something along the lines of the following:
no = no.toFixed(2);
no = no.toString().split('.');
var p1 = no[0];
var arr = [];
arr = p1.split("").reverse().join("").match(/[\s\S]{1,3}/g) || [];
arr = arr.reverse();
p1 = "";
for(var i = 0; i < arr.length; i++){
p1 += arr[i].split("").reverse().join("");
if(i != arr.length - 1){
p1 += ',';
}
}
no = p1 + '.' + no[1];
This method splits the number into an array by each number, reverses the array as we need to start from the end of the string to get accurate result.
Then we iterate the array of strings with 3 or less values by splitting the number into an array again, reversing it and joining back together and then appending to p1. If it's the last item, it doesn't add a comma.
Lastly we take the decimal and append to built string.
JSFiddle

using the digits of a number as an array

var number = 342345820139586830203845861938475676
var output = []
var sum = 0;
while (number) {
output.push(number % 10);
number = Math.floor(number/10);
}
output = output.reverse();
function addTerms () {
for (i = 0; i < output.length; i=i+2) {
var term = Math.pow(output[i], output[i+1]);
sum += term;
}
return sum;
}
document.write(output);
document.write("<br>");
document.write(addTerms());
I am trying to take that large number and split it into its digits. Then, find the sum of the the first digit raised to the power of the 2nd, 3rd digit raiseed to the 4th, 5th raised to the 6th and so on. for some reason, my array is returning weird digits, causing my sum to be off. the correct answer is 2517052. Thanks
You're running into precision issues within JavaScript. Just evaluate the current value of number before you start doing anything, and the results may surprise you:
>>> var number = 342345820139586830203845861938475676; number;
3.423458201395868e+35
See also: What is JavaScript's highest integer value that a Number can go to without losing precision?
To resolve your issue, I'd store your input number as an array (or maybe even a string), then pull the digits off of that.
This will solve your calculation with the expected result of 2517052:
var number = "342345820139586830203845861938475676";
var sum = 0;
for(var i=0; i<number.length; i=i+2){
sum += Math.pow(number.charAt(i), number.charAt(i+1));
}
sum;
JavaScript stores numbers in floating point format (commonly double). double can store precisely only 15 digits.
You can use string to store this large number.
As mentioned, this is a problem with numeric precision. It applies to all programming languages that use native numeric formats. Your problem works fine if you use a string instead
var number = '342345820139586830203845861938475676'
var digits = number.split('')
var total = 0
while (digits.length > 1) {
var [n, power] = digits.splice(0, 2)
total += Math.pow(n, power)
}
(the result is 2517052, byt the way!)
Cast the number as a string and then iterate through it doing your math.
var number = "342345820139586830203845861938475676";//number definition
var X = 0;//some iterator
var numberAtX = 0 + number.charAt(X);//number access
The greatest integer supported by Javascript is 9007199254740992. So that only your output is weird.
For Reference go through the link http://ecma262-5.com/ELS5_HTML.htm#Section_8.5
[edit] adjusted the answer based on Borodins comment.
Mmm, I think the result should be 2517052. I'd say this does the same:
var numbers = '342345820139586830203845861938475676'.split('')
,num = numbers.splice(0,2)
,result = Math.pow(num[0],num[1]);
while ( (num = numbers.splice(0,2)) && num.length ){
result += Math.pow(num[0],num[1]);
}
console.log(result); //=> 2517052
The array methods map and reduce are supported in modern browsers,
and could be worth defining in older browsers. This is a good opportunity,
if you haven't used them before.
If you are going to make an array of a string anyway,
match pairs of digits instead of splitting to single digits.
This example takes numbers or strings.
function sumPower(s){
return String(s).match(/\d{2}/g).map(function(itm){
return Math.pow(itm.charAt(0), itm.charAt(1));
}).reduce(function(a, b){
return a+b;
});
}
sumPower('342345820139586830203845861938475676');
alert(sumPower(s))
/*
returned value:(Number)
2517052
*/

Novice Javascript query about bad input

I am making a simple tip calculator to help myself learn Javascript. The problem I can't solve is how to compensate for "bad input".
In the code below if the user prefaces the numeric input amount with a dollar sign $, the result is NAN.
function tipAmount(){
var dinner=prompt("How much was dinner?");
result = dinner*.10;
alert("Your tip is " +"$"+result );
}
How do I fix that.
You can try to parse out the numeric value with a regular expression:
var match = dinner.match(/\d+\.?\d*/); // parse with a regular expression
if(!match) { // not able to parse
alert("wrong");
}
var price = +match[0]; // convert to a number
result = price * .10;
The regular expression /\d+\.?\d*/ means: one or more digits, and possibly a dot with other digits following. This means that if e.g. dinner is "$1.23", price will be the number 1.23. The same goes for "$ 1.23" or "1.23 dollar" etc - the number will be parsed out with the pattern defined by the regular expression.
The simplest way would be to parse the input into a float, and see if NaN is returned.
if (isNaN(parseFloat(dinner)))
alert("Bad Input")
Just note that 45.2WWW will return 45.2, and so the above will pass.
If you want to make sure what the user typed in is exactly a number, you could do something like this:
var str = '3.445';
var num = parseFloat(str);
if (isNaN(num) || str.length !== num.toString().length)
alert("Bad Input");
try to parse the input as float or integer depending on your needs:
var dinner = parseFloat(prompt("How much was dinner?"));
or
var dinner = parseInt(prompt("How much was dinner?"));
this functions return 0 whether they unable to parse the input as number
Given your approach of using alerts, the following will work:
function tipAmount() {
var dinner=prompt("How much was dinner?");
//convert "dinner" to a number, stripping out any non numeric data
dinner = Number(dinner.replace(/[^0-9\.]+/g,""));
//any unknown data will convert to 0
if(dinner <= 0) {
alert("Please enter a valid amount");
return false;
}
var result = dinner*.10;
alert("Your tip is " +"$"+result );
return true;
}
Please tip more!
Just check if the value is numeric - Javascript's isNaN:
if (isNaN(dinner)) {
alert('Bad number, bub.');
return;
}
Or, if you want to allow users to type in both - just number or an amount with $ at the beginning, you can check for first char:
if( dinner.charAt(0) == '$' )
{
dinner = dinner.substring(1);
}
This way, whenever user types $, your app will just remove it. If they type a normal number it will calculate the tip for you...

How to parse float with two decimal places in javascript?

I have the following code. I would like to have it such that if price_result equals an integer, let's say 10, then I would like to add two decimal places. So 10 would be 10.00.
Or if it equals 10.6 would be 10.60. Not sure how to do this.
price_result = parseFloat(test_var.split('$')[1].slice(0,-1));
You can use toFixed() to do that
var twoPlacedFloat = parseFloat(yourString).toFixed(2)
If you need performance (like in games):
Math.round(number * 100) / 100
It's about 100 times as fast as parseFloat(number.toFixed(2))
http://jsperf.com/parsefloat-tofixed-vs-math-round
When you use toFixed, it always returns the value as a string. This sometimes complicates the code. To avoid that, you can make an alternative method for Number.
Number.prototype.round = function(p) {
p = p || 10;
return parseFloat( this.toFixed(p) );
};
and use:
var n = 22 / 7; // 3.142857142857143
n.round(3); // 3.143
or simply:
(22/7).round(3); // 3.143
To return a number, add another layer of parentheses. Keeps it clean.
var twoPlacedFloat = parseFloat((10.02745).toFixed(2));
If your objective is to parse, and your input might be a literal, then you'd expect a float and toFixed won't provide that, so here are two simple functions to provide this:
function parseFloat2Decimals(value) {
return parseFloat(parseFloat(value).toFixed(2));
}
function parseFloat2Decimals(value,decimalPlaces) {
return parseFloat(parseFloat(value).toFixed(decimalPlaces));
}
ceil from lodash is probably the best
_.ceil("315.9250488",2)
_.ceil(315.9250488,2)
_.ceil(undefined,2)
_.ceil(null,2)
_.ceil("",2)
will work also with a number and it's safe
You can use .toFixed() to for float value 2 digits
Exampale
let newValue = parseFloat(9.990000).toFixed(2)
//output
9.99
I have tried this for my case and it'll work fine.
var multiplied_value = parseFloat(given_quantity*given_price).toFixed(3);
Sample output:
9.007
parseFloat(parseFloat(amount).toFixed(2))
You have to parse it twice. The first time is to convert the string to a float, then fix it to two decimals (but the toFixed returns a string), and finally parse it again.
Please use below function if you don't want to round off.
function ConvertToDecimal(num) {
num = num.toString(); //If it's not already a String
num = num.slice(0, (num.indexOf(".")) + 3); //With 3 exposing the hundredths place
alert('M : ' + Number(num)); //If you need it back as a Number
}
For what its worth: A decimal number, is a decimal number, you either round it to some other value or not. Internally, it will approximate a decimal fraction according to the rule of floating point arthmetic and handling. It stays a decimal number (floating point, in JS a double) internally, no matter how you many digits you want to display it with.
To present it for display, you can choose the precision of the display to whatever you want by string conversion. Presentation is a display issue, not a storage thing.
#sd
Short Answer: There is no way in JS to have Number datatype value with trailing zeros after a decimal.
Long Answer: Its the property of toFixed or toPrecision function of JavaScript, to return the String. The reason for this is that the Number datatype cannot have value like a = 2.00, it will always remove the trailing zeros after the decimal, This is the inbuilt property of Number Datatype. So to achieve the above in JS we have 2 options
Either use data as a string or
Agree to have truncated value with case '0' at the end ex 2.50 -> 2.5.
You can store your price as a string
You can use
Number(string)
for your calculations.
example
Number("34.50") == 34.5
also
Number("35.65") == 35.65
If you're comfortable with the Number function , you can go with it.
Try this (see comments in code):
function fixInteger(el) {
// this is element's value selector, you should use your own
value = $(el).val();
if (value == '') {
value = 0;
}
newValue = parseInt(value);
// if new value is Nan (when input is a string with no integers in it)
if (isNaN(newValue)) {
value = 0;
newValue = parseInt(value);
}
// apply new value to element
$(el).val(newValue);
}
function fixPrice(el) {
// this is element's value selector, you should use your own
value = $(el).val();
if (value == '') {
value = 0;
}
newValue = parseFloat(value.replace(',', '.')).toFixed(2);
// if new value is Nan (when input is a string with no integers in it)
if (isNaN(newValue)) {
value = 0;
newValue = parseFloat(value).toFixed(2);
}
// apply new value to element
$(el).val(newValue);
}
Solution for FormArray controllers
Initialize FormArray form Builder
formInitilize() {
this.Form = this._formBuilder.group({
formArray: this._formBuilder.array([this.createForm()])
});
}
Create Form
createForm() {
return (this.Form = this._formBuilder.group({
convertodecimal: ['']
}));
}
Set Form Values into Form Controller
setFormvalues() {
this.Form.setControl('formArray', this._formBuilder.array([]));
const control = <FormArray>this.resourceBalanceForm.controls['formArray'];
this.ListArrayValues.forEach((x) => {
control.push(this.buildForm(x));
});
}
private buildForm(x): FormGroup {
const bindvalues= this._formBuilder.group({
convertodecimal: x.ArrayCollection1? parseFloat(x.ArrayCollection1[0].name).toFixed(2) : '' // Option for array collection
// convertodecimal: x.number.toFixed(2) --- option for two decimal value
});
return bindvalues;
}
I've got other solution.
You can use round() to do that instead toFixed()
var twoPlacedFloat = parseFloat(yourString).round(2)
The solution that work for me is the following
parseFloat(value)

Comparing negative numbers in javascript

I'm sure this is a simple problem, but I'm comparing negative numbers in javascript i.e.:
var num1 = -83.778;
var num2 = -83.356;
if(num1 < num2)
{
// Take action 1
}
else
{
// Take action 2
}
This script will always take action 2, even though num1 is less than num2. Whats going on here?
How does if (parseFloat(num1) < parseFloat(num2)) work? Maybe your numbers are turning into strings somewhere.
This case also works when we want to compare signed characters for both positive and negative numbers. For my case i had numbers like +3, +4, 0, -1 etc..
Directly using if(num1 > num2) would compare these values as string and we would get output of string comparision.
Thus to compare signed numbers., compare them via if (parseFloat(num1) < parseFloat(num2))
I have the same issue. Workaround for that:
var num1 = -83.778;
var num2 = -83.356;
if((num1 - num2) < 0)
{
// Take action 1
}
else
{
// Take action 2
}
Now Ation 1 will be used.

Categories