- Written forms
- Zero division,
`Infinity`

`NaN`

- Conversion to a number
- Permissive conversion:
`parseInt`

and`parseFloat`

- Imprecise calculations
- Rounding
- Random numbers
- Summary

All numbers in JavaScript, both integer or floating-point are of type `Number`

.

Internally a number is represented by the floating-point format IEEE 754, also called “double precision”. There are 8 bytes per number.

The maximal integer value is about `2`

.^{53}

## Written forms

In JavaScript, it is possible to write numbers using hexadimal or octal radix:

alert( 0xFF ) // 255 in hexadimal form, starts with 0x alert( 010 ) // 8 in octal form, starts with 0

A so-called *scientific* form is also available, it consists of a number followed by “e” and quantity of zeroes.

For example, `1e3`

is 1 with 3 zeroes, effectively 1000.

// scientific form: 3 with 5 zeros alert( 3e5 ) // 300000

If the quantity of zeroes is negative, then the number is shifted past the decimal point.

// shift 5 times past the decimal point. alert( 3e-5 ) // 0.00003

## Zero division, `Infinity`

Imagine, you are to create a new language. People will call it “JavaScript” (or LiveScript.. whatever).

What should happen if someone divides by zero?

Usually the answer is “Zero Division Error”. At least, for most programming languages it is like that.

But JavaScript creators decided to go more mathematical way. In maths, when you divide by 0, you get *Infinity* (or `-Infinity`

).

Same in JavaScript:

alert(1/0) // Infinity alert(-1/0) // -Intinify

`Infinity`

is a special numeric value in JavaScript and behaves just like it should. Infinity is larger than any other number. Adding anything to `Infinity`

doesn’t change it:

alert(Infinity > 999999999999999999999999999); alert(Infinity + 5 == Infinity);

So there is no error, just infinity.

`NaN`

If a mathematical operation can’t be performed, it returns a special pseudo-numerical value: `NaN`

(Not-A-Number).

For example, division of zero by zero is not defined in mathematical sense, so it returns `NaN`

.

alert( 0 / 0 ) // NaN

`NaN`

has following properties:

`NaN`

is*not equal to anything*, including itself.The code below is silent:

if (NaN == NaN) alert("== works"); // Neither of these if (NaN === NaN) alert("=== works"); // will work

`NaN`

can be checked only by`isNaN`

- a special function which returns`true`

for`NaN`

and`false`

for any other value.

var n = 0/0 alert( isNaN(n) ) // true

`NaN`

is sticky. Any math operation with`NaN`

gives`NaN`

.

alert( NaN + 1 ) // NaN

Mathematical operations can’t lead to an error or crash in JavaScript.

At worst, `NaN`

is returned.

## Conversion to a number

**The strict conversion can be done by “+”**

var s = "12.34" alert( +s ) // 12.34

The string is parsed and if its format is numeric, then the number is returned.

Actually, all mathematical functions excepts binary plus `'+'`

convert a string to number:

var s = "12.34" alert( -"12.34" / "2" ) // -6.17

**Parsing into a number ignores whitespaces at start and end.** For example:

alert( +" 12") // 12 alert( +" \n34 \n") // 34, newlines are whitespace symbols too

If the value can’t be converted to a number, the operation returns `NaN`

:

alert( +"12test" ) // NaN

`isNaN`

converts it’s argument into a number automatically. So it can be used to check whether a string represents a number:

