I'm running a program that evaluates equalities after I substitute all symbols for numbers. The equalities on floats are giving me trouble. My program is reaching a point where something like the following is being evaluated:
2.304793200735844`*^-8 == 2.30479302310016`*^-8
. This
gives False, despite the difference being 1.77636*10^-15
, which is below the Chop threshold of 10^-10. Running Chop on both numbers obviously doesn't fix the problem, since neither number is individually below the threshold.
Chop[2.304793200735844`*^-8 - 2.30479302310016`*^-8 ]==0
gives the correct result, but I can't easily make this change as not all comparisons are between floats or even lists of floats (Chop[a-b] == 0 or {0,0,0,...} is not always a valid way to test equality between a and b).
I want to avoid overcomplicating my program: I don't want to do a ReplaceAll on a_==b_ /; (a and b are numbers) -> Chop[a-b]==0
as this is very complicated, requires something like Hold
, and doesn't resolve the same exact issues which arise in the case of float inequality comparisons. There's gotta be a better way! If there's not, what's the best solution?
EDIT: My solution was to modify Equal (==)
for float comparison, and to update List equality to use this new float equality. It's extremely simple, but I think it might slightly slow things down:
Unprotect[Equal]; (* this lets us edit Equal (==) *)
Equal[a_Real,b_Real]:=Chop[a-b]==0 (* change comparison for reals *)
Equal[a_List?RealQ,b_List?RealQ]:=
Dimensions@a==Dimensions@b&&AllTrue[MapThread[#1==#2&,{a,b}],TrueQ] (* update comparison for real lists to use the new real comparison *)
Protect[Equal];
(* True iff r is a real or any nested List containing only reals *)
RealQ[r_]:=Developer`MachineRealQ[r]||Developer`RealQ[r]||(MatchQ[r,_List]&&AllTrue[r,RealQ]);
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)." If you want a different tolerance, useAbs[x1 - x2] < tolerance
$\endgroup$Abs[x1 - x2]/Max@Abs[{x1,x2}] < relTolerance
. This last may be programmed in Mathematica by settingBlock[{Internal`$EqualTolerance = Log10[2*relTolerance/$MachineEpsilon]}, x1 == x2]
. OrBlock[{Internal`$EqualTolerance = Log10[2*relTolerance/$MachineEpsilon]}, code]
in which each==
between real numbers will be compared withrelTolerance
relative tolerance. For your example numbers,relTolerance
should be about7.70723 * 10^-8
or greater. $\endgroup$