For all its warts, JavaScript has some novelties few other languages have. In this post I want to share about JavaScript numbers, which both acknowledge normal mathematics and the fact that they are represented by an imperfect data format.

## Summary

JavaScript numbers are all internally represented by a double-precision floating-point value, which means that there are *perfect* and *imperfect* representations of whole numbers as well as normal double-type floating-point values. Additionally, this is augmented by a few special values representing infinities and impossible numbers. Numbers do not overflow in JavaScript: they become positive or negative infinity. Division-by-zero does not throw an exception: it returns infinity (the limit rule). Nonsense math does not yield nonsense answers: it returns “not a number.”

## Show me!

While I encourage you to read the MDN article on `Number`

, I want to provide a few patterns I have found useful when working in JavaScript that I can’t often use in other languages. In many cases we can turn iffy code (code with conditional branching) into code that simply always works regardless of the input. Here is a list of a few of those patterns. Do you have others up your sleeve?

### Safe Division

If we end up dividing by zero we get `Infinity`

as the result. Often we’ll see something like this written to prevent that:

<br /> const quotient = dividend / ( divisor + 0.0001 )<br />

This is often good enough but there are *pathological cases* that should make us consider this code a bug. What happens if the divisor is small compared to that `0.0001`

? As long as it’s sufficiently large the little extra doesn’t affect the outcome much, but if `divisor === 0.0001`

then this value will cause our result to be half as large as it should be. Solution? We could descend further and further until we’re “sufficiently safe.” Maybe we could put it in a named constant for reuse.

<br /> const EPSILON = 1e-16<br /> const quotient = dividend / ( divisor + EPSILON )<br />

Why `EPSILON`

? Because mathematicians agreed that ε is the smallest unit number. It’s the number which cannot be reached by adding or subtracting, multiplying or dividing. Well, `1e-16`

isn’t small enough for us, but luckily, JavaScript has us covered.

<br /> const quotient = dividend / ( divisor + Number.EPSILON )<br />

See what just happened? It’s already defined for us, and the value is a bit technical but perfect: “the difference between one and the smallest value greater than one that can be represented as a Number.” It’s the smallest difference in values representable by the language. If that value made a significant difference in our calculations then we would have other major problems in our code to take care of.

### Clamping

We often want to limit numbers within certain bounds.

<br /> let a = 15<br /> if ( a > 10 ) {<br /> a = 10<br /> }<br />

This is a noisy and mutable approach. It introduces needless branching (to our eyes, not the computer’s). Thankfully, math has a solution for us.

<br /> const a = Math.max( 10, 15 ) // a === 10<br />

In one line of code we have expressed something that will always conform and we had no `if`

in there. This means fewer lines of code to maintain and fewer opportunities to accidentally break apart the logic of what `a`

should be. And a minimum?

<br /> const clamp = ( min, max, value ) => Math.min( max, Math.max( min, value ) )<br /> const a = clamp( 3, 8, 15 ) // a === 8<br /> const a = clamp( 3, 8, -9 ) // a === 3<br />

Again, we have a single expression valid for all inputs which also indicates our intention: to constrain `a`

within certain bounds (the `if`

provides no such context apart from reading the code within).

### Clamping selections

We often index into lists with a separate indexing variable. Recently I came across a need to grab the last item in the list *if no index were provided* but to grab the indexed item if it had been.

<br /> let item<br /> if ( selectedIndex !== undefined ) {<br /> item = list[ selectedIndex ]<br /> } else {<br /> item = list[ list.length - 1 ]<br /> }<br />

Get’s the job done, but it’s also a bit ugly and noisy. Couldn’t we make more immutable and clean declarations?

<br /> const index = clamp( 0, list.length - 1, selectedIndex )<br />

There, not so bad again – one line. Oh wait, you see a bug? That’s right; what if `selectedIndex`

is `undefined`

? Here we can set a default. Let’s expand our code view…

<br /> const getItem = ( list, selectedIndex = Infinity ) => {<br /> const index = clamp( 0, list.length - 1, selectedIndex )<br /> return list[ index ]<br /> }<br />

We have used `Infinity`

as the default because it will always be bigger than any index we pass in and get clamped down to the last element in the array.

### Fun Facts

Anything divided by `Infinity`

is `0`

. In this example we’re counting how many groups we would need to split a list into n-sized chunks. This is safe with negative numbers, zero, and beyond (we’ll assume we will always need at least one group, even for an empty list).

<br /> const countGroups = ( list, groupSize = Infinity ) =><br /> Math.max( 1, Math.ceil( list.length / groupSize ) )<br />

Everything is smaller than `Infinity`

(except other infinities). Using `Infinity`

as a default value thus allows trivial operations to grab the larger or smaller of a given number *or* the provided number if it’s provided.

<br /> const getHardMax = ( softLimit = Infinity ) => Math.min( softLimit, 1000 )<br /> const getHardMin = ( softLimit = -Infinity ) => Math.max( softLimit, 10 )<br />

Like most languages, we can know if a number is negative or positive with `Math.sign()`

. This is a relative of `Math.abs()`

. We can use it to indicate direction or to enforce the sign at the end of an expression.

<br /> const delta = next - prev<br /> const message = {<br /> [ -1 ]: `decreased by ${ Math.abs( delta ) }º`,<br /> [ 0 ]: 'stayed the same',<br /> [ 1 ]: `increased by ${ Math.abs( delta ) }º`,<br /> }[ Math.sign( delta ) ]<br /> return `The temperature ${ message }`.<br />

The `Math.max()`

and `Math.min()`

operations are *associative*, *commutative*, and *idempotent*, meaning that they can be done in any order any number of times and come to the same result. Honestly; it doesn’t matter how we get to the destination – all the paths bring us to the same place.

<br /> if ( a > runningMax ) {<br /> return a<br /> }<br /> return runningMax<br />

How redundant! If the value hasn’t changed, running it through `Math.max()`

again won’t hurt. It will return the same value.

<br /> return Math.max( a, runningMax )<br />

Notice that we can choose to put `a`

wherever makes more sense reading the code because of the commutativity. It could be *before* `runningMax`

or *after*. In fact, you may be noticing a pattern here for finding the largest value in an array…

<br /> const max = list => list.reduce( Math.max, -Infinity )<br /> const min = list => list.reduce( Math.min, Infinity )<br />

Our old friend `Infinity`

is showing up again. This list *reduction* will iterate over the list and compare the previous value (starting at the smallest possible number) with the next item in the list. It will propagate forward to the end when the highest-valued number will be returned (same accordingly for `min()`

).

## Making impossible states impossible

There are many more patterns like this that will be valuable in our code which can prevent accidentally getting into invalid states. `if`

-assignements can be easy to break since they decouple a value’s logic from its definition or binding. In most cases where we think we need conditional assignment, however, we can use higher-order functions to get around that, such as with `clamp()`

.

Oftentimes we neither have to resort to some clever snippet of code nor to a mangled nesting of branches in order to get a value we want. A pause to think about what we are doing and some basic math can usually clarify the logic in ways we probably didn’t expect. JavaScript’s number system helps us out here too because of how it supports things like `EPSILON`

and `Infinity`

.

Let’s keep an eye out for these cases where the conditionals and the loops and the ternaries open up opportunities for bugs (by us or by future modifications to our code). In those place, maybe a single expression can return our valid desired output no matter what comes in (assuming the types are right: numbers in, numbers out).

Well done and written in a nice way 🙂