Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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}
share|improve this question
2  
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 at 11:24
1  
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 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 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 at 0:12

3 Answers 3

up vote 5 down vote accepted

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.

share|improve this answer
    
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 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). –  Pickett Jul 17 at 11:25
3  
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 at 11:33
    
@OleksandrR. Thanks, I quoted you in the answer since this is what the answer should have said from the beginning. –  Pickett Jul 17 at 13:40

Mathematica graphics

Position[r, n_ /; n == #] & /@ {39.7026, 39.7027, 39.7028, 39.7029, 39.703}
(* {{{1}}, {{2}}, {{3}}, {{4}}, {{5}}} *)
share|improve this answer
    
PS. Thanks for an excellent question. I would have never noticed this issue if it were not brought up on here. –  seismatica Jul 17 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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.