37

I'm having a big problem with number comparison in javascript.

The script accuses that the comparison "7 < 10" is false.

console.clear();

var min = parseFloat("5").toFixed(2);
var max = parseFloat("10").toFixed(2);
var value = parseFloat("7").toFixed(2);

console.log(min, max, value);

console.log(value > min); // OK.
console.log(value < max); // ---- false ??????

Anyone knows what is happing?

Alexandre Perez
  • 3,155
  • 3
  • 20
  • 21

2 Answers2

54

As it turns out .toFixed() returns strings - Try adding parseFloat before comparing the values to see the result:

console.log(parseFloat(value) < parseFloat(max)); // ---- now true
prototype
  • 3,163
  • 2
  • 25
  • 42
  • I wouldn't do it if I were you. Try this to find out why ;) `console.log(parseFloat(6760/100*100) < parseFloat(6760));` Check my full answer below https://stackoverflow.com/a/55164784/1737158 – Lukas Liesis Mar 14 '19 at 14:15
  • 1
    is not working! my example: ```javascript 3 === 2.999999999999999999 => true parseFloat(3) === parseFloat(2.999999999999999999) => true ``` – Crisan Lucian Oct 28 '19 at 08:42
  • 1
    JavaScript is weird in comparing floating point numbers - i'd recommend either avoiding them completely (when possible) or using third party solution. Here is a good read - https://dev.to/alldanielscott/why-floating-point-numbers-are-so-weird-e03 – prototype Oct 28 '19 at 12:12
15

You should always round float numbers or you will get weird results on some cases.

Try this to see the issue: console.log(parseFloat(6760/100*100));

With rounding, you will get correct results:

console.log(Math.round(parseFloat(value)*100000) < Math.round(parseFloat(max)*100000));

Or you can try using something like: http://mikemcl.github.io/decimal.js/

Floating-point numbers are not accurate numbers they are a close representation of the numbers.

It's actually pretty simple. When you have a base 10 system (like ours), it can only express fractions that use a prime factor of the base. The prime factors of 10 are 2 and 5. So 1/2, 1/4, 1/5, 1/8, and 1/10 can all be expressed cleanly because the denominators all use prime factors of 10. In contrast, 1/3, 1/6, and 1/7 are all repeating decimals because their denominators use a prime factor of 3 or 7. In binary (or base 2), the only prime factor is 2. So you can only express fractions cleanly which only contain 2 as a prime factor. In binary, 1/2, 1/4, 1/8 would all be expressed cleanly as decimals. While 1/5 or 1/10 would be repeating decimals. So 0.1 and 0.2 (1/10 and 1/5) while clean decimals in a base 10 system, are repeating decimals in the base 2 system the computer is operating in. When you do the math on these repeating decimals, you end up with leftovers which carry over when you convert the computer's base 2 (binary) number into a more human-readable base 10 number. Source


This is not JavaScript's issue. It happens because the computer really understands just 1 and 0.

If you want to dive deep into the topic, I suggest this as a starting point: https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Lukas Liesis
  • 21,304
  • 8
  • 101
  • 99