JavaScript Math.round: Doesnt round object to 1 decimal - javascript

I have objects in array:
x[{a=2.99, b=5.11}{a=4.99, b=2.11}]
And I want it to display 1 decimal with Math round, as I use Math.round(x[0].a*10)/10; it displays 3, while it works fine if I use just numbers as Math.round(2.99*10)/10.
Why is that?

please try the below code
x[0].a.toString().match(/^-?\d+(?:\.\d{0,2})?/)[0]
you can round off to 1 by changing regex patter from {0, 2} to {0, 1}

Thiss might work -- Math.floor() and toFixed(1) are the keys here... rounding will cause the original input to change to the nearest integer.
function roundToTenth(inputVal) {
return Math.floor(inputVal * 10) * 0.1;
}
console.log(roundToTenth(2.99).toFixed(1));
Division is slower than multiplication is generally - and definitely using Regular Expression Matching is going to be slower than multiplication is....
All I'm doing in the code above is saying "Take the number times 10 and then turn it into a straight Integer with no Decimals,
so
2.99 * 10 = 29.9 which then becomes 29
finally, since I use the operation * 0.1 it becomes a float like 2.900000004 and I use toFixed(1) to strip out all those pesky 0s at the end

Related

JavaScript: Rounding Down in .5 Cases

I am in a situation where a JavaScript function produces numbers, such as 2.5. I want to have these point five numbers rounded down to 2, rather than the result of Math.round, which will always round up in such cases (ignoring the even odd rule), producing 2. Is there any more elegant way of doing this than subtracting 0.01 from the number before rounding? Thanks.
Just negate the input and the output to Math.round:
var result = -Math.round(-num);
In more detail: JavaScript's Math.round has the unusual property that it rounds halfway cases towards positive infinity, regardless of whether they're positive or negative. So for example 2.5 will round to 3.0, but -2.5 will round to -2.0. This is an uncommon rounding mode: it's much more common to round halfway cases either away from zero (so -2.5 would round to -3.0), or to the nearest even integer.
However, it does have the nice property that it's trivial to adapt it to round halfway cases towards negative infinity instead: if that's what you want, then all you have to do is negate both the input and the output:
Example:
function RoundHalfDown(num) {
return -Math.round(-num);
}
document.write("1.5 rounds to ", RoundHalfDown(1.5), "<br>");
document.write("2.5 rounds to ", RoundHalfDown(2.5), "<br>");
document.write("2.4 rounds to ", RoundHalfDown(2.4), "<br>");
document.write("2.6 rounds to ", RoundHalfDown(2.6), "<br>");
document.write("-2.5 rounds to ", RoundHalfDown(-2.5), "<br>");
do this:
var result = (num - Math.Floor(num)) > 0.5 ? Math.Round(num):Math.Floor(num);
Another way exists that is to use real numbers (instead of 0.2 use 20, 0.02 use 2, etc.), then add floatingPoints variable that will divide the result (in your case it's 2). As a result you can operate as Number/(10^floatingPoints).
This solution is wide across Forex companies.
You can also use this function to round with no decimal part and .5 down rule (Only positive numbers):
function customRound(number) {
var decimalPart = number % 1;
if (decimalPart === 0.5)
return number - decimalPart;
else
return Math.round(number);
}
And sorry for my english.

Comparing floating-point to integers in Javascript

So I ran across a small piece of code that looks like this
Math.random() * 5 | 0 and was confused by what it did.
after some inspecting, it seems like the comparison turns the decimal into an integer. is that right? and so the piece of code is another way is saying give me a random number between 0 and 4. Can anyone explain why that is?
1) Math.random() function always return decimal value and will be less than one. Ex - 0.2131313
random()
Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
2) Math.random()*5 will always be less than 5. (maxvalue - 4.99999).
3) The bitwise operator '|' will truncate the decimal values.
Edit : Paul is correct. '|' does more than just truncate.
But in this case Math.random()*5|0 - It truncates the decimal and returns the integar.

