DEV Community

Serguey Asael Shinder
Serguey Asael Shinder

Posted on

Your parseInt Turned a Tiny Number Into Five

The helper was one line.

Take a number,
drop the fraction,
return the whole part.

Somebody wrote it with parseInt,
because parseInt
has the word int in it.

It worked for a year.

Then a pricing job
divided a small fee
across a very large batch,
and the share per item
came out at
0.0000005.

The helper should have said zero.

It said five.

Nothing threw.

Five went into the report,
and the report was believed.

Nobody checks a small number
that looks like a normal one.

Here is the mechanism.

parseInt does not take a number.

It takes a string.

Hand it a number,
and JavaScript first
turns the number into text.

Most numbers
become the text you expect.

But below one millionth,
JavaScript writes them
in exponent form.

0.0000005
becomes the string
5e-7.

parseInt then does its real job.

It reads digits from the left
and stops at the first character
that is not a digit.

It reads the 5.

It stops at the e.

Five.

The same thing happens at the top.

A number of a sextillion or more
is written as 1e+21,
and parseInt
hands you back a one.

Between those edges
the helper is perfect,
which is why it survives review.

Every test anyone thought to write
lives between those edges.

One, two, ten and a half.

Nobody types
five ten millionths
into a unit test
unless they have already
been bitten by it.

So use the tool
that was built for the job.

Math.trunc
takes a number
and drops the fraction.

No text in the middle.

Math.floor
if you mean round down,
which is a different thing
for negative numbers.

Keep parseInt
for what it was made for.

Text from a form.

Text from a file.

And give it the radix,
ten,
every time.

Then add two lines to the tests.

One very small number.

One very large one.

The bug is never
in what the function does.

It is in what it quietly does first.

– Serguey Asael Shinder

Top comments (0)