32

I have this JavaScript function:

Contrl.prototype.EvaluateStatement = function(acVal, cfVal) {

    var cv = parseFloat(cfVal).toFixed(2);
    var av = parseFloat(acVal).toFixed(2);

   if( av < cv) // do some thing
}

When i compare float numbers av=7.00 and cv=12.00 the result of 7.00<12.00 is false!

Any ideas why?

Tomalak
  • 322,446
  • 66
  • 504
  • 612
Harold Sota
  • 7,290
  • 12
  • 55
  • 83

5 Answers5

42

toFixed returns a string, and you are comparing the two resulting strings. Lexically, the 1 in 12 comes before the 7 so 12 < 7.

I guess you want to compare something like:

(Math.round(parseFloat(acVal)*100)/100)

which rounds to two decimals

thomaux
  • 18,290
  • 9
  • 74
  • 97
second
  • 26,808
  • 7
  • 73
  • 75
22

Compare float numbers with precision:

var precision = 0.001;

if (Math.abs(n1 - n2) <= precision) {
  // equal
}
else {
  // not equal
}

UPD: Or, if one of the numbers is precise, compare precision with the relative error

var absoluteError = (Math.abs(nApprox - nExact)),
  relativeError = absoluteError / nExact;

return (relativeError <= precision);
Edward
  • 276
  • 2
  • 5
  • any chance you can explain what it means when one of the numbers is precise, and why you're suggesting the relative error approach? I googled for a while but I cannot understand what you mean or the benefit of your approach in this case. It'd be much appreciated! – mahonya Jan 15 '22 at 15:38
  • 1
    @mahonya the relative error does not depend on magnitude of two values, e.g 1001 and 1000. The absolute error is 1, relative error is 0.001. Sometime exact value is known and approximate value is computed. – Edward Feb 05 '22 at 17:57
  • Thanks for the clarification Edward. – mahonya Feb 05 '22 at 21:14
4

The Math.fround() function returns the nearest 32-bit single precision float representation of a Number.

And therefore is one of the best choices to compare 2 floats.

if (Math.fround(1.5) < Math.fround(1.6)) {
    console.log('yes')
} else {
    console.log('no')
}

>>> yes

// More examples:
console.log(Math.fround(0.9) < Math.fround(1));                            >>> true
console.log(Math.fround(1.5) < Math.fround(1.6));                          >>> true
console.log(Math.fround(0.005) < Math.fround(0.00006));                    >>> false
console.log(Math.fround(0.00000000009) < Math.fround(0.0000000000000009)); >>> false
George C.
  • 5,637
  • 12
  • 49
  • 77
3

Comparing floats using short notation, also accepts floats as strings and integers:

var floatOne = 2, floatTwo = '1.456';

Math.floor(floatOne*100) > Math.floor(floatTwo*100) 

(!) Note: Comparison happens using integers. What actually happens behind the scenes: 200 > 145

Extend 100 with zero's for more decimal precision. For example use 1000 for 3 decimals precision.

Test:

var floatOne = 2, floatTwo = '1.456';
console.log(Math.floor(floatOne*100), '>', Math.floor(floatTwo*100), '=', Math.floor(floatOne*100) > Math.floor(floatTwo*100));
Slava
  • 2,737
  • 2
  • 29
  • 37
2

Comparing of float values is tricky due to long "post dot" tail of the float value stored in the memory. The simplest (and in fact the best) way is: to multiply values, for reducing known amount of post dot digits to zero, and then round the value (to rid of the tail).

Obviously both compared values must be multiplied by the same rate.

F.i.: 1,234 * 1000 gives 1234 - which can be compared very easily. 5,67 can be multiplied by 100, as for reducing the float comparing problem in general, but then it couldn't be compared to the first value (1,234 vel 1234). So in this example it need to be multiplied by 1000.

Then the comparition code could look like (in meta code):

  var v1 = 1.234;
  var v2 = 5.67;

  if (Math.round(v1*1000) < Math.round(v2*1000)) ....
Dharman
  • 26,923
  • 21
  • 73
  • 125
Marek Wysmułek
  • 516
  • 5
  • 6