7
$\begingroup$

I'm having some problems with Position.

Sometimes it will give an empty list instead of the actual position of the element I am looking for when that element is specified through some other code, but will return the correct position when the element is specified directly as a number as in the minimum working example below.

data = {{0.1, 0.0001683}, {0.2, 0.00035754}, {0.3, 0.00056711}, {0.4, 
   0.00078986}, {0.5, 0.0010333}, {0.6, 0.0010333}, {0.7, 
   0.0015758}, {0.8, 0.0018738}, {0.9, 0.0022054}, {1., 
   0.0025706}, {1.1, 0.0029788}, {1.2, 0.0034366}, {1.3, 
   0.0039831}, {1.4, 0.0046433}, {1.5, 0.0055203}, {1.6, 
   0.0068061}, {1.7, 0.010939}, {1.8, 0.031246}, {1.9, 0.054948}, {2.,
    0.076556}, {2.1, 0.098521}, {2.2, 0.12551}, {2.3, 0.1585}, {2.4, 
   0.1921}, {2.5, 0.22544}, {2.6, 0.25798}, {2.7, 0.28992}, {2.8, 
   0.32051}, {2.9, 0.35095}, {3., 0.38104}}

interpol = Interpolation[data];

q = FindRoot[interpol[x] == 0.159, {x, 2.9}][[1, 2]]
(*2.3015*)

xlow = Floor[q, 0.1]
(*2.3*)

Position[data[[All, 1]], xlow]
(*{}*)

Position[data[[All, 1]], 2.3]
(*{{23}}*)

When running Mathematica 8 on Windows XP, this code returns {} for the first output and {{23}} for the second.

This type of error is mentioned in the Possible Issues section of the documentation for Position in v8 and v9, but no advice is given.

In[1] := Position[Range[-1, 1, 0.05], 0.1]
Out[1] = {}

I thought this might be a precision or representation issue (i.e., 2.3 vs 23/10), so I've tried using N everywhere to get around the issue, but with no success. Does anyone have a nifty work around or solution to this problem?

$\endgroup$
3
  • 2
    $\begingroup$ Would Position[data[[All, 1]], Nearest[data[[All, 1]], xlow][[1]]] be acceptable ? $\endgroup$ Commented Dec 7, 2012 at 10:25
  • $\begingroup$ It works so it most certainly would be acceptable! Thanks for the fast reply. $\endgroup$
    – fizzics
    Commented Dec 7, 2012 at 10:40
  • 1
    $\begingroup$ Since I believe the correct answer is to use Chop (see below), it's also worth pointing to this and this. $\endgroup$
    – Jens
    Commented Dec 8, 2012 at 18:26

2 Answers 2

15
$\begingroup$

Position is looking for an exact match (pseudo-SameQ), rather than a numeric one.
You will get the result you want with:

Position[data[[All, 1]], _?(# == xlow &)]

Or:

Position[data[[All, 1]], x_ /; x == xlow]

Generally you should use Equal (short form ==) any time you are trying to mach Real numbers, to allow for small rounding errors.

Using the pattern 0 | 0. is not sufficient; See this for examples.


For an excellent treatment of the problems of matching inexact numbers see:

Instability in DeleteDuplicates and Tally

$\endgroup$
2
  • $\begingroup$ Thanks for the fast reply. Both of those do the job perfectly but I'm a bit confused by the structure you use in the first one. Wouldn't the _? return a True value instead of a numeric? The second structure I don't fully understand either as I don't see how Position knows to loop over x and compared each term. There is obviously more functionality built in than I appreciate $\endgroup$
    – fizzics
    Commented Dec 7, 2012 at 10:37
  • 2
    $\begingroup$ @fizzics Both _?(# == xlow &) and x_ /; x == xlow are patterns, which is what Position needs as a second argument. _?testfunction is a pattern for any single expression for which testfunction yields True when applied. x_ /; expr is a pattern for any single expression, which we locally name x, for which expr evaluates to True; if x appears in expr the local definition is used. Read the documentation for Pattern, PatternTest, and Condition, then see this question. Return with any further questions. $\endgroup$
    – Mr.Wizard
    Commented Dec 7, 2012 at 11:27
8
$\begingroup$

One alternative approach that is very powerful when dealing with approximate real numbers hasn't been mentioned yet: use Chop or Threshold.

These two functions are intended for just the type of situations you describe, so I would always try them first:

In your example, this simple command works:

Position[Chop[data[[All, 1]] - xlow], 0]

{{23}}

Instead of finding xlow, I reformulated the problem so that you find 0 in the list of differences with xlow.

$\endgroup$
1
  • $\begingroup$ Excellent recommendation. Numeric methods are almost always faster. $\endgroup$
    – Mr.Wizard
    Commented Dec 8, 2012 at 22:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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