# The difference between 0. and 0

I have a function for which 0 is a special case:

f[A___, 0, B___] := 0


But since I am doing numerics, sometimes in the course of things f gets called with 0. instead of 0. Of course I can add the line

f[A___, 0., B___] := 0


But I don't understand why I need to because I don't understand the difference between 0 and 0.. Can anyone illuminate this for me?

(In addition to saving a line of code, or as Jens points out, a couple of characters, I also want to know the difference between them so I don't run into hard-to-debug problems in the future because of something I didn't know about.)

-
Mathematica knows the differnece: typing 0.-0 gives the definitive answer: 0. –  bill s Apr 10 '13 at 9:52
Related: (5149) –  Mr.Wizard May 8 at 16:53

0. is an approximate real number that is very close to zero, while 0 is exactly zero. They aren't the same object, as 0 === 0. is False, and 0. has a head of Real, while 0 has a head of Integer.

If you want to turn 0. into 0, you can use Chop, although that will replace all approximate numbers within some tolerance (by default 10^(-10)) of zero with 0.

-
+1 - I was writing essentially the same thing while you posted... –  Jens Jun 18 '12 at 20:00
@Jens, @Pillsy, thanks. I arbitrarily choose this as the correct answer. I have chosen to add the line F[A___, a_?(Equal[#, 0] &), B___] to be safe: I do not want to cut off at less than 10^-10. –  Ian Hincks Jun 18 '12 at 20:08
@Ian I recommend a_ /; a==0 in place of a_?(Equal[#, 0] &) -- it is cleaner, and usually a bit faster. –  Mr.Wizard Jun 18 '12 at 23:24
We also have 0.0*I which is a complex number that is approximately zero. Also have 0.0''200 which is a real number known to have absolute value less than 10^-200. I find it inconsistent that Head[Re[0.0 I]] is Real, but Head[Re[1.0''200 I ]] is Integer. –  Ted Ersek Jun 18 '12 at 23:45

To match all sorts of zero, you can use

F[A___, zero_ /; zero==0, B___] := 0


Another possibility which catches more cases, but also matches some non-zero expressions is to use PossibleZeroQ:

F[A___, _?PossibleZeroQ, B___] := 0

-
I favor this method as well. Don't forget the underscore on the LHS though. –  Mr.Wizard Jun 18 '12 at 21:45
@Mr.Wizard Are you aware of any issues with 0|0.? (I need to use this right now.) –  Szabolcs Apr 10 '13 at 20:43
@Szabolcs only what I illustrated here. Is there some reason you cannot use x_ /; x==0? –  Mr.Wizard Apr 10 '13 at 20:46
@Mr.Wizard Performance concerns (it's for a package so it's difficult to assess the performance impact). Your MatchQ[0.000000000000000000, 0 | 0.] example convinced me, thanks! –  Szabolcs Apr 10 '13 at 21:19

F[A___, 0 | 0., B___] := 0


Now you get zero in both cases.

Regarding the explanation: You obviously know that the 0. comes about when doing numerics, and the reason is that in numerics we're working with approximate real or complex numbers. These are to be distinguished from exact numbers of which 0 is an example.

Both are numbers,

{NumericQ[0], NumericQ[0.]}


{True, True}

but they're different animals as represented by their Head:

{Head[0], Head[0.]}


{Integer, Real}

Therefore, in defining a pattern test, 0 and 0. show up as non-identical.

-

I think it is worthwhile to include a table of how different methods compare when deciding about possible zero value. My advice is to use PossibleZeroQ, but always make sure to handle/be prepared to all extrema. Let me quote the documentation:

The general problem of determining whether an expression has value zero is undecidable; PossibleZeroQ provides a quick but not always accurate test.

ClearAll[x];
expr = {0, 0., 0.*10^-1, 1.1 - 1, 0.0000000000000000000,
0 + \$MachineEpsilon, 0.0001, 0. I, x};

Panel@TableForm[Transpose@{
FullForm /@ expr,
Replace[expr, {0 | 0. -> True, _ -> False}, {1}],
MatchQ[#, 0 | 0.] & /@ expr, (* same as above *)
(# === 0 \[Or] # === 0.) & /@ expr ,(*
not identical to MatchQ above! *)
# == 0 & /@ expr,
(NumericQ@# \[And] # == 0) & /@ expr,
PossibleZeroQ /@ expr (* same as NumericQ && Equal *)
}, TableHeadings -> {expr, {FullForm, "rule matching", MatchQ,
SameQ, Equal, NumericQ && Equal, PossibleZeroQ}}] /.
False -> Item[False, Background -> GrayLevel@.95]


Note that returning False for PossibleZeroQ[x] is not correct mathematically (e.g. x could be zero), but sometimes one really only wants to know whether an expression has a numeric value of zero or not (and x doesn't have a value).

-
Maybe consider 1.1 - 1 as well... –  Ｊ. Ｍ. Apr 9 '13 at 13:42
@J.M. Thanks, added! –  István Zachar Apr 10 '13 at 9:26

Sometimes I define my pattern using a tolerance value to consider zero:

tolerance = 10.^-15;
F[A___, zero_ /; Abs[zero] <= tolerance, B___] := 0;


As said before, using Chop is possible too (and you can use the second argument to set the tolerance):

F[A___, zero_ /; Chop[zero, tolerance]==0, B___] := 0;


And if you want to take more cases (like the cases in PossibleZeroQ), you can wrap your zero by Simplify: Chop[Simplify[zero], tolerance]==0.

-