Improvement on this function
Jon.Fairbairn at cl.cam.ac.uk
Wed Sep 17 17:43:42 EDT 2003
On 2003-09-17 at 10:31EDT Gordon James Miller wrote:
Something I think is more café than language:
> Hello all.
> I'd be interested in getting some feedback on how to do this linear
> interpolation function a little more cleanly. The normal way that this
> is taught is to find the set of indices in the x list that bracket the
> input value, then use the slope between these points to calculate the y
> value for the input value.
> I had a version working at one point using !! to access particular
> elements but I wasn't sure which one was the better solution.
!! can be expensive.
> linterp :: [Double] -> [Double] -> Double -> Double
> linterp (x1:x2:xs) (y1:y2:ys) x
> | x <= x2 || xs ==  = linterpPair x1 x2 y1 y2 x
> | otherwise = linterp (x2:xs) (y2:ys) x
> where linterpPair x1 x2 y1 y2 x = x1 + (x - x1) * (y2 - y1) / (x2 -
It seems to me that you have too much going on in one
function. It would be better to break it into the part that
finds the point where the interpolation is supposed to
happen and the function that does the interpolation. You
sort-of do this, but don't go far enough for my taste.
You don't say whether the xs are supposed to be in
increasing order. Also it's not obvious that your version
does the right thing in the case where x < head xs, and
linterpPair doesn't look right to me.
linterp :: [Double] -> [Double] -> Double -> Double
linterp xs ys x = linterpPair (neighbours (zip xs ys))
where linterpPair ((x1,y1),(x2,y2)) = y1 + (x - x1) * (y2 - y1) / (x2 - x1)
| x >= x1
= head (dropWhile ((<x). fst . snd) (all `zip` rest))
would be more to my taste, though it would be better to
handle the errors rather than leave them to the runtime
system. I think I would also define the function as
linterp :: [(Double, Double)] -> Double -> Double
since that seems more natural as the data are connected that
way, and it would eliminate a zip.
Jón Fairbairn Jon.Fairbairn at cl.cam.ac.uk
More information about the Haskell-Cafe