Why parseInt(0.0000001) !== 0?

JavaScript Implicit Type Conversion and Scientific Notation.

bitbug
JavaScript in Plain English

--

Preface

A special bug occurred while developing the project. The data field given by the backend is changed from string type to number type. In some extreme cases, there will be problems with the front-end display.

The previous data was ‘0.0000001’ , we use parseInt to get the integer.

parseInt('0.0000001') // equal 0, right.

When the field type changes, we get 0.0000001, something is wrong:

parseInt(0.0000001) // expect 0, but equal 1

Why parseInt(0.0000001) === 1 ?

In order to solve this problem, we first need to understand the usage of parseInt. The syntax of parseInt:

parseInt(string)
parseInt(string, radix)

parseInt accepts a string argument, if the argument is not a string, it will be converted to one using the toString.

So when using parseInt parses a number, it first converts the number to a string and then parses it to a number.

parseInt(number) === parseInt(number.toString());

The steps of parseInt(0.0000001) :

  1. convert 0.0000001 to a string by using Number.prototype.toString
  2. parse the string to number
The steps of parseInt(0.0000001)

The problem seems to be more complicated, (0.0000001).toString() is not '0.0000001' ?

Why (0.0000001).toString() === ‘1e-7’ ?

1e-7 is a scientific notation of numbers. JavaScript will convert any floating-point value with at least six trailing zeros into an annotation by default.

// six trailing zero or more
console.log(0.0000001) // 1e-7
console.log(0.00000000001) // 1e-11
// less then six trailing zero
console.log(0.000001) // 0.000001

If you want to get the scientific notation of a number, you can use the toExponential:

(0.000001).toExponential() // 1e-6

How to make parseInt(0.0000001) === 0

We know that in JavaScript floating-point value with at least six trailing zeros are converted to scientific notation. That makes parseInt not behave as expected, how can we get the right answer?

Fortunately, JavaScript provides toFixed API to get a string of numbers that don’t convert numbers to scientific notation by default.

(0.0000001).toFixed(7) // '0.0000001'

But we have to provide an argument of digits after the decimal place. In order to get the right digits , we can use toExponential by hacking.

function getStringOfFloat(number) {
const notation = number.toExponential();
const [ base, exp] = notation.split('e-');
return number.toFixed(Math.max(base.length - 1, exp));
}
// test it
getStringOfFloat(0.0000001) // '0.0000001'
getStringOfFloat(0.000000000001) // '0.000000000001'
getStringOfFloat(0.100000000001) // '0.100000000001'

If the argument to parseInt is a number, we can get the correct answer in the following way:

parseInt(getStringOfFloat(0.0000001)) // 0

Finally

Thanks for reading, hope it helps you. I’ll expect you to follow me and I’ll provide more useful tips.

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter and LinkedIn. Check out our Community Discord and join our Talent Collective.

--

--