Why do some rounded JavaScript values round the wrong way? - javascript

I have tried numerous scripts after 1 hour and half of googling and all have either given me the wrong rounded number or the wrong value altogether. These are two scripts I tried.
FIRST TRY:
Number.prototype.round = function(p) {
p = p || 10;
return parseFloat( this.toFixed(p) );
};
SECOND TRY:
function roundNumber(number, decimals) {
var newnumber = new Number(number+'').toFixed(parseInt(decimals));
return parseFloat(newnumber);
}
Some Example Outputs that I get from both:
0.22 -> 0.21480000000000005 (bad) should be 21
0.43 -> 0.4284 (good) 43 is right
What am I doing wrong? Any help would be appreciated as this has had me poking for too long.

Why not use something like this:
Math.round(yourNumber * 100) / 100;
This will round it to two decimal places, the same question was more or less answered here - Round to at most 2 decimal places (only if necessary)
Here is a small example
function round(num){
var result = Math.round(num * 100) / 100;
return console.log(result);
}
round(0.4284);
The Fiddle is here to test: https://jsfiddle.net/ToreanJoel/bLzz2mL8/

Related

JavaScript returns different output for same parameter values

I have the below JavaScript code to round the values, which returns different result in similar cases. This is being called through a tool.
var precision = -1;
/**
* Initialization
*/
function _init()
{
precision = 8;
}
case1
function RoundUp(number, num_digits)
{
var shift = Math.pow(10, num_digits);
var rounded = Math.ceil(number * shift) / shift;
rounded = (precision>-1) ? Number(rounded.toFixed(precision)) : rounded;
return rounded;
}
case2
function RoundUp(110, 1)
{
var shift = Math.pow(10, num_digits);
var rounded = Math.ceil(number * shift) / shift;
rounded = (precision>-1) ? Number(rounded.toFixed(precision)) : rounded;
return rounded;
}
If we directly pass some parameter values, ex (110,1), it returns 110. (CASE2) But when we pass the same parameter values indirectly through some variable (CASE1), the output changes to 111 for some reason.
Here, number = 110 and num_digits = 1
I cant figure out why this is the case. Can someone please help. Pardon me, but I am new to JavaScript.
Thanks
It's not entirely clear what you're actually trying to do. However, you appear to have two problems.
1. Syntax error
This line:
function RoundUp(110, 1)
is not a legal JavaScript statement. You cannot pass values to a function while you're defining it. What JavaScript thinks you're trying to do here is define a function with two parameters called 110 and 1, which are both illegal parameter names, so you get a syntax error.
2. Math
I'm assuming that what you're trying to do is this:
roundUp(12345, 1) => 20000
roundUp(12345, 2) => 13000
roundUp(12345, 3) => 12400
roundUp(12345, 4) => 12350 etc
If that's correct, then your math is wrong. Try this instead:
function roundUp(number, numDigits) {
var shift = Math.pow(10, number.toString().length - numDigits);
var rounded = Math.ceil(number / shift) * shift;
rounded = (precision>-1) ? Number(rounded.toFixed(precision)) : rounded;
return rounded;
}
This will not work for floating-point numbers, but if you only need to deal with integers it's fine.

How to remove trailing decimals without rounding up?

For example, I have a number 123.429. How can I remove the trailing decimals without rounding up to two decimal place.
Hence, I need the number to be up to two d.p. i.e 123.42.
Definitely toFixed() method or Math.round(num * 100) / 100 cannot be used in this situation.
The function you want is Math.floor(x) to remove decimals without rounding up (so floor(4.9) = 4).
var number = Math.floor(num * 100) / 100;
Edit: I want to update my answer because actually, this rounds down with negative numbers:
var Math.floor(-1.456 * 100) / 100;
-1.46
However, since Javascript 6, they have introduced the Math.trunc() function which truncates to an int without rounding, as expected. You can use it the same way as my proposed usage of Math.floor():
var number = Math.trunc(num * 100) / 100;
Alternatively, the parseInt() method proposed by awe works as well, although requires a string allocation.
var number = parseInt('' + (num * 100)) / 100;
You can convert it to a string and then simply truncate the string two places after the decimal, e.g.:
var s = String(123.429);
s.substring(0, s.indexOf('.') + 3); // "123.42"
Please note that there's no guarantee if you convert that final string back into a number that it'll be exactly representable to those two decimal places - computer floating point math doesn't work that way.
another v. cool solution is by using | operator
let num = 123.429 | 0
let num = 123.429 | 0
console.log(num);
let's get the variable name as "num"
var num = 123.429;
num=num*100;
num=num.toString();
num=num.split(".");
num=parseInt(num[0]);
num=num/100;
value of the num variable will be 12.42
Try this
number = parseFloat(number).toFixed(12);
number = number.substring(0, number.indexOf('.') + 3);
return parseFloat(number);
Not the fastest solution but the only one that handles an edge case like 0.0006*10000 = 5.999999999 properly, i.e. if you want to truncate to 4 decimal places and the value is exactly 0.0006, then using Math.trunc(0.0006 * (10 ** 4))/(10 ** 4) gives you 0.0005.

Rounding to two decimal places issue

