I'm implementing the following function for signed integer numbers: given endpoints of a closed interval
hi, and inputs
dx, I'd like to compute the "reflected sum":
x + dx is still in
[lo..hi] then that's it; otherwise the underhanging or overhanging portion is "folded back" onto the result (shown as
y below). Basically,
x is "bouncing around" in the interval.
overhang /--\ dx --------------> --------[-------|-------|---]---|------ lo x y hi x + dx <---
My current implementation is the following:
bounce :: (KnownNat n, KnownNat k, (k + 1) <= n) => (Signed n, Signed n) -> Signed n -> Signed k -> (Signed n, Bool) bounce (lo, hi) x dx | under > 0 = (lo + under, True) | over > 0 = (hi - over, True) | otherwise = (resize new, False) where new = add x dx under = resize $ resize lo - new over = resize $ new - resize hi
Things I don't like about this implementation:
- There is a lot of noise about bit widths (all the
- Overall, it is not immediately obvious by just looking at the code what it does. It feels like it's doing a lot of seemingly ad-hoc arithmetic operations that "just happen" to work.
I am looking for improvements that come from the structure of the problem, not "oh you should rename
theNumberThatIsBouncingAround because one-letter variable names bad".