How can I parse a string as an integer and keep decimal places if they are zeros?

I have these strings: "59.50" & "30.00"
What I need to do is convert them to integers but keep the trailing zeros at the end to effectively return:
59.50
30.00
I've tried:
Math.round(59.50 * 1000) / 1000
Math.round(30.00 * 1000) / 1000
but ended up with
59.5
30
I'm assuming I need to use a different method than Math.round as this automatically chops off trailing zeros.
I need to keep these as integers as they need to be multiplied with other integers and keep two decimals points. T thought this would be fairly straight forward but after a lot of searching I can't seem to find a solution to exactly what I need.
Thanks!
Your premise is flawed. If you parse a number, you are converting it to its numerical representation, which by definition doesn't have trailing zeros.
A further flaw is that you seem to think you can multiply two numbers together and keep the same number of decimal places as the original numbers. That barely makes sense.
It sounds like this might be an XY Problem, and what you really want to do is just have two decimal places in your result.
If so, you can use .toFixed() for this:
var num = parseFloat("59.50");
var num2 = parseFloat("12.33");
var num3 = num * num2
console.log(num3.toFixed(2)); // 733.64
Whenever you want to display the value of the variable, use Number.prototype.toFixed(). This function takes one argument: the number of decimal places to keep. It returns a string, so do it right before viewing the value to the user.
console.log((123.4567).toFixed(2)); // logs "123.46" (rounded)
To keep the decimals - multiply the string by 1
example : "33.01" * 1 // equals to 33.01
Seems you are trying to retain the same floating point, so better solution will be some thing like
parseFloat(string).toFixed(string.split('.')[1].length);
If you want numbers with decimal points, you are not talking about integers (which are whole numbers) but floating point numbers.
In Javascript all numbers are represented as floating point numbers.
You don't need the trailing zeros to do calculations. As long as you've got all the significant digits, you're fine.
If you want to output your result with a given number of decimal values, you can use the toFixed method to transform your number into a formatted string:
var num = 1.5
var output = num.toFixed(2) // '1.50'
// the number is rounded
num = 1.234
output = num.toFixed(2) // '1.23'
num = 1.567
output = num.toFixed(2) // '1.57'
Here's a more detailed description of toFixed: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed

Javascript precision while dividing

Is there a way to determine whether dividing one number by another will result in whole number in JavaScript? Like 18.4 / 0.002 gives us 9200, but 18.4 / 0.1 gives us 183.99999999999997. The problem is that both of them may be any float number (like 0.1, 0.01, 1, 10, ...) which makes it impossible to use the standard function modulo or trying to subtract, and floating point precision issues mean we will sometimes get non-whole-number results for numbers that should be whole, or whole-number results for ones that shouldn't be.
One hacky way would be
Convert both numbers to strings with toString()
Count the precision points (N) by stripping off the characters before the . (including the .) and taking the length of the remaining part
Multiply with 10^N to make them integers
Do modulo and get the result
Updated Demo: http://jsfiddle.net/9HLxe/1/
function isDivisible(u, d) {
var numD = Math.max(u.toString().replace(/^\d+\./, '').length,
d.toString().replace(/^\d+\./, '').length);
u = Math.round(u * Math.pow(10, numD));
d = Math.round(d * Math.pow(10, numD));
return (u % d) === 0;
}
I don't think you can do that with JavaScript's double-precision floating point numbers, not reliably across the entire range. Maybe within some constraints you could (although precision errors crop up in all sorts of -- to me -- unexpected locations).
The only way I see is to use any of the several "big decimal" libraries for JavaScript, that don't use Number at all. They're slower, but...
I Assume that you want the reminder to be zero when you perform the division.
check for the precision of the divisor, and multiply both divisor and divident by powers of 10
for example
you want to check for 2.14/1.245 multiply both divident and divisor by 1000 as 1.245 has 3 digits precision, now the you would have integers like 2140/1245 to perform modulo
Divide first number by second one and check if result is integer ?
Only, when you check that the result is integer, you need to specify a rounding threshold.
In javascript, 3.39/1.13 is slightly more than 3.
Example :
/**
* Returns true iif a is an integer multiple of b
*/
function isIntegerMultiple(a, b, precision) {
if (precision === undefined) {
precision = 10;
}
var quotient = a / b;
return Math.abs(quotient - Math.round(quotient)) < Math.pow(10, -precision);
}
console.log(isIntegerMultiple(2, 1)); // true
console.log(isIntegerMultiple(2.4, 1.2)); // true
console.log(isIntegerMultiple(3.39, 1.13)); // true
console.log(isIntegerMultiple(3.39, 1.13, 20)); // false
console.log(isIntegerMultiple(3, 2)); // false
Have a look at this for more details on floating point rounding issues: Is floating point math broken?

