debugMinor
Haskell function to error-diffuse a floating value to a list of integers
Viewed 0 times
errorfloatingfunctionvalueintegershaskelldiffuselist
Problem
I needed to write a function which would 'error diffuse' floating values to integers:
So that, for example:
(i.e., the function produces a list of
Is there a better way to write this sort of
errorDiffuse :: Double -> Int -> Double -> [Int]
errorDiffuse _ 0 _ = []
errorDiffuse v num err = tv : errorDiffuse v (num - 1) (err + v - fromIntegral tv)
where tv = truncate (v + err)So that, for example:
errorDiffuse 1.4 10 0 => [1,1,2,1,1,2,1,2,1,1](i.e., the function produces a list of
num integers, each of which is the ceiling or floor of v, starting with a given error value (zero in this case)).Is there a better way to write this sort of
for loop? What's the higher-order function I ought to be thinking in terms of?Solution
First I'd get rid of the dependency on
and you can use
So we have:
Then I'd think about generating the list of
Since we're trying to generate a list, that makes me think of
which you can find in Data.List:
The unfold takes a function that, given a seed, produces the next
value in the outputted list, along with a new seed. The function
starts with an intitial seed, and keeps using those seeds, adding to the
list until the function returns
The function we're looking for is the following:
Our list is infinite, so we always return a
Putting things together we have:
num, since that's just a counter,and you can use
take num on an infinite list of errorDiffuses:errorDiffuses :: Double -> Double -> [Int]
errorDiffuses v err = tv : errorDiffuses v (err + v - fromIntegral tv)
where
tv = truncate (v + err)So we have:
errorDiffuse' :: Double -> Int -> Double -> [Int]
errorDiffuse' v num err = take num $ errorDiffuses v errThen I'd think about generating the list of
errorDiffuses differently.Since we're trying to generate a list, that makes me think of
unfolds,which you can find in Data.List:
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]The unfold takes a function that, given a seed, produces the next
value in the outputted list, along with a new seed. The function
starts with an intitial seed, and keeps using those seeds, adding to the
list until the function returns
Nothing.The function we're looking for is the following:
nextErrorDiffuse :: Double -> Double -> Maybe (Int, Double)
nextErrorDiffuse v err = Just (tv, err + v - fromIntegral tv)
where
tv = truncate (v + err)Our list is infinite, so we always return a
Just value. The value that is output at each stage is tv, and the next "seed" is given by err + v - fromIntegral tv.Putting things together we have:
errorDiffuse'' :: Double -> Int -> Double -> [Int]
errorDiffuse'' v num err = take num $ unfoldr (nextErrorDiffuse v) errCode Snippets
errorDiffuses :: Double -> Double -> [Int]
errorDiffuses v err = tv : errorDiffuses v (err + v - fromIntegral tv)
where
tv = truncate (v + err)errorDiffuse' :: Double -> Int -> Double -> [Int]
errorDiffuse' v num err = take num $ errorDiffuses v errunfoldr :: (b -> Maybe (a, b)) -> b -> [a]nextErrorDiffuse :: Double -> Double -> Maybe (Int, Double)
nextErrorDiffuse v err = Just (tv, err + v - fromIntegral tv)
where
tv = truncate (v + err)errorDiffuse'' :: Double -> Int -> Double -> [Int]
errorDiffuse'' v num err = take num $ unfoldr (nextErrorDiffuse v) errContext
StackExchange Code Review Q#5757, answer score: 3
Revisions (0)
No revisions yet.