# 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. – m_goldberg Jul 17 '14 at 11:24
• All: this is a duplicate of a number of earlier questions. Please find and appropriate one and mark this for closure. – Mr.Wizard Jul 17 '14 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)? – Oleksandr R. Jul 17 '14 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. – Mr.Wizard Jul 18 '14 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? – zoutoftime Jul 17 '14 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). – C. E. Jul 17 '14 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. – Oleksandr R. Jul 17 '14 at 11:33
• @OleksandrR. Thanks, I quoted you in the answer since this is what the answer should have said from the beginning. – C. E. Jul 17 '14 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. – seismatica Jul 17 '14 at 11:28