866

I have an annoying problem in JavaScript.

> parseInt(1 / 0, 19)
> 18

Why does the parseInt function return 18?

Arsen Khachaturyan
  • 7,904
  • 4
  • 42
  • 42
cebor
  • 6,546
  • 4
  • 24
  • 31
  • 4
    Interesting. But why is this an annoying problem for you? Do you have to handle Infinity in other ways? If so, an `if` might help. – Thilo Jul 05 '12 at 08:44
  • 269
    What the hell were you even doing that required you to work with either base-19 numbers OR division by zero!? – Jack M Jul 05 '12 at 13:19
  • @ Ray Toal `0 / 0 == NaN` :) – cebor Jul 06 '12 at 06:51
  • 22
    When you get confused about JS, just go back to [this quote](http://www.jwz.org/blog/2010/10/every-day-i-learn-something-new-and-stupid/#comment-1021) and remember that the whole damn language was designed and implemented in less than 10 days (according to the person who did it). – tylerl Jul 06 '12 at 09:13
  • I almost dared to cite here what Zed A Shaw said about JavaScript!! :) – DejanLekic Jul 06 '12 at 12:04
  • 36
    From the FAQ: "You should only ask practical, answerable questions based on actual problems that you face." This isn't actually an "annoying problem" that you actually face, it's a unrealistic example [that's been floating around the internet forever](http://forums.somethingawful.com/showthread.php?threadid=2803713&pagenumber=334#post405347339). – Jeremy Jul 09 '12 at 23:25
  • 2
    python does the same thing: int('I', 19) == 18 – oberhamsi Jul 11 '12 at 06:09
  • 1
    @oberhamsi Please don't say that. You are talking about something else; `int(1/0, 19)` raises a `ZeroDivisionError`, and `int('Infinity', 19)` raises a `ValueError`. If you consider this to be similar to js.... – jadkik94 Jul 11 '12 at 13:27
  • @oberhamsi That's hardly the same thing. This question is a perfect example of why Python's type system is so much more restrictive than JavaScript's - e.g. why you have to explicitly cast other types to strings. – dimo414 Jul 28 '12 at 19:41

4 Answers4

1309

The result of 1/0 is Infinity.

parseInt treats its first argument as a string which means first of all Infinity.toString() is called, producing the string "Infinity". So it works the same as if you asked it to convert "Infinity" in base 19 to decimal.

Here are the digits in base 19 along with their decimal values:

Base 19   Base 10 (decimal)
---------------------------
   0            0
   1            1
   2            2
   3            3
   4            4
   5            5
   6            6
   7            7
   8            8
   9            9
   a            10
   b            11
   c            12
   d            13
   e            14
   f            15
   g            16
   h            17
   i            18

What happens next is that parseInt scans the input "Infinity" to find which part of it can be parsed and stops after accepting the first I (because n is not a valid digit in base 19).

Therefore it behaves as if you called parseInt("I", 19), which converts to decimal 18 by the table above.

Zsolt Meszaros
  • 21,961
  • 19
  • 54
  • 57
Jon
  • 428,835
  • 81
  • 738
  • 806
  • 12
    then why parseInt(1/0, 24) gives me 151176378 ? – Mithun Satheesh Jul 05 '12 at 08:44
  • 35
    @mithunsatheesh Try `parseInt('Infini',24)`. – Supr Jul 05 '12 at 08:45
  • 115
    @mithunsatheesh: Because in base 24 `n` is also a valid digit, so it actually ends up doing `parseInt("Infini", 24)`. – Jon Jul 05 '12 at 08:46
  • 1
    @mithunsatheesh: probably because during parsing with base of 19 only the first character is parsed (n is not within list of chars for this base)? In case of base 24 there are more characters that can be parsed, so the result is bigger. – Tadeck Jul 05 '12 at 08:46
  • 9
    @Tadeck: Yes because we love JavaScript, have eyes on it to always learn something new :) +1 – Blaster Jul 05 '12 at 09:03
  • 41
    Why someone wants to 'program' in a language which behaves like this is beyond me. – Frans Bouma Jul 06 '12 at 08:24
  • 48
    @FransBouma: JS is beautiful in its own way. And really, no part of what happens here is unreasonable in a dynamic language. – Jon Jul 06 '12 at 08:27
  • 62
    @Jon: this artifact isn't the result of dynamic language; it's a result of loose-typing. In strictly-typed dynamic language, the implicit conversion of Infinity (float) to "Infinity" (string) would not happen, to prevent this sort of silliness. – Lie Ryan Jul 08 '12 at 12:34
  • 6
    @LieRyan It is not implicit. `parseInt` explicitly converts the argument to be parsed to string by calling `ToString` on it. What is the correct string presentation of `Infinity`? `"Infinity"` seems reasonable to me. But there is no implicit conversion anywhere. – Esailija Jul 10 '12 at 06:54
  • 8
    `parseInt` is meant to parse a string, not an arbitrary object on which `toString` is called. The ability to pass in `Infinity` (NOT a string) and have it converted to `"Infinity"` is in fact an non-obvious, implicit conversion. – munchybunch Jul 10 '12 at 07:01
  • 1
    Can't say I would agree with this. [Implicit type conversion](http://en.wikipedia.org/wiki/Type_conversion#Implicit_type_conversion) has to do with automated conversion not undocumented feature. Automatic conversion of `int` to `long` in C is very well documented, still implicit though. – Muhammad Alkarouri Jul 10 '12 at 08:29
  • 6
    @Jon: This is non-obvious & surprising behavior which has nothing to do with JS being a "dynamic language". It requires knowing that the IEEE floating point standard arbitrarily defines 1/0 as positive infinity instead of being (the more widely accepted, obvious and unsurprising) undefined value. I believe JS is a great language but calling this reasonable behavior smacks of Stockholm Syndrome. – mattdeboard Jul 10 '12 at 08:35
  • 2
    As a physicist (or mathematician) I'd assume `x/0` to return `undefined`, not `Infinity` - just like mattdeboard says. – Markus Jul 10 '12 at 08:48
  • @MuhammadAlkarouri this conversion is not like `int` to `long` or what is described in that part of the article at all, it's closer to calling [`itoa`](http://www.cplusplus.com/reference/clibrary/cstdlib/itoa/), except of course it's not integer to string but double (which can be `Infinity`) to string – Esailija Jul 10 '12 at 08:55
  • 8
    @mattdeboard: I agree that it is surprising, but disagree that it's unreasonable. Every decision has pros and cons; for me, agreement with IEE 754 is a property more desirable than agreement with an informed non-programmer's expectation. Developers have been trained to accept the models of computer systems as "correct" even when they differ from more widely accepted models because they offer specific engineering benefits. I don't expect *everyone* to agree with this POV, but I also don't think it's fair to call it Stockholm Syndrome. – Jon Jul 10 '12 at 09:31
  • 1
    @Esailija: my point was that _implicit_ does not mean _undocumented_. Conversion of `int` to `long`, or `int` to `string`, or converting a [`string` to a `TextWriterFormat<'T>` in F#](http://stackoverflow.com/q/2162081/336455) are all implicit as long as the automatic calling of [itoa](http://www.cplusplus.com/reference/clibrary/cstdlib/itoa/) or another suitable conversion function is handled automatically and not called explicitly by the programmer. – Muhammad Alkarouri Jul 10 '12 at 12:42
  • I think this is a combination of two problems: 1) Implicitly calling toString(), 2) The base being an optional parameter – luiscubal Jul 11 '12 at 14:11
  • Very interesting topic indeed, with amazing explanations! :-) And `2*parseInt(1/0,19)+6` gives you the [ultimate answer](http://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy) ... ;-) – Matt Jul 13 '12 at 14:12
  • 1
    Talk about obscure coding. One could win "IOJSCC" with such things :)) – Mihai Todor Jul 13 '12 at 17:21
  • 2
    @munchybunch - You stated yourself that "`parseInt` is meant to parse a string", as indeed the "parse" part of its name implies (and as all reputable JS references state), so if somebody deliberately passes an argument that is _not_ a string they really shouldn't be too surprised if they don't get whatever result they expected. – nnnnnn Oct 26 '13 at 10:35
  • 4
    Isn't part of the "stupidity" that `parseInt` is willing to parse an argument where only a prefix is a valid number in the given base? Rather than report an error and/or return `undefined` when the input has garbage after the numeric prefix, it simply ignores it. Unfortunately, this is quite common; PHP does the same thing, as does C's `atoi()` and similar functions. – Barmar Jul 31 '14 at 02:24
230

Here's the sequence of events:

  • 1/0 evaluates to Infinity
  • parseInt reads Infinity and happily notes that I is 18 in base 19
  • parseInt ignores the remainder of the string, since it can't be converted.

Note that you'd get a result for any base >= 19, but not for bases below that. For bases >= 24, you'll get a larger result, as n becomes a valid digit at that point.

Craig Citro
  • 6,505
  • 1
  • 31
  • 28
  • @Thilo BTW, what would be the reason, why it *might* stop at 19, if base's greater? Do you know, what's the greatest base JS can iterpret? – Arnthor Jul 10 '12 at 07:37
  • 4
    @Nordvind The largest base `parseInt` will accept is 36, since there are 26 letters in the English alphabet, and the convention is to use digits then letters as the set of valid digits in the given base. – Craig Citro Jul 10 '12 at 08:14
  • 4
    On bullet point #2, may I suggest changing `Infinity` to `"Infinity"`... – CJBS May 04 '17 at 20:55
  • @CJBS Correct, but there’s a bullet point missing before that: `parseInt` expects a string as its first argument, so `Infinity` is coerced to `"Infinity"`; also that should be an ordered list, not an unordered one. But the accepted answer already explains everything… – Sebastian Simon Apr 09 '21 at 02:17
39

To add to the above answers:

parseInt is intended to parse strings into numbers (the clue is in the name). In your situation, you don't want to do any parsing at all since 1/0 is already a number, so it's a strange choice of function. If you have a number (which you do) and want to convert it to a particular base, you should use toString with a radix instead.

var num = 1 / 0;
var numInBase19 = num.toString(19); // returns the string "Infinity"
kybernetikos
  • 8,281
  • 1
  • 46
  • 54
14

To add to the above answers

parseInt(1/0,19) is equivalent to parseInt("Infinity",19)

Within base 19 numbers 0-9 and A-I (or a-i) are a valid numbers. So, from the "Infinity" it takes I of base 19 and converts to base 10 which becomes 18 Then it tries to take the next character i.e. n which is not present in base 19 so discards next characters (as per javascript's behavior of converting string to number)

So, if you write parseInt("Infinity",19) OR parseInt("I",19) OR parseInt("i",19) the result will be same i.e 18.

Now, if you write parseInt("I0",19) the result will be 342 as I X 19 (the base)^1 + 0 X 19^0 = 18 X 19^1 + 0 X 19^0 = 18 X 19 + 0 X 1 = 342

Similarly, parseInt("I11",19) will result in 6518

i.e.

  18 X 19^2  +   1 X 19^1   +  1 X 19^0
= 18 X 19^2  +   1 X 19^1   +  1 X 19^0
= 18 X 361   +   1 X 19     +  1 X 1
= 6498  +  19  +  1
= 6518
Imdad
  • 5,942
  • 4
  • 33
  • 53