Check out a free preview of the full The Good Parts of JavaScript and the Web course

The "Numbers" Lesson is part of the full, The Good Parts of JavaScript and the Web course featured in this preview video. Here's what you'd learn in this lesson:

Numbers are simpler in JavaScript than other programming languages because they are represented by a single type. Sharing a few of their shortcomings, Doug describes how numbers behave in JavaScript. Doug then talks about the Math object and the various operations that can be performed on JavaScript numbers.


Transcript from the "Numbers" Lesson

>> [MUSIC]

>> Douglas Crockford: Everything in JavaScript is an object, so numbers, booleans, strings, arrays, dates, regular expressions and functions, they're all objects. So, let's look at numbers, numbers are objects, it's a much a simpler number system than you have in Java in that we don't have ints and integers, you don't have either of those, you just have numbers.

We make numbers with number literals. All these number literals refer to the same object.
>> Douglas Crockford: There's only one number type in JavaScript which is actually a very good thing and there are no integer types which is something you have to get used to but it's actually a good thing too.

The problem is that the one number type we have is the wrong one. It's based on 64-bit binary floating point from the IEEE-754 standard which is strangely called double in Java and other languages. Anybody care to know why it's called double? Why they picked such a silly name?

It's something that comes from Fortran. Fortran had integer and real and later they added double precision, which was two reals put together in order to give you more precision. And C took Fortran's double precision and shortened it to double. And everyone else has been using double ever since then.

So we don't have ints and I'm glad we don't have ints cuz I hate ints. Ints have some really strange properties. For example, we can have two ints which are both greater than zero. We can add them together and we can get results that are smaller than the original numbers, which is insane and inexcusable, and how can you have any confidence in the correctness and the perfection of your system if it's built on a number type which can do such insanely ridiculous things?

So JavaScript does not have this defect in it which I think is brilliant. So one problem with computer arithmetic in general is that the Associative Law will not hold, and that's because computer numbers are necessarily finite and real numbers aren't. So in many cases we're only dealing with approximations.

And when the values are approximate, then associativity doesn't hold. Now if you just confine to the integer space, JavaScript integers go up to around 9 quadrillion, which is pretty big. 9 quadrillion is bigger than the national debt, so it's big, right? That's big. So as long as your integers are smaller than 9 quadrillion they work out exactly.

When the integers get above 9 quadrillion they don't do the crazy wrap around thing that ints do, they just get fuzzy. So if I take a number above 9 quadrillion and add 1 to it, it's like I added 0 to it, which is not good but it's much less bad than what ints do.

And because computer arithmetic can be approximate, then there are identities that we're used to thinking about which don't hold. So you need to be aware of that and cautious. So the most reported bug for JavaScript is that 0.10 + 0.20 is not equal to 0.30. And that's because we're trying to represent decimal fractions in binary floating point.

And binary floating point cannot accurately represent most of the decimal fractions. It can only approximate them, but it approximates them with infinite repeating bit patterns, but we're not allowed to have infinitely long numbers. And so they truncate, and so every number is gonna be slightly wrong. Which is only a problem if you're living on a planet that uses the decimal system.

But on such a planet, you're counting people's money using this. When you're adding people's money, they have a reasonable expectation you're gonna get the right sum. And we're not guaranteed to get the right sum with binary floating point, which is a huge problem.
>> Douglas Crockford: Numbers are objects, and so numbers have methods.

You don't have to box them in order to get object behavior. Every number is already an object. Every number inherits from number.prototype. So if we wanted to add new methods to numbers, we can do that by adding them to number.prototype. This is not something that applications should ever do, but it is a useful thing for libraries to do, and in fact this is how we evolve the language.

So we can add new methods to new versions of the standard and libraries can back fill old browsers, and old implementations with the new stuff as long as new methods can be implemented in JavaScript. Numbers are first class objects which means that a number can be stored in a variable, can be passed as a parameter, can be returned from a function and it can be stored in an object.

And because numbers are themselves objects they can have methods. JavaScript has made the same mistake that Java made in having a separate math object or math container for keeping the higher elementary functions. This was done in Java anticipating that in the future there might be very low memory configurations and they'd wanna be able to remove the math functions.

That didn't happen because Moore's Law kept cranking on memory capacity so that turned out not to have been a good strategy. But it wouldn't have worked anyway because you'd be throwing away essential things like floor. There's no good way to get the integer part of a number if you get rid of the floor function so it couldn't have worked.

There are also some constants stored in the math object as well. So, one of the worst, or one of the things that we get from the IEEE format is something called NaN, which stands for Not a Number. It's the result of confusing or erroneous operations. For example, if you're trying to divide zero by zero the result is NaN.

NaN is toxic, which means that any arithmetic operation with NaN as an input will have NaN as an output. And despite the fact that NaN stands for Not a Number, it is a number. If you ask JavaScript, what is the type of NaN? It says number and it's right.

>> Douglas Crockford: The thing I hate about NaN is that NaN is not equal to anything including NaN, so NaN equal NaN is false. Which bugs the hell out of me and even worse than that is that NaN not equal NaN is true. Which I hate even more. So if you want to find out if something is NaN, there is a global isNaN function.

And you can pass NaN to it and it will return true, which is good. Unfortunately, isNaN also does type coercion. So if you pass it a string like hello world, it'll try to convert the string into a number. The number that hello world turns into is NaN, so hello world is NaN, which is not true.

>> Douglas Crockford: So ever since Fortran, we've been writing statements that look like this, x = x + 1, which is mathematical nonsense. So ALGOL got this right. ALGOL came up with an assignment operator so this didn't look so ridiculous, and BCPL did the same thing as ALGOL which got it right.

Unfortunately Thompson liked this better, and so we reverted back to it and we have not evolved away from this since. So we're stuck with this and it looks crazy, right? Because it looks like an equation but there's no value of x which equals x + 1 right. Except it turns out if you're using binary floating point, there's a value called infinity.

And, if you add one to infinity, you get infinity so this actually is an equation. There is a value of X for which this is true. And not just that, there's another value called Number.MAX_VALUE which is one followed by 308 digits, that's a really big number. And if you add one to the biggest number that JavaScript knows you would think that would be infinity but it isn't it, it'll be MAX_VALUE, so it holds.

In fact that is true for every number above 9 quadrillion. So there's a lot of values for which this holds.
>> Douglas Crockford: But not NaN. Even though NaN plus one is NaN, NaN is not equal to NaN. So I hate that and NaN, I hate that even more.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now