23
$\begingroup$

I am getting these results:

0.999999999999988 < 1.0  (*False*)
0.999999999999988 >=  1.0  (*True*)
0.999999999999988 ===  1.0  (*False*)

Block[{$MinPrecision = $MachinePrecision, $MaxPrecision=$MachinePrecision}, 0.999999999999988 >=  1.0] (*False*)


N[0.999999999999988 -  1.0]  (*small negative number, but larger in magnitude than machine precision*)

PossibleZeroQ[N[0.999999999999988 -  1.0]]  (*False*)

Is there a workaround?

$\endgroup$
6
  • $\begingroup$ I think you found the work around: instead of testing a == b, check a - b == 0 (same with <, >). The normal rules of arithmetic don't necessarily apply when you're working with floating point numbers. $\endgroup$ Commented Mar 15, 2021 at 16:27
  • 2
    $\begingroup$ 0.999999999999988`17. >= 1.`17. gives False See also Possible Issues in the documentation of Equal. $\endgroup$ Commented Mar 15, 2021 at 16:27
  • 1
    $\begingroup$ Finding that this was the source of a larger problem was a (time-consuming) surprise. I think that including this in Possible Issues for Less would be helpful, or perhaps an option for Less[a,b,NumericalPrecision->xxx]? $\endgroup$ Commented Mar 15, 2021 at 16:51
  • 1
    $\begingroup$ Related/duplicate: (48810), (132890) $\endgroup$
    – Michael E2
    Commented Mar 15, 2021 at 20:40
  • $\begingroup$ Oh, I was looking in the docs at LessThan (where "Possible Issues" is absent). I see it in Less now. Thanks. $\endgroup$ Commented Mar 15, 2021 at 20:47

3 Answers 3

26
$\begingroup$

You can lower the value of Internal`$EqualTolerance:

Block[{Internal`$EqualTolerance = 0},
  0.999999999999988 >= 1.0 
]
False

This can lead to unexpected behaviors too:

Block[{Internal`$EqualTolerance = 0},
  0.1 + 0.2 == 0.3 
]
False

Maybe there's a better sweet spot that fits your needs. For these two examples, this works:

Block[{Internal`$EqualTolerance = Internal`$SameQTolerance},
  0.999999999999988 >= 1.0 
]
False
Block[{Internal`$EqualTolerance = Internal`$SameQTolerance},
  0.1 + 0.2 == 0.3 
]
True

If you have a nice representative sample of values you're comparing, you can estimate a value for Internal`$EqualTolerance by plotting. These two examples return correct comparisons for values between Log10[5/3] and Log10[108]:

correctEquals[x_?NumericQ] := 
  Block[{Internal`$EqualTolerance = x}, 
    Boole[Not[0.999999999999988 >= 1.0] && (0.1 + 0.2 == 0.3)]
  ]

Plot[correctEquals[x], {x, 0, Internal`$EqualTolerance}]

$\endgroup$
6
  • $\begingroup$ This would be a great addition to the Documentation or in a Guide. Excellent answer. $\endgroup$ Commented Mar 15, 2021 at 17:32
  • 1
    $\begingroup$ This explains why 0.999999999999988 >= 1.0 was true, but it doesn't explain why 0.999999999999988 === 1.0 was simultaneously false. $\endgroup$ Commented Mar 16, 2021 at 3:19
  • 1
    $\begingroup$ @BlueRaja-DannyPflughoeft : "SameQ requires exact correspondence between expressions, except that it still considers Real numbers equal if they differ in their last binary digit." and RealDigits[#, 2] & /@ {0.999999999999988, 1.0} exhibits discrepancy long before the last binary digit. If you meant 0.999999999999988 == 1.0, at least on M'ma 11.3, this gives True. $\endgroup$ Commented Mar 16, 2021 at 4:20
  • 1
    $\begingroup$ Any insight as to why the values that work in this case are exactly Log10[5/3] and Log10[108] ? $\endgroup$
    – Carmeister
    Commented Mar 16, 2021 at 16:46
  • $\begingroup$ Good question, I'm curious to know why too. $\endgroup$
    – Greg Hurst
    Commented Mar 16, 2021 at 18:13
11
$\begingroup$

From the help.

Equal (==): Approximate numbers with machine precision or higher are considered equal if they differ in at most their last seven binary digits (roughly their last two decimal digits).

This explains the fist two cases: 0.999999999999988 and 1. differ by less than 7 digits.

SameQ (===): SameQ requires exact correspondence between expressions, except that it still considers Real numbers equal if they differ in their last binary digit.

As 0.999999999999988 and 1. differ by more than one digits they, are considered different.

$\endgroup$
4
$\begingroup$
Sign[ 0.999999999999988 - 1.0]

-1

$\endgroup$
1
  • 2
    $\begingroup$ This approach has its limitations: for example, following the documentation, Block[{$MaxExtraPrecision = 10000}, N[Sign[0.9999999999999999999999 - 1.0], 40]] produces 0. $\endgroup$
    – user64494
    Commented Mar 15, 2021 at 17:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.