It is a well known problem of floating point arithmetic that equality comparisons are unreliable. For example if you try
1.0 == 0.3 + 0.3 + 0.3 + 0.1
in Python or C or any other traditional language, you get false. Why? Because these numbers are not exactly representable in binary the same way as $1/3 = 0.33333333\dots$ is not exactly representable in decimal using a finite number of digits. Due to this, and potentially due to numerical roundoff errors the two sides won't be digit-for-digit equal up to the last binary digit.
You are probably aware of this.
Now try in Mathematica:
In[151]:= 1.0 == 0.3 + 0.3 + 0.3 + 0.1
Out[151]= True
Mathematica tries to be helpful and equality comparisons have some tolerance. This can be controlled by Internal`$EqualTolerance
, which is set to 7 binary digits by default.
Internal`$EqualTolerance
(* 2.10721 *)
Log[2, 10^Internal`$EqualTolerance]
(* 7. *)
This choice of 7 digits is of course rather arbitrary and even though equality comparisons behave in a nice and convenient way most of the time, you must keep in mind that they are not foolproof, and cannot be foolproof even in principle.
The difficulty is that your determinant is zero:
Det@N[{{-1, -5/2}, {-5/2, -25/4}}]
(* 3.46945*10^-16 *)
When saying "equal except for the last 7 binary digits" (or $\sim 2.1$ decimal digits), we are talking about a relative tolerance. Relative tolerances don't really work for zero values because we can't divide by zero. Or rather: since floating point numbers are stored as a separate exponent and mantissa, once the result is zero, the last few normally insignificant mantissa digits are shifted up into positions which appear significant.
People have already pointed out Chop
, which deals exactly with this problem. It converts floating point numbers smaller than a certain threshold ($10^{-10}$ by default) into exact 0
. I.e. it uses an absolute tolerance, not a relative one.
Another way to deal with it is to use Mathematica's arbitrary precision inexact numbers instead of machine precision numbers. The former have built-in precision tracking, so the system can detect that a zero that arises due to catastrophic cancellation has very few accurate digits. This is also not foolproof, but it's much better than no precision tracking at all. Arbitrary precision numbers can be forced by SetPrecision
or by using N
with a second argument on exact numbers. Observe:
Det[{{a, b}, {b, d}}]
(* -b^2 + a d *)
% /. N[{a -> -1, b -> -5/2, d -> -25/4}, 10]
(* 0.*10^-9 *)
Accuracy[%]
(* 8.60206 *)
%% == 0
(* True *)
The result is zero, but it has lost some accuracy. The zero comparison evaluates to True
.
Unfortunately, when using Det
directly on such an arbitrary precision matrix, it doesn't perform the precision tracking:
Det@N[{{-1, -5/2}, {-5/2, -25/4}}, 10]
(* -1.469367939*10^-38 *)
{Accuracy[%], Precision[%]}
(* {47.8329, 10.} *)
Note that we have both Precision
and Accuracy
in Mathematica. The former is a relative measure, the latter an absolute one. Since Precision
is a relative measure, it is less meaningful with a zero result.
Chop@Det[{{-1, -2.5}, {-2.5, -6.25}}] == 0
yieldsTrue
. $\endgroup$0.
.exp := Det[{{-1, -2.5}, {-2.5, -6.25}}]
, then{CloudEvaluate[exp], exp}
. Difference in OS maybe? $\endgroup$