parseInt() scientific notation - javascript

Was playing around with JS and noticed this.
Why does parseInt(1e+21) return 1 and parseInt(1e+20) return 100000000000000000000 ? parseInt(10e+20) also returns 1?
Why does parseInt(1.7976931348623157E+10308); return NaN while parseFloat(1.7976931348623157E+10308) returns Infinity?
Even made a fibonacci sequence and any value that has +21 exponents only returns the first digit:
parseFloat() will return the correct number till Infinity.
Fibonacci demo (int : parseInt() : parseFloat())
( tested in Chrome )

parseInt and parseFloat are supposed to parse strings and convert them to Numbers. So, when you pass them a Number, it gets coerced to a string by the interpreter. So, at least in Firefox, "" + 1e+20 outputs "100000000000000000000", and "" + 1e+21 outputs "1e+21".
Let's read the documentation of parseInt:
If parseInt encounters a character that is not a numeral in the specified radix, it ignores it and all succeeding characters and returns the integer value parsed up to that point
so parseInt("1.whatever") returns 1 and parseInt("32.231e+something") returns 32.
A similar thing must be happening with parseFloat.
It's the weak typing's fault. IMO the correct behaviour when doing what you do would be to throw an exception.

Related

Numeric conversion in JavaScript [duplicate]

How do parseInt() and Number() behave differently when converting strings to numbers?
Well, they are semantically different, the Number constructor called as a function performs type conversion and parseInt performs parsing, e.g.:
// parsing:
parseInt("20px"); // 20
parseInt("10100", 2); // 20
parseInt("2e1"); // 2
// type conversion
Number("20px"); // NaN
Number("2e1"); // 20, exponential notation
Also parseInt will ignore trailing characters that don't correspond with any digit of the currently used base.
The Number constructor doesn't detect implicit octals, but can detect the explicit octal notation:
Number("010"); // 10
Number("0o10") // 8, explicit octal
parseInt("010"); // 8, implicit octal
parseInt("010", 10); // 10, decimal radix used
And it can handle numbers in hexadecimal notation, just like parseInt:
Number("0xF"); // 15
parseInt("0xF"); //15
In addition, a widely used construct to perform Numeric type conversion, is the Unary + Operator (p. 72), it is equivalent to using the Number constructor as a function:
+"2e1"; // 20
+"0xF"; // 15
+"010"; // 10
typeof parseInt("123") => number
typeof Number("123") => number
typeof new Number("123") => object (Number primitive wrapper object)
first two will give you better performance as it returns a primitive instead of an object.
One minor difference is what they convert of undefined or null,
Number() Or Number(null) Or Number('') // returns 0
while
parseInt() Or parseInt(null) // returns NaN
Summary:
parseInt():
Takes a string as a first argument, the radix (An integer which is the base of a numeral system e.g. decimal 10 or binary 2) as a second argument
The function returns a integer number, if the first character cannot be converted to a number NaN will be returned.
If the parseInt() function encounters a non numerical value, it will cut off the rest of input string and only parse the part until the non numerical value.
If the radix is undefined or 0, JS will assume the following:
If the input string begins with "0x" or "0X", the radix is 16 (hexadecimal), the remainder of the string is parsed into a number.
If the input value begins with a 0 the radix can be either 8 (octal) or 10 (decimal). Which radix is chosen is depending on JS engine implementation. ES5 specifies that 10 should be used then. However, this is not supported by all browsers, therefore always specify radix if your numbers can begin with a 0.
If the input value begins with any number, the radix will be 10
Number():
The Number() constructor can convert any argument input into a number. If the Number() constructor cannot convert the input into a number, NaN will be returned.
The Number() constructor can also handle hexadecimal number, they have to start with 0x.
Example:
console.log(parseInt('0xF', 16)); // 15
// z is no number, it will only evaluate 0xF, therefore 15 is logged
console.log(parseInt('0xFz123', 16));
// because the radix is 10, A is considered a letter not a number (like in Hexadecimal)
// Therefore, A will be cut off the string and 10 is logged
console.log(parseInt('10A', 10)); // 10
// first character isnot a number, therefore parseInt will return NaN
console.log(parseInt('a1213', 10));
console.log('\n');
// start with 0X, therefore Number will interpret it as a hexadecimal value
console.log(Number('0x11'));
// Cannot be converted to a number, NaN will be returned, notice that
// the number constructor will not cut off a non number part like parseInt does
console.log(Number('123A'));
// scientific notation is allowed
console.log(Number('152e-1')); // 15.21
If you are looking for performance then probably best results you'll get with bitwise right shift "10">>0. Also multiply ("10" * 1) or not not (~~"10"). All of them are much faster of Number and parseInt.
They even have "feature" returning 0 for not number argument.
Here are Performance tests.
I found two links of performance compare among several ways of converting string to int.
parseInt(str,10)
parseFloat(str)
str << 0
+str
str*1
str-0
Number(str)
http://jsben.ch/#/zGJHM
http://phrogz.net/js/string_to_number.html
parseInt() -> Parses a number to specified redix.
Number()-> Converts the specified value to its numeric equivalent or NaN if it fails to do so.
Hence for converting some non-numeric value to number we should always use Number() function.
eg.
Number("")//0
parseInt("")//NaN
Number("123")//123
parseInt("123")//123
Number("123ac") //NaN,as it is a non numeric string
parsInt("123ac") //123,it parse decimal number outof string
Number(true)//1
parseInt(true) //NaN
There are various corner case to parseInt() functions as it does redix conversion, hence we should avoid using parseInt() function for coersion purposes.
Now, to check weather the provided value is Numeric or not,we should use nativeisNaN() function
I always use parseInt, but beware of leading zeroes that will force it into octal mode.
It's a good idea to stay away from parseInt and use Number and Math.round unless you need hex or octal. Both can use strings. Why stay away from it?
parseInt(0.001, 10)
0
parseInt(-0.0000000001, 10)
-1
parseInt(0.0000000001, 10)
1
parseInt(4000000000000000000000, 10)
4
It completely butchers really large or really small numbers. Oddly enough it works normally if these inputs are a string.
parseInt("-0.0000000001", 10)
0
parseInt("0.0000000001", 10)
0
parseInt("4000000000000000000000", 10)
4e+21
Instead of risking hard to find bugs with this and the other gotchas people mentioned, I would just avoid parseInt unless you need to parse something other than base 10. Number, Math.round, Math.floor, and .toFixed(0) can all do the same things parseInt can be used for without having these types of bugs.
If you really want or need to use parseInt for some of it's other qualities, never use it to convert floats to ints.
parseInt converts to a integer number, that is, it strips decimals. Number does not convert to integer.
Another way to get the result is to use the ~ operator
For most circumstances
~~someThing === parseInt(something)
but ~~ will return zero for strings that parseInt will accept with trailing other characters or with the number base spec (eg hex) and will also return zero when parseInt returns NaN. Another difference is that ~~ if given a bigint returns a bigint to which you can add another bigint whereas parseInt returns an ordinary floating point number (yes really - it gives exactly the same value as parseFloat) if the bigint is large
However for most circumstances ~~ is 30% faster than parseInt. It is only slower by 10% when something is a floating point represented as a string.
So if the more restricted scope of ~~ fits your need then save the computer time and give yourself less to type