2.9999999999999999 >> .5?

I heard that you could right-shift a number by .5 instead of using Math.floor(). I decided to check its limits to make sure that it was a suitable replacement, so I checked the following values and got the following results in Google Chrome:
2.5 >> .5 == 2;
2.9999 >> .5 == 2;
2.999999999999999 >> .5 == 2; // 15 9s
2.9999999999999999 >> .5 == 3; // 16 9s
After some fiddling, I found out that the highest possible value of two which, when right-shifted by .5, would yield 2 is 2.9999999999999997779553950749686919152736663818359374999999¯ (with the 9 repeating) in Chrome and Firefox. The number is 2.9999999999999997779¯ in IE.
My question is: what is the significance of the number .0000000000000007779553950749686919152736663818359374? It's a very strange number and it really piqued my curiosity.
I've been trying to find an answer or at least some kind of pattern, but I think my problem lies in the fact that I really don't understand the bitwise operation. I understand the idea in principle, but shifting a bit sequence by .5 doesn't make any sense at all to me. Any help is appreciated.
For the record, the weird digit sequence changes with 2^x. The highest possible values of the following numbers that still truncate properly:
for 0: 0.9999999999999999444888487687421729788184165954589843749¯
for 1: 1.9999999999999999888977697537484345957636833190917968749¯
for 2-3: x+.99999999999999977795539507496869191527366638183593749¯
for 4-7: x+.9999999999999995559107901499373838305473327636718749¯
for 8-15: x+.999999999999999111821580299874767661094665527343749¯
...and so forth
Actually, you're simply ending up doing a floor() on the first operand, without any floating point operations going on. Since the left shift and right shift bitwise operations only make sense with integer operands, the JavaScript engine is converting the two operands to integers first:
2.999999 >> 0.5
Becomes:
Math.floor(2.999999) >> Math.floor(0.5)
Which in turn is:
2 >> 0
Shifting by 0 bits means "don't do a shift" and therefore you end up with the first operand, simply truncated to an integer.
The SpiderMonkey source code has:
switch (op) {
case JSOP_LSH:
case JSOP_RSH:
if (!js_DoubleToECMAInt32(cx, d, &i)) // Same as Math.floor()
return JS_FALSE;
if (!js_DoubleToECMAInt32(cx, d2, &j)) // Same as Math.floor()
return JS_FALSE;
j &= 31;
d = (op == JSOP_LSH) ? i << j : i >> j;
break;
Your seeing a "rounding up" with certain numbers is due to the fact the JavaScript engine can't handle decimal digits beyond a certain precision and therefore your number ends up getting rounded up to the next integer. Try this in your browser:
alert(2.999999999999999);
You'll get 2.999999999999999. Now try adding one more 9:
alert(2.9999999999999999);
You'll get a 3.
This is possibly the single worst idea I have ever seen. Its only possible purpose for existing is for winning an obfusticated code contest. There's no significance to the long numbers you posted -- they're an artifact of the underlying floating-point implementation, filtered through god-knows how many intermediate layers. Bit-shifting by a fractional number of bytes is insane and I'm surprised it doesn't raise an exception -- but that's Javascript, always willing to redefine "insane".
If I were you, I'd avoid ever using this "feature". Its only value is as a possible root cause for an unusual error condition. Use Math.floor() and take pity on the next programmer who will maintain the code.
Confirming a couple suspicions I had when reading the question:
Right-shifting any fractional number x by any fractional number y will simply truncate x, giving the same result as Math.floor() while thoroughly confusing the reader.
2.999999999999999777955395074968691915... is simply the largest number that can be differentiated from "3". Try evaluating it by itself -- if you add anything to it, it will evaluate to 3. This is an artifact of the browser and local system's floating-point implementation.
If you wanna go deeper, read "What Every Computer Scientist Should Know About Floating-Point Arithmetic": https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Try this javascript out:
alert(parseFloat("2.9999999999999997779553950749686919152736663818359374999999"));
Then try this:
alert(parseFloat("2.9999999999999997779553950749686919152736663818359375"));
What you are seeing is simple floating point inaccuracy. For more information about that, see this for example: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems.
The basic issue is that the closest that a floating point value can get to representing the second number is greater than or equal to 3, whereas the closes that the a float can get to the first number is strictly less than three.
As for why right shifting by 0.5 does anything sane at all, it seems that 0.5 is just itself getting converted to an int (0) beforehand. Then the original float (2.999...) is getting converted to an int by truncation, as usual.
I don't think your right shift is relevant. You are simply beyond the resolution of a double precision floating point constant.
In Chrome:
var x = 2.999999999999999777955395074968691915273666381835937499999;
var y = 2.9999999999999997779553950749686919152736663818359375;
document.write("x=" + x);
document.write(" y=" + y);
Prints out: x = 2.9999999999999996 y=3
The shift right operator only operates on integers (both sides). So, shifting right by .5 bits should be exactly equivalent to shifting right by 0 bits. And, the left hand side is converted to an integer before the shift operation, which does the same thing as Math.floor().
I suspect that converting 2.9999999999999997779553950749686919152736663818359374999999
to it's binary representation would be enlightening. It's probably only 1 bit different
from true 3.
Good guess, but no cigar.
As the double precision FP number has 53 bits, the last FP number before 3 is actually
(exact): 2.999999999999999555910790149937383830547332763671875
But why it is
2.9999999999999997779553950749686919152736663818359375
(and this is exact, not 49999... !)
which is higher than the last displayable unit ? Rounding. The conversion routine (String to number) simply is correctly programmed to round the input the the next floating point number.
2.999999999999999555910790149937383830547332763671875
.......(values between, increasing) -> round down
2.9999999999999997779553950749686919152736663818359375
....... (values between, increasing) -> round up to 3
3
The conversion input must use full precision. If the number is exactly the half between
those two fp numbers (which is 2.9999999999999997779553950749686919152736663818359375)
the rounding depends on the setted flags. The default rounding is round to even, meaning that the number will be rounded to the next even number.
Now
3 = 11. (binary)
2.999... = 10.11111111111...... (binary)
All bits are set, the number is always odd. That means that the exact half number will be rounded up, so you are getting the strange .....49999 period because it must be smaller than the exact half to be distinguishable from 3.
I suspect that converting 2.9999999999999997779553950749686919152736663818359374999999 to its binary representation would be enlightening. It's probably only 1 bit different from true 3.
And to add to John's answer, the odds of this being more performant than Math.floor are vanishingly small.
I don't know if JavaScript uses floating-point numbers or some kind of infinite-precision library, but either way, you're going to get rounding errors on an operation like this -- even if it's pretty well defined.
It should be noted that the number ".0000000000000007779553950749686919152736663818359374" is quite possibly the Epsilon, defined as "the smallest number E such that (1+E) > 1."

Categories

Resources