# Strange behavior of MemberQ, Position

After importing an array of latitudes and longitudes and trying to find the position of some latitudes I was encountered with an unexpected problem since certain values could not be found for some reason. Position and MemberQ behave the same.

Everything works just fine if converted to strings.

I work with Mathematica Version 9.

Example:

r = Range[39.7026, 39.703, 0.0001];
r == {39.7026, 39.7027, 39.7028, 39.7029, 39.703}

True

MemberQ[r, #] & /@ r

{True, True, True, True, True}

MemberQ[r, #] & /@ {39.7026, 39.7027, 39.7028, 39.7029, 39.703}

{True, True, False, True, True}

Position[r, #] & /@ r

{{{1}}, {{2}}, {{3}}, {{4}}, {{5}}}

Position[r, #] & /@ {39.7026, 39.7027, 39.7028, 39.7029, 39.703}

{{{1}}, {{2}}, {}, {{4}}, {{5}}}


Out of the 1001 values of the following list rr, this problem is encountered with 17 of them

rr = Range[39.69, 39.79, 0.0001];


Notice the spacings of 30

Positions:

{{92}, {122}, {199}, {229}, {259}, {336}, {366}, {443}, {473},
{503}, {580}, {610}, {717}, {747}, {824}, {854}, {884}}


Values:

{39.6891, 39.6921, 39.6998, 39.7028, 39.7058, 39.7135, 39.7165, 39.7242, 39.7272,
39.7302, 39.7379, 39.7409, 39.7516, 39.7546, 39.7623, 39.7653, 39.7683}

• Your problem arises from the machine precision approximate reals generated by Range sometimes wandering a little too much from the ones you type in by hand. Jul 17, 2014 at 11:24
• All: this is a duplicate of a number of earlier questions. Please find and appropriate one and mark this for closure. Jul 17, 2014 at 13:45
• @Mr.Wizard duplicate of (15907), but the explanation given in that one is not as complete as here because it references a post on SO for the rationale rather than reiterating it. Could I suggest that they be merged, possibly including the SO answer (or a copy of it)? Jul 17, 2014 at 14:36
• @Oleksandr Thanks for looking. However I know that's not the best one; there have been others where people detailed the behavior of floating-point binary numbers in decimal representation -- more than once I think. I'll try to return to search for that later. Jul 18, 2014 at 0:12

To paraphrase Oleksandr's comment to this answer: Not all numbers with a finite number of digits in base 10 can be also expressed with a finite number of digits in base 2. Look at this:

r // FullForm
(* Out: List[39.7026,39.7027,39.702799999999996,39.7029,39.702999999999996] *)


and compare it with

{39.7026, 39.7027, 39.7028, 39.7029, 39.703} // FullForm
(* Out: List[39.7026,39.7027,39.7028,39.7029,39.703] *)


== returns true because according to the documentation

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). For numbers below machine precision the required tolerance is reduced in proportion to the precision of the numbers.

but since some of these numbers aren't actually equal it can have unexpected results. This is also due to how Position etc. works; the other answers complement this answer and provide more detail.

• I guess it is obvious that this is what's happening. Any ideas about the spacings of 30 between the problematic values? Jul 17, 2014 at 11:22
• @zoutoftime Well, some questions remain: Why does Range do this? Why does it affect the third element but not the fifth? I noticed you were unsure whether to accept now or not; it wouldn't be wrong at all to wait for a couple of hours to see if someone answers it more authoritatively before accepting this answer (or another potentially better). Jul 17, 2014 at 11:25
• The reason is really no mystery; not all numbers with a finite number of digits in base 10 can be also expressed with a finite number of digits in base 2. If not, then you get a truncated binary fraction, which comes out as a decimal number very close, but not exactly equal, to the desired value. Jul 17, 2014 at 11:33
• @OleksandrR. Thanks, I quoted you in the answer since this is what the answer should have said from the beginning. Jul 17, 2014 at 13:40

Position[r, n_ /; n == #] & /@ {39.7026, 39.7027, 39.7028, 39.7029, 39.703}
(* {{{1}}, {{2}}, {{3}}, {{4}}, {{5}}} *)

• PS. Thanks for an excellent question. I would have never noticed this issue if it were not brought up on here. Jul 17, 2014 at 11:28

In addition to Pickett's answer, you can use Round to get closer to the expected behaviour (see also this answer):

r = Round[Range[39.7026, 39.703, 0.0001], 0.0001];
r // InputForm


{39.702600000000004, 39.7027, 39.7028, 39.7029, 39.703}

MemberQ[r, #] & /@ {39.7026, 39.7027, 39.7028, 39.7029, 39.703}


{True, True, True, True, True}

I don't know why the first element of r isn't completely rounded as I would have expected; perhaps someone else can elucidate on that.