I'm implementing the following function for signed integer numbers: given endpoints of a closed interval lo and hi, and inputs x (in [lo..hi]) and dx, I'd like to compute the "reflected sum": if 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
<---


Because this is for a hardware circuit, I am doing this using Clash's sized Signed integer type and width-extending addition, otherwise it is normal Haskell code.

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
under = resize $resize lo - new over = resize$ new - resize hi


• There is a lot of noise about bit widths (all the resize calls)
• 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 x to theNumberThatIsBouncingAround because one-letter variable names bad".

bounce (lo, hi) x dx = let
(bounces, remainder) = divMod (add dx $x-lo)$ hi-lo

• Unfortunately, divMod by a non-power-of-two is not really implementable as a combinational circuit. Commented Feb 1, 2020 at 0:45
• You are already implementing divMod by means of a lookup table for div in {-1,0,1}. That's why your code looks improvable to you. You do in fact need to implement divMod in some way, for that is your problem statement. Commented Feb 1, 2020 at 0:53