I am loading numeric values to 2 decimal places using Javascript. All values seem okay, apart from £299.90 and £499.90, which loads as £299.9 and £499.9
Current code:
//ROUNDING FUNCTION
function round(num, decimals) {
return Math.round(num * Math.pow(10, decimals)) / Math.pow(10, decimals);
}
//LOADING VALUES - Line cost variable is £49.99/£29.99 * 10
jQuery(".content").html("£" + round(lineCost, 2));
What I have tried:
jQuery(".content").html(parseFloat(lineCost * 100) / 100).toFixed(2);
jQuery(".content").html(Number(lineCost).toFixed(2));
Any ideas?
Thanks.
You can try with toFixed method on a float/integer value:
var value = 0.127456;
value.toFixed(2);
Output:
0.13
In your case:
jQuery(".content").html("£" + lineCost.toFixed(2));
If lineCost is a string, parse it to float:
jQuery(".content").html("£" + parseFloat(lineCost).toFixed(2));
You are over complicating it.
It just requires
parseFloat(lineCost).toFixed(2);
Here is a demo fiddle.
Actually rounding means to convert a number like 10.5 to 11 or 12.49 to 12 so you should not round the number if you want to use a float with decimals, instead you should just use something like this:
var lineCost = 12.5;
parseFloat(lineCost).toFixed(2);

Javascript Number Formatting

Certainly a stupid question, please forgive me. My customer wants decimal numbers to display with five digits. For example: 100.34 or 37.459. I was accomplishing this with val.toPrecision (5);; however, when my numbers get really small, I stop getting what I want. For example, if my number is 0.000347, it displays 0.00034700. Now, I understand why it's doing this, but what I don't know is how to get it to display 0.0003. Any thoughts?
Math.round(0.000347 * 1e4) / 1e4
Or with toFixed:
Number.prototype.toNDigits = function (n) {
return (Math.abs(this) < 1) ?
this.toFixed(n - 1) :
this.toPrecision(n);
};
http://jsfiddle.net/HeQtH/6/
Our problem is with numbers less than 1 obviously. So catch them and deal them separately
function SetPrecisionToFive(n){
return (n > 1) ? n.toPrecision (5) : (Math.round(n * 1e4) / 1e4).toString();
}
You can use the toFixed method to accomplish this. For example: (0.000347).toFixed(4)
The Javascript toFixed() function will truncate small numbers to a fixed decimal precision, eg:
var num = .0000350;
var result = num.toFixed(5); // result will equal .00003

javascript correctly rounding up to two decimals, impossible?

In php, we have number_format(). Passing it a value such as:
number_format(3.00 * 0.175, 2);
returns 0.53, which is what I would expect.
However, in JavaScript using toFixed()
var num = 3.00 * 0.175;
num.toFixed(2);
returns 0.52.
Ok, so perhaps toFixed is not what I want... Maybe something like this...
var num = 3.17 * 0.175;
var dec = 2;
Math.round( Math.round( num * Math.pow( 10, dec + 1 ) ) / Math.pow( 10, 1 ) ) / Math.pow(10,dec);
No, that doesn't work either. It will return 0.56.
How can I get a number_format function in JavaScript that doesn't give an incorrect answer?
Actually I did find an implementation of number_format for js, http://phpjs.org/functions/number_format, but it suffers from the same problem.
What is going on here with JavaScript rounding up? What am I missing?
JavaScript does badly with floating point numbers (as do many other languages).
When I run
3.000 * 0.175
In my browser, I get
0.5249999999999999
Which will not round up to 0.525 with Math.round. To circumvent this, you kind of have to multiply both sides until you get them to be integers (relatively easy, knowing some tricks help though).
So to do this we can say something like this:
function money_multiply (a, b) {
var log_10 = function (c) { return Math.log(c) / Math.log(10); },
ten_e = function (d) { return Math.pow(10, d); },
pow_10 = -Math.floor(Math.min(log_10(a), log_10(b))) + 1;
return ((a * ten_e(pow_10)) * (b * ten_e(pow_10))) / ten_e(pow_10 * 2);
}
This may look kind of funky, but here's some pseudo-code:
get the lowest power of 10 of the arguments (with log(base 10))
add 1 to make positive powers of ten (covert to integers)
multiply
divide by conversion factor (to get original quantities)
Hope this is what you are looking for. Here's a sample run:
3.000 * 0.175
0.5249999999999999
money_multiply(3.000, 0.175);
0.525
The toFixed function is working correctly. It truncates past the specified amount of fraction digits.
Why all the powers?? Why not just add slightly less than 1/2 a cent and round:
(3.00 * 0.175 + 0.0049).toFixed(2)
Never had any accountants complain about the output.
I think the problem you are encountering is with floating point math as opposed to the rounding itself.
Using the firebug console for testing, logging the result of 3.00 * 0.175 given 0.524999.... So rounding this number down is actually correct.
I don't know if there is a good solution to your problem, but in my experience when working with currency: it is easier to work in the smallest unit (cents) and then convert for display.
Why didn't you just use Math.round( num * Math.pow( 10, dec ) ) / Math.pow( 10, dec) )?
EDIT: I see, the problem is that 3 * 0.175 gives you 0.52499999999999991, leading you to want an additional rounding step. Maybe just adding a small amount would work:
Math.round( num * Math.pow( 10, dec ) + 0.000000001 ) / Math.pow( 10, dec) )
I know this is old but this is how I usually solve a rounding problem. This can be put in a function easily but for now I just put in simple vars for right now. If this doesn't work you could use money_format() or number_format() as a start from php.js (more info below).
var n = (3.00 * 0.175);
n = Math.round(n * Math.pow(10, 3)) / Math.pow(10, 3);
Math.round(n*100)/100;
comes out to 0.53 (0.5249999999999999)
var n = (3.00 * 0.175);
n = Math.round(n * Math.pow(10, 3)) / Math.pow(10, 3);
Math.round(n*100)/100;
comes out to 0.56 (0.55475)
It also looks like the php.js repo is being kept up on GitHub https://github.com/kvz/phpjs so if there isn't a function that is not performing correctly an issue can be submitted.
Anyway figured this information may help someone looking later on.

Categories