Why does Number(null) return 0, and parseFloat(null) return NaN?

I'm trying to write a helper function that will cast a String coming from an <input type="text" /> to a Number.
As I wasn't sure whether to use parseFloat(str) or Number(str) I doublechecked how they handle potentially problematic arguments.
See:
console.log(Number(null)); // 0
console.log(parseFloat(null)); // NaN
console.log(parseInt(null)); // NaN
console.log(isNaN(null)); // false
Both parseFloat and parseInt return NaN, whereas Number returns 0. Number seems more coherent here with isNaN(null).
Why is that?
Number constructor tries to coerce the argument to number. So empty string '', false, null and all falsy values become 0.
Similarly, Number(true) will return 1. Number('some string') will be NaN as 'some string' cannot be converted to a number.
Note that as pointed out in the comments, Number(undefined) is NaN and not 0 in arithmetic operations. (Read here https://codeburst.io/understanding-null-undefined-and-nan-b603cb74b44c)
Read more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
parseInt/Float convert their argument to a string, read it char by char from the left and try to make a number from what they've found. Since String(null) is "null" and a decimal number cannot start with "n", parseInt(null) will be NaN. If you provide a different base, where n, u and l are digits, the result will be different:
console.log(parseInt(null, 32))
Number converts its argument as a whole into a number. Number(null) returns +0 because the ECMA committee wants it to: http://www.ecma-international.org/ecma-262/7.0/#sec-tonumber . This is probably for historical reasons.
global isNaN (not to confuse with Number.isNaN) applies Number to its argument and returns true if the result is NaN. Since Number(null) is +0, isNaN(null) is false.
Hope this sheds some light...
NaN stands for "Not a Number". ParseFloat and ParseInt return real numbers and integers, so this is like an error returned by the function. Number(), on the other hand, represents the object's value. For instance, Number(false) will output 0.
The reason seems to be quite subtle with how parseInt and parseFloat work:
If the argument passed to parseInt/parseFloat is not a String (which null isn't), then it calls toString(null) which returns "[object Undefined]".
If the first character cannot be converted to a number, parseInt returns NaN.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt

Why does Javascript isNaN function declare string negative hex values to be NaN?

Given the following example:
isNaN("-0x123"); // returns true , meaning is not a number <- Why?
isNaN(-0x123); // returns false, meaning is a number
isNaN("0x123"); // returns false, meaning is a number
parseInt("-0x123"); // returns -291
My question: why does isNaN declares negative hex strings as NaN when other similar inputs yield more reasonable outputs?
Thanks
The function isNaN() tells you whether or not a value may be coerced to a number, it says nothing about whether there exists a function that will convert the value to a number.
You will see the same behaviour if you attempt to coerce the strings to numbers:
> +"-0x123"
NaN
> +(-0x123)
-291
> +"0x123"
291
The first case you have a string that does not match Javascript's rules for a number as that doesn't allow for a leading - on a hex literal, the second case you have an expression that evaluates to a number (so 0x123 negated), the third case you have a string that does match the grammar for a number.
See http://www.ecma-international.org/ecma-262/5.1/#sec-9.3 for the exact description, but in short a string numeric literal may be an unsigned decimal literal, + or - followed by an unsigned decimal literal, or it may be a hex integer literal (and in all these cases leading and trailing whitespace is ignored). There is no option for a sign on a hex literal.
What you are expecting is this :
isNaN(parseInt("-0x123")); // returns -291
Because "-0x123" is treated as a string and not as a number. So
isNaN("-0x123");
will return false since there is no number. The MDN says:
The isNaN() function determines whether a value is NaN or not. Note:
coercion inside the isNaN function has interesting rules; you may
alternatively want to use Number.
.........
Confusing special-case behavior
Since the very earliest versions of the isNaN function specification,
its behavior for non-numeric arguments has been confusing. When the
argument to the isNaN function is not of type Number, the value is
first coerced to a Number. The resulting value is then tested to
determine whether it is NaN. Thus for non-numbers that when coerced to
numeric type result in a valid non-NaN numeric value (notably the
empty string and boolean primitives, which when coerced give numeric
values zero or one), the "false" returned value may be unexpected; the
empty string, for example, is surely "not a number." The confusion
stems from the fact that the term, "not a number", has a specific
meaning for numbers represented as IEEE-754 floating-point values. The
function should be interpreted as answering the question, "is this
value, when coerced to a numeric value, an IEEE-754 'Not A Number'
value?"

parseInt('1e1') vs parseFloat('1e1')

parseInt(1e1); //10
parseInt('1e1'); //1
parserFloat('1e1') //10
Why parseInt returns 1 in the second case? The three shouldn't return the same result?
1e1 is a number literal that evaluates to 10; parseInt() sees 10 and happily returns that.
'1e1' is a string, and parseInt() does not recognize exponential notation, so it stops at the first letter.
'1e1' as a string is perfectly fine when parsed as a float.
Bonus: parseInt('1e1', 16) returns 481, parsing it as a 3-digit hex number.
When you're trying to parse a string, only the first number in a string is returned. Check function specification at http://www.w3schools.com/jsref/jsref_parseint.asp
Also, you can test it out yourself:
parseInt('2e1') - returns 2
parseInt('3e2') - returns 3
To understand the difference we have to read ecma official documentation for parseInt and parseFloat
... parseInt may interpret only a leading portion of string as an integer value; it ignores any characters that cannot be interpreted as part of the notation of an integer, and no indication is given that any such characters were ignored...
... parseFloat may interpret only a leading portion of string as a Number value; it ignores any characters that cannot be interpreted as part of the notation of an decimal literal, and no indication is given that any such characters were ignored...
parseInt expects ONLY an integer value (1, 10, 28 and etc), but parseFloat expects Number. So, string "1e1" will be automatically converted to Number in parseFloat.
parseInt('1e1'); // 1
parseFloat('1e1'); // 10

javascript, parseInt behavior when passing in a float number

I have the following two parseInt() and I am not quite sure why they gave me different results:
alert(parseInt(0.00001)) shows 0;
alert(parseInt(0.00000001)) shows 1
My guess is that since parseInt needs string parameter, it treats 0.00001 as ""+0.00001 which is "0.00001", therefore, the first alert will show 0 after parseInt. For the second statement, ""+0.00000001 will be "1e-8", whose parseInt will be 1. Am I correct?
Thanks
I believe you are correct.
parseInt(0.00001) == parseInt(String(0.00001)) == parseInt('0.00001') ==> 0
parseInt(0.00000001) == parseInt(String(0.00000001)) == parseInt('1e-8') ==> 1
You are correct.
parseInt is intended to get a number from a string. So, if you pass it a number, it first converts it into a string, and then back into a number. After string conversion, parseInt starts at the first number in the string and gives up at the first non-number related character. So "1.e-8" becomes "1"
If you know you are starting with a string, and are just trying to get an Integer value, you can do something like.
Math.round(Number('0.00000001')); // 0
If you know you have a floating point number and not a string...
Math.round(0.00000001); // 0
You can also truncate, ceil(), or floor the number
parseInt takes each character in the first argument (converted to a string) that it recognizes as a number, and as soon as it finds a non-numeric value it ignores that value and the rest of the string. (see MDN second paragraph under "Description")
Therefore it's likely that parseInt(0.00000001) === parseInt(String(0.00000001)) === parseInt("1e-8"), which would only extract the 1 from the string yielding parseInt("1") === 1
However, there's another possibility:
From Mozilla developer network:
parseInt(string, radix);
for the string argument (emphasis added): "The value to parse. If string is not a string, then it is converted to one. Leading whitespace in the string is ignored."
I think this possibility is less likely, since String(0.00000001) does not yield NAN.

Categories

Resources