var x = "-11.5" if (isNaN(x)) { alert("Not a number") } else { alert("Number") // isNaN(x) = false means it's a number }

But please, be careful, because a string with whitespaces is converted to `0`

:

alert(isNaN(" \n\r\t ")) // false, "..spaces.." is 0

And, of course `isNaN`

won’t work for other types, because `false, null, undefined`

are also converted to `0`

.

Actually, the most reliable conversion check is either a regexp or `isNumeric`

below:

function isNumeric(n) { return !isNaN(parseFloat(n)) && isFinite(n) }

`isNumeric`

correctly checks numericality for all input types.
Make an interface to prompt for two numbers and then alert their sum.

It should work like this page.

Note. There’s a pitfall ahead. Watch the types.

Check source for the solution: tutorial/intro/sum.html.

## Permissive conversion: `parseInt`

and `parseFloat`

In real-life, many values are not exactly numbers. Especially, those “10pt” or “-12px” used in CSS.

The “+” operator can’t convert them into a number, because it checks the strict format. It will return `NaN`

:

alert( +"12px" ) // NaN

That’s where `parseInt`

jumps in:

var v = parseInt('12px') alert(v)

`parseInt`

and its friend `parseFloat`

convert the value character by character until they meet something impossible to convert. Then it stops and returns what could be converted.

alert( parseFloat('12.3.4') ) // 12.3, 1st dot is fine, but not the 2nd

A minor pitfall with `parseInt`

on some browsers is that ECMAScript specification allows it to guess the radix.

The older version of the specification treats a string starting with 0 in `parseInt`

as octal:

alert( parseInt('0xFF') ) // 255 alert( parseInt('010') ) // in some browsers 8, because 0 means octal

If you want be sure that “010” means 10, use the second optional argument to pass the radix:

alert( parseInt('010', 10) )

Note, `parseInt/parseFloat`

returns `NaN`

if conversion stops at first char:

alert( parseInt('a123') )

## Imprecise calculations

The floating point format leads to loss of precision. Minor computational errors may occur.

Please, run the following:

alert(0.1 + 0.2 == 0.3)

Did you run it? If not, please do.

Ok, you did. So what’s up? Maybe the browser is buggy? Change the browser, run it again.

Ok, well, now you can be sure: `0.1 + 0.2`

is not `0.3`

. Then what is it?

alert(0.1 + 0.2)

Now you see, there is a minor calculation error.

That’s because internal floating-point format represents a number in binary form. But, just like 1/3 can’t be represented in decimal form (it’s 0.3333…),

0.1(=1/10) cannot be exactly represented as binary, and 0.2(=2/10) as well.

Their binary representations are cut at some point. Here you are:

alert( 0.1.toFixed(20) ) // 0.10000000000000000555

When you sum two inaccuracies, you get the minor calculation error.

Of course, that doesn’t mean you can’t sum numbers in JavaScript. In fact, you can.

Actually, there are two ways to sum 0.1 and 0.2:

- Make them integers, sum and then divide back:

alert( (0.1*10 + 0.2*10) / 10 ) // 0.3

It works, because 1 and 2 can be represented in binary form exactly. So, the sum is exact.

- Sum and then round to fixed precision as described in the next section. Rounding to 10-th decimal digit will chop off the calculation error.

alert( +(0.1+0.2).toFixed(10) )

Look, I’m a self-increasing number!

alert(9999999999999999)

The reason is, of course, precision loss. The number format cannot store that many digits exactly.

The following loop hangs up the browser. Why?

var i = 0 while(i != 10) { i += 0.2 }

That’s because `i`

never equals `10`

.

Run the following to see *real* values of `i`

:

var i = 0 while(i < 11) { i += 0.2 if (i>9.8 && i<10.2) alert(i) }

Note that neither value equals `10`

.

## Rounding

One of most often operations with numbers is rounding. In JavaScript, there are 3 functions for basic rounding.

`Math.floor`

- Rounds down
`Math.ceil`

- Rounds up
`Math.round`

- Rounds to nearest

alert( Math.floor(3.1) ) // 3 alert( Math.ceil(3.1) ) // 4 alert( Math.round(3.1) ) // 3

Note how `floor`

and `ceil`

work for negative numbers:

alert( Math.floor(-3.1) ) // -4, rounds to nearest less than -3.1 alert( Math.ceil(-3.1) ) // -3, rounds to nearest greater than -3.1

Bitwise operators cut off the decimal part automatically when applied.

In the example below, `12.3`

is rounded by XOR’ing with 0:

alert( 12.3^0 ) // 12

The XOR `^0`

was chosen, because it doesn’t change the number. Any bitwise operator, which doesn’t modify the number, will do. For example, double NOT `~~12.3`

, right shift to 0 bits `12.3>>0`

etc.

Note that for negative numbers cutting of the decimal part is not the same as `Math.floor`

.

### Rounding to given precision

It is often required round to precision, like: two digits after the decimal point. An old trick is multiply and divide on 10 with given number of zeroes:

var n = 3.456 alert( Math.round( n * 100 ) / 100 ) // 3.456 -> 345.6 -> 346 -> 3.46

`toFixed(precision)`

There is also a method `toFixed(precision)`

can be called directly on a number.

It rounds the number to given precision and returns a string:

var a = 12.34 alert( a.toFixed(1) ) // "12.3"

The returned string is right-padded with zeroes if needed:

var a = 12.34 alert( a.toFixed(5) ) // "12.34000"

So, if we need a number, we can convert it back by adding “+” to `n.toFixed()`

:

var a = 12.34 alert( +a.toFixed(5) ) // 12.34

## Random numbers

The `Math.random()`

returns a random number from 0(inclusive) to 1(exclusive):

alert( Math.random() )

Most often recipes regarding random numbers are represented as a set of tasks. Check them out below.

Write a code to return a random float value between `0`

(inclusive) and `max`

(exclusive).

What we need is to generate a value between `0..1`

and multiply it by `max`

:

var max = 10 alert( Math.random()*max )

Write a code to return a random float value between `min`

(inclusive) and `max`

(exclusive).

The classical way to solve it is to generate a random value in range `0..max-min`

, then shift it by `min`

.

var min=5, max = 10 alert( min + Math.random()*(max-min) )

Write the code to generate a random **integer** value between `min`

and `max`

, with both `min,max`

as possible values.

Any value from `min..max`

range should happen with the same probability.

## The wrong way

A first idea could be to generate a value between `min..max`

and round it.

But the probability of edge values `min`

and `max`

will be two times less than any other value.

For example, let’s find random between 1 and 3. We take the following code as the source:

// random float value from min(inclusive) to max(exclusive) var rand = min + Math.random()*(max-min) // so for 1 and 3 var rand = 1 + Math.random()*(3-1)

The `Math.round()`

will map the resulting `rand`

like this:

1 ... 1.499+ will map to 1 1.5 ... 2.499+ will map to 2 2.5 ... 2.999+ will map to 3

Note that the first range (for 1) is of length 0.5, the second (for 2) has length 1, and the third range is again 0.5.

So, 2 will happen two times more often than 1 or 3, the probability will not be same as required.

## The good way

A better way is to `Math.floor()`

a number from `min`

to `max+1`

.

So, to find a random integer between 1 and 3, we need to generate a random float between 1(inclusive) to 4(exclusive) first.

Then the `Math.floor()`

will map them like this:

1 ... 1.999+ will map to 1 2 ... 2.999+ will map to 2 3 ... 3.999+ will map to 3

You can see, the ranges are same, so the probability is uniform.

The resulting code is:

var min=5, max=10 *!* var rand = min + Math.random()*(max+1-min) rand = Math.floor(rand) */!* alert(rand)

## Another nice solution

The following also works. Please figure out why.

var rand = Math.round(random(min-0.5, max+0.5))

## Summary

In this section you’ve learned about numbers in JavaScript:

- Which written forms exist.
- An imprecision which is a consequence of the internal number format.
- How errors are handled:
`Infinity`

and`NaN`

. - How to round numbers.
- How to convert a string to number in a permissive way, for values like “12px”.

There are more methods and mathematical actions upon numbers. Consult the manual about Number and Math objects.