I'm testing toFixed() method of javascript. The result is seen as below.
(49.175).toFixed(2) => "49.17"
(49.775).toFixed(2) => "49.77"
(49.185).toFixed(2) => "49.19"
(49.785).toFixed(2) => "49.78"
(49.1175).toFixed(3) => "49.117"
(49.1775).toFixed(3) => "49.178"
(49.1185).toFixed(3) => "49.118"
(49.1785).toFixed(3) => "49.178"
I made this test at chrome browser, and I'm surprised with the result. I couldn't catch the logic. It doesn't fit neither 'round away from zero' nor 'round to even'.
What is the rule behind of 'toFixed()' function ?
About toFixed
Returns a String containing this Number value represented in decimal fixed-point notation with fractionDigits digits after the decimal point. If fractionDigits is undefined, 0 is assumed. Specifically, perform the following steps:
Algorithm Number.prototype.toFixed (fractionDigits): https://www.ecma-international.org/ecma-262/5.1/#sec-15.7.4.5
The length property of the toFixed method is 1.
If the toFixed method is called with more than one argument, then the behaviour is undefined (see clause 15).
An implementation is permitted to extend the behaviour of toFixed for values of fractionDigits less than 0 or greater than 20. In this case toFixed would not necessarily throw RangeError for such values.
NOTE The output of toFixed may be more precise than toString for some values because toString only prints enough significant digits to distinguish the number from adjacent number values.
JS Work Around
function fix(n, p) {
return (+(Math.round(+(n + 'e' + p)) + 'e' + -p)).toFixed(p);
}
let exampleA = fix(49.1175, 3);
let exampleB = fix(49.1775, 3);
let exampleC = fix(49.775, 2);
const random = Math.random();
console.log(exampleA);
console.log(exampleB);
console.log(exampleC);
console.log('Before:', random, 'After Custom =>', fix(random, 3), 'Default:', random.toFixed(3));
// 49.118
// 49.178
// 49.78
Precision Needed
I suggest just simply porting set precision from C++ to a Node.JS Module.
You could simply rig up and use a child_process also in Node.JS to call a C++ program with an argument, and have the C++ run a function to convert the value and output to the console.
The issue is, that the numbers you entered do not exist! On scanning, they are (binary) rounded to the nearest possible/existing number. toPrecision(18) shows the numbers after scanning more exact:
(49.175).toPrecision(18); // "49.1749999999999972" => "49.17"
(49.775).toPrecision(18); // "49.7749999999999986" => "49.77"
(49.185).toPrecision(18); // "49.1850000000000023" => "49.19"
(49.785).toPrecision(18); // "49.7849999999999966" => "49.78"
So the number is rounded 2 times: First on scanning, and then by toFixed().
From the MDN:
toFixed() returns a string representation of numObj that does not use exponential notation and has exactly digits digits after the decimal place. The number is rounded if necessary, and the fractional part is padded with zeros if necessary so that it has the specified length. If numObj is greater or equal to 1e+21, this method simply calls Number.prototype.toString() and returns a string in exponential notation.
And later you can read:
WARNING: Floating point numbers cannot represent all decimals precisely in binary which can lead to unexpected results such as 0.1 + 0.2 === 0.3 returning false.
The above warning in conjuntion with the round logic (maybe arithmetical operations on the number) will explain the different behaviours you are experimenting in the rounding procedure (you can read it here).
Related
How to get big power of 2 in decimal or
how to convert big exponential value into decimal value.
I want 2 to the power of 128 in decimal not exponential
what I did till now
tofixed(+exponent)
which again given me the same value.
var num = Math.pow(2, 128);
Actual result = 3.402823669209385e+38
expected some decimal value not exponential value.
You could use BigInt, if implemented.
var num = BigInt(2) ** BigInt(128);
console.log(num.toString());
console.log(BigInt(2 ** 128).toString());
3.402823669209385e+38 is a decimal number (in string form, because it's been output as a string). It's in scientific notation, specifically E-notation. It's the number 3.402823669209385 times 100000000000000000000000000000000000000.
If you want a string that isn't in scientific notation, you can use Intl.NumberFormat for that:
console.log(new Intl.NumberFormat().format(Math.pow(2, 128)));
Note: Although that number is well outside the range that JavaScript's number type can represent with precision in general (any integer above Number.MAX_SAFE_INTEGER [9,007,199,254,740,991] may be the result of rounding), it's one of the values that is held precisely, even at that magnitude, because it's a power of 2. But operations on it that would have a true mathematical result that wasn't a power of 2 would almost certainly get rounded.
I think the default power function won't be able to the results you want.
You can refer to the article below to understand how to create an Power function with big number by yourself.
Demo code is not JS but still quite understandable.
↓
Writing power function for large numbers
I've made a program to convert bases of numbers. I thought that, in the event that there are no characters A-F in the output, it would be convenient to return the number as a Number instead of a String (even though I'd be returning base 2 numbers as regular decimal numbers, whatever).
For some reason, when I converted A3B232 to Binary (which should be 10100001101011001002 [Wolfram|Alpha source]), I got 1010000110101100200. There's a two in there, that isn't binary! The final line of code which returns the value is:
return (toBase <= 10) ? Number(result) : result;
This worked properly for basically all tests, until I decided to use that base-32 number above. I thought my program was doing the division/remainder step incorrect, so I had it print out the result just before it returns the value. It was correctly giving out 1010000110101100100. So, I tested the Number() method directly in Chrome's console. This is what happened:
> Number("1010000110101100100")
> 1010000110101100200
Am I misunderstanding what the Number() method does? Why is it converting a string made up of all Ones and Zeroes to a number with Ones, Zeroes, and Twos?
What you're doing when calling Number("1010000110101100100") is passing a string, which it is trying to turn it into a number, but that number is higher than JavaScript can count, which is 9,007,199,254,740,991 (also known as Number.MAX_SAFE_INTEGER)
Basically, any number over 9,007,199,254,740,991 can't reliably be used because JavaScript uses double-precision floating-point format numbers as specified in IEEE 754
Here's some examples, the following input numbers "should" be the same as the output, but aren't because they've gone over the MAX_SAFE_INTEGER. Some are, but it's not reliable as demonstrated in the Bonus Fun With LARGE Numbers section below.
Number("9007199254740992") // 9007199254740992
Number("9007199254740993") // 9007199254740992
Number("9007199254740994") // 9007199254740994
Number("9007199254740995") // 9007199254740996
Number("9007199254740996") // 9007199254740996
Number("9007199254740997") // 9007199254740996
Number("9007199254740998") // 9007199254740998
Number("9007199254740999") // 9007199254741000
If you still want to convert hex to binary, you need to use parseInt and Number.prototype.toString and keep it as a string.
const hex = "A3B2";
const binary = parseInt(hex, 16).toString(2);
console.log(binary);
Bonus Fun With LARGE Numbers
The following is true!
console.log(9007199254740992 === 9007199254740993);
console.log(1010000110101100200 === 1010000110101100100)
Documentation
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString
#AnonymusSB said is right. i want add few details to it.
So when you Number(value) it internally calls ToNumber to calculate the value. when you supply a string. it have a two step process to change it number.
First it calculate the Mathematical value (MV) of the string.
In second process it rounds up the calculated value.(when you exceed the limit of Math.MAX_SAFE_INTEGER it round of the number).
console.log(Number("9007199254740996"))
console.log(Number("9007199254740997"), "rounded down")
console.log(Number("9007199254740998"))
console.log(Number("9007199254740999") ,"rounded up")
EcmaScript
I have a decimal precision function which takes in an object and a precision number as arguments and it returns me a number which is parsed using JSON.parse(number) as output.
I have observed that the toPrecision() function returns a value in exponential notation when the value passed is an integer with no decimal places and the precision value is between 1 and 100. When I pass in the exponential notation to the JSON.parse(), it gives me a number. I am not understanding how this is working internally. Could anyone explain me what exactly is happening here. The following is the function which I have devised:
function precise(object, precision){
let st = JSON.stringify(object);
st = st.replace(/[+-]?([0-9]*[.])?[0-9]+/g, s => parseFloat(s).toPrecision(precision));
return JSON.parse(st);
}
For instance, if I call precise(100, 2), st will have the value 1.0e+2 and the return value will be 100. How does this conversion taking place?
Thank you.
If I'm understanding your question correctly it is essentially...
"Why does console.log((100).toPrecision(2)); result in 1.0e+2?"
The argument that is given to toPrecision defines the desired number of precision (aka "scientific precision" or number of digits (not decimal places)).
In other words... there are more than two digits in 100 so the result has to be defined using scientific notation.
I have just observed that the parseInt function doesn't take care about the decimals in case of integers (numbers containing the e character).
Let's take an example: -3.67394039744206e-15
> parseInt(-3.67394039744206e-15)
-3
> -3.67394039744206e-15.toFixed(19)
-3.6739e-15
> -3.67394039744206e-15.toFixed(2)
-0
> Math.round(-3.67394039744206e-15)
0
I expected that the parseInt will also return 0. What's going on at lower level? Why does parseInt return 3 in this case (some snippets from the source code would be appreciated)?
In this example I'm using node v0.12.1, but I expect same to happen in browser and other JavaScript engines.
I think the reason is parseInt converts the passed value to string by calling ToString which will return "-3.67394039744206e-15", then parses it so it will consider -3 and will return it.
The mdn documentation
The parseInt function converts its first argument to a string, parses
it, and returns an integer or NaN
parseInt(-3.67394039744206e-15) === -3
The parseInt function expects a string as the first argument. JavaScript will call toString method behind the scene if the argument is not a string. So the expression is evaluated as follows:
(-3.67394039744206e-15).toString()
// "-3.67394039744206e-15"
parseInt("-3.67394039744206e-15")
// -3
-3.67394039744206e-15.toFixed(19) === -3.6739e-15
This expression is parsed as:
Unary - operator
The number literal 3.67394039744206e-15
.toFixed() -- property accessor, property name and function invocation
The way number literals are parsed is described here. Interestingly, +/- are not part of the number literal. So we have:
// property accessor has higher precedence than unary - operator
3.67394039744206e-15.toFixed(19)
// "0.0000000000000036739"
-"0.0000000000000036739"
// -3.6739e-15
Likewise for -3.67394039744206e-15.toFixed(2):
3.67394039744206e-15.toFixed(2)
// "0.00"
-"0.00"
// -0
If the parsed string (stripped of +/- sign) contains any character that is not a radix digit (10 in your case), then a substring is created containing all the other characters before such character discarding those unrecognized characters.
In the case of -3.67394039744206e-15, the conversion starts and the radix is determined as base 10 -> The conversion happens till it encounters '.' which is not a valid character in base 10 - Thus, effectively, the conversion happens for 3 which gives the value 3 and then the sign is applied, thus -3.
For implementation logic - http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.2
More Examples -
alert(parseInt("2711e2", 16));
alert(parseInt("2711e2", 10));
TO note:
The radix starts out at base 10.
If the first character is a '0', it switches to base 8.
If the next character is an 'x', it switches to base 16.
It tries to parse strings to integers. My suspicion is that your floats are first getting casted to strings. Then rather than parsing the whole value then rounding, it uses a character by character parsing function and will stop when it gets to the first decimal point ignoring any decimal places or exponents.
Some examples here http://www.w3schools.com/jsref/jsref_parseint.asp
parseInt has the purpose of parsing a string and not a number:
The parseInt() function parses a string argument and returns an
integer of the specified radix (the base in mathematical numeral
systems).
And parseInt calls the function ToString wherein all the non numerical characters are ignored.
You can use Math.round, which also parses strings, and rounds a number to the nearest integer:
Math.round("12.2e-2") === 0 //true
Math.round("12.2e-2") may round up or down based on the value. Hence may cause issues.
new Number("3.2343e-10").toFixed(0) may solve the issue.
Looks like you try to calculate using parseFloat, this will give you the correct answer.
parseInt as it says, returns an integer, whereas parseFloat returns a floating-point number or exponential number:
parseInt(-3.67394039744206e-15) = -3
parseFloat(-3.67394039744206e-15) = -3.67394039744206e-15
console.log('parseInt(-3.67394039744206e-15) = ' , parseInt(-3.67394039744206e-15));
console.log('parseFloat(-3.67394039744206e-15) = ',parseFloat(-3.67394039744206e-15));
I'm using John Resig's function to find min value in an array but it returns somehow floored value.
Here's a demo and here's the code.
var arr = Math.min.apply(Math, [310127563311820800, 310127563190202368, 310127563110502401, 310127562443595776, 310127562326163457, 310127561751556097]);
document.write(arr);
Can you explain me what happens and why it's returning wrong(floored) value?
The problem isn't in finding the min but in using those numbers. You can't represent them as numbers in JavaScript as integers can only be completely kept between -9007199254740992 and +9007199254740992.
It's because all numbers in JavaScript are double precision IEEE754 floats and the size of the mantissa is 53.
See more details in ECMAScript specification on the number type :
Note that all the positive and negative integers whose magnitude is no
greater than 253 are representable in the Number type (indeed, the
integer 0 has two representations, +0 and -0).
To deal with those numbers (and find their min), you need to use another representation than the native JavaScript number. Hopefully, there are many libraries dealing with big numbers, for example bignum (but you should google and pick the one you like).
You will lose precision in javascript unless you make the input strings of digits.
If they are all positive integers you can sort them and return the lowest indexed element, remembering that a string with more digits must be larger than one with fewer-
var input= ['310127563311820800', '310127563190202368', '310127563110502401',
'310127562443595776', '310127562326163457', '310127561751556097'];
var minim= input.slice(0).sort(function(a, b){
if(a=== b) return 0;
if(a.length!= b.length) return a.length-b.length;
return a>b? 1:-1;
})[0];
alert(minim);
/* returned value: (String)
310127561751556097
*/
You can skip the slice(0) bit if you don't need to keep the original in its order.