Why does someNum - Math.floor(someNum) give me different decimal numbers - javascript

I have some simple javascript which I want to use to determine if a number needs to be rounded.
Example: User enters 1.2346 and the number is rounded to 1.235 and a message should be displayed to the user informing them that the number was rounded.
Rounding the number isn't the issue, but showing the error message to the user is. I need to find the number of digits after the decimal point.
I use the following code to retrieve the decimal places off of a string. I then count the length of the variable to get the decimal places:
var dp = field_value - Math.floor(field_value);
However, When I test this I enter 1.23 for the value of field_value. When I check the value of field value it is indeed 1.23. When I check the value of Math.floor(field_value) it is indeed 1. But then I check the value of dp and it turns out to be 0.22999999999999998
Why does this subtraction not work the way it is expected?

Problem is given by the fact that floating numbers have a finite representation, take a look here and you will understand how and why.
If problem with roundings is just for printing that number you could use something like sprintf for JS that allows you to format float output as you nee.

Trying to do anything too exact and specific with the representation of a floating point number is always going to a tricky situation. As other people have pointed out, this is a property of IEEE-754 floating point standard. Besides treating it as a string and trying to analyze the number, you could also just round it deterministically to the format you want, doing something like:
function roundFloat(num, decimalPlaces) {
multiplier = Math.pow(10, decimalPlaces);
return Math.round(num * multiplier) / multiplier;
}

Related

round decimals in javascript

I use to round decimal in javascript like this:
lat = e.latLng.lat().toFixed(8);
works most of the times but some times I get more decimals as a result.
For example I get 8.341621100000001 from 8.341621100000001 that means that the number is not rounded. Issue is that I need to save it in the db with a 8 decimals precision and that this values are accepted by an API only with a 8 decimals precision.
How can I fix my code to have always it rounded to 8 decimals. We are talking about latitude and longitudes if it can help. Note that I know about issues with working with decimals in javascript but this seems to me like just an issue about using the wrong tool (sometimes it round sometimes it doesn't).
Thanks!
.toFixed() returns a String representing a rounded number, not a Number. As soon as you continue to use the value like a Number again (thanks to JavaScript's lax conversion rules), you re-enter the realm of floating-point inaccuracy.
If the API accepts strings for the numbers, then just call .toFixed(8) where you pass the value to the API.
You can call .toFixed() then send the result through parseFloat():
parseFloat(8.341621100000001.toFixed(8)); // 8.3416211
Or define a helped function to do it for you:
function clip(value, precision) {
return parseFloat(value.toFixed(precision));
};
clip(8.341621100000001, 8); // 8.3416211

toFixed function on large numbers

I have following number with e+ on it
9.074701047887939e+304
I want to take only 9.07
So I tried below , but its not working , its returning full output
console.log(parseFloat(9.074701047887939e+304).toFixed(2));
Ps : I also need the code to work for normal numbers aswell for example 892.0747010 , should output 892.07
toFixed trims digits after the decimal point, but your actual number is very large - it doesn't have a decimal point.
If you don't know in advance whether the number is large or not, one option is to call toFixed(2) on the number first (trimming off and properly rounding digits past the decimal point for small numbers), then using a regular expression to take the numeric part only (removing the e if it exists), then call toFixed(2) again (trimming off and properly rounding digits past the decimal point for large numbers):
const fix = num => Number(
num.toFixed(2).match(/\d+(?:\.\d+)?/)[0]
).toFixed(2);
console.log(fix(9.074701047887939e+304));
console.log(fix(123.4567));
console.log(fix(12345));
Since you mentioned for both 9.074701047887939e+304 and 9.074701047887939, you want the answer to be 9.07.
For 9.074701047887939e-304 I assume you want 9.07 too, although you might actually want 0.00.
const twoDecimal = (a =>
(a.toString().match(/e/) ? Number(a.toString().match(/[^e]*/)[0]) : a).toFixed(2)
);
console.log(twoDecimal(9.074701047887939e+304));
console.log(twoDecimal(9.074701047887939e-304));
console.log(twoDecimal(9.074701047887939));
console.log(twoDecimal(789.074701047887939));
console.log(twoDecimal(0.00001));
console.log(twoDecimal(0.20001));
console.log(twoDecimal(-9.074701047887939e+304));
console.log(twoDecimal(-9.074701047887939e-304));
console.log(twoDecimal(-9.074701047887939));
console.log(twoDecimal(-789.074701047887939));
console.log(twoDecimal(-0.00001));
console.log(twoDecimal(-0.20001));
console.log(twoDecimal(0));

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 toString limits

So my problem is this, I'm writing a program that checks if number is even or odd without division. So I decided to take the number, turn it into a String with the
number.toString()
method. The problem I'm having is that if you put a number that is about 17 or more digits long the string is correct for about the first 17 digits then it's just 0's and sometimes 2's. For example,
function toStr (number)
{
return number.toString(10);
}
console.log(toStr(123456789123456789));
prints,
123456789123456780
any ideas?
The problem has nothing to do with strings or your function at all. Try going to your console and just entering the expression 123456789123456789 and pressing return.
You will likewise obtain 123456789123456780.
Why?
The expression 123456789123456789 within the JavaScript language is interpreted as a JavaScript number type, which can only be represented exactly to a certain number of base two significant figures. The input number happens to have more significant digits when expressed in base two than the number of base two significant figures available in JavaScript's representation of a number, and so the value is automatically rounded in base two as follows:
123456789123456789 =
110110110100110110100101110101100110100000101111100010101 (base two)
123456789123456780 =
110110110100110110100101110101100110100000101111100001100 (base two)
Note that you CAN accurately represent some numbers larger than a certain size in JavaScript, but only those numbers with no more significant figures in base two than JavaScript has room for. For instance, 2 times a very large power of 10, which would have only one significant figure in base two.
If you are designing this program to accept user input from a form or dialog box, then you will receive the input as a string. You only need to check the last digit in order to determine if the input number is odd or even (assuming it is indeed an integer to begin with). The other answer has suggested the standard way to obtain the last character of a string as well as the standard way to test if a string value is odd or even.
If you go beyond Javascript's max integer size (9007199254740992) you are asking for trouble: http://ecma262-5.com/ELS5_HTML.htm.
So to solve this problem, you must treat it as a string only. Then extract the last digit in the string and use it to determine whether the number is even or odd.
if(parseInt(("123456789123456789").slice(-1)) % 2)
//odd
else
//even
It's a 64-bit floating point number, using the IEEE 754 specification. A feature of this spec is that starting at 2^53 the smallest distance between two numbers is 2.
var x = Math.pow(2, 53);
console.log( x == x + 1 );
This difference is the value of the unit in the last place, or ULP.
This is similar in principle to trying to store fractional values in integral types in other languages; values like .5 can't be represented, so they are discarded. With integers, the ULP value is always 1; with floating point, the ULP value depends on how big or small the number you're trying to represent.

Round float to 2 decimals javascript

I have the problem that when i round a number to 2 decimals the parseFloat() function removes .00 from the number. I have tried
var num = parseFloat(Math.round(19 * 100) / 100).toFixed(2);
The return: num="19.00"
The return i need: num = 19.00
I know 19 = 19.00, but i am using a service that always require two decimals .00
The function returns a string with the right value. When i parse it to float the .00 is removed.
You cannot get 19.00 as float, only as string, because numbers always remove trailing zeros.
Maybe you can show us a bit more code to get an idea, there you need these trailing zeros?
Numbers do and can not hold information about their representation. They are only a numerical value.
When you display a number using window.alert, console.log or similar, you are not looking at a number, but at a string. Those display functions convert numbers to strings before displaying them. Number.toFixed also converts numbers into strings, with the difference being that it rounds them to two decimal places, so you end up with another representation of the same number.
What I am trying to say is that to display a number, you cannot get around converting it to a string. Whether you do it explicitly or the display function does it for you. When you send the number to the service that you are using, you are probably also sending a string (JSON, XML, etc. are always strings once you send them). If you need the value of the number for calculations, use it, then convert it in the end. No matter how, you have to do it in the end if you want those 0's at the end.

Categories

Resources