
Way back when I started with haskell I noticed this, and switched to using
this:
-- | Enumerate an inclusive range. Uses multiplication instead of
successive
-- addition to avoid loss of precision.
--
-- Also it doesn't require an Enum instance.
range :: (Num a, Ord a) => a -> a -> a -> [a]
range start end step = go 0
where
go i
| step >= 0 && val > end = []
| step < 0 && val < end = []
| otherwise = val : go (i+1)
where val = start + (i*step)
It's always seemed better in every way, except syntax convenience.
Wouldn't any approach with successive addition lose precision?
On Tue, Aug 9, 2016 at 8:22 PM, Andrew Farmer
Noticed this today:
ghci> let xs = [0.0,0.1 .. 86400.0] in maximum xs 86400.0000005062
enumFromThenTo is implemented by numericEnumFromThenTo:
https://github.com/ghc/ghc/blob/a90085bd45239fffd65c01c24752a9 bbcef346f1/libraries/base/GHC/Real.hs#L227
Which probably accumulates error in numericEnumFromThen with the (m+m-n):
numericEnumFromThen n m = n `seq` m `seq` (n : numericEnumFromThen m (m+m-n))
Why not define numericEnumFromThen as:
numericEnumFromThen n m = let d = m - n in d `seq` go d n where go delta x = x `seq` (x : go delta (x + delta))
(or with BangPatterns)
numericEnumFromThen n m = go (m - n) n where go !delta !x = x : go delta (x + delta)
Seems like we'd save a lot of subtractions by using the worker function. _______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs