33

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
  • 332,285
  • 67
  • 532
  • 628
Harold Sota
  • 7,490
  • 12
  • 58
  • 84

5 Answers5

43

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
  • 19,133
  • 10
  • 76
  • 103
second
  • 28,029
  • 7
  • 75
  • 76
  • 2
    Rounding to two decimals while keeping a number: `Math.round(parseFloat(cfVal)*100)/100` – Tomalak Jul 27 '10 at 12:41
  • This answer is helpful to OP's question. However, this is not helpful for comparison of close float values in Javascript, which needs either a precision value, or multiplying by some multiples of ten to move to integer representation. Then, there is also the question of whether Javascript actually supports integers at all. – Teddy Oct 12 '22 at 10:29
26

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
  • 334
  • 3
  • 5
  • 1
    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
  • 2
    @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
  • Decimal comparison is a language-agnostic problem. Specifying a "precision" is a solution that works in some contexts but it's worthwhile to note its limitation: it may fail when used to implement transitive equivalence relations i.e., it may be true that `(n1-n2) – MTV Jun 20 '22 at 16:57
  • This doesn't answer OP's question. OP is comparing two strings. – ggorlen Sep 05 '22 at 17:53
6

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.
  • 6,574
  • 12
  • 55
  • 80
  • In other words, you are suggesting introducing the same error on both sides so that they become comparable? – Teddy Oct 12 '22 at 10:23
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,887
  • 3
  • 30
  • 39
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
  • 30,962
  • 25
  • 85
  • 135
Marek Wysmułek
  • 786
  • 6
  • 6