Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- (defun carry-or-borrow (original limits)
- "Clamp the ORIGINAL list of numbers so each number appears between the LIMITS.
- Furthermore, the list of numbers are considered to be a number
- with a variable base,
- which is one more than the difference between the first and second elements
- in each sublist of LIMITS.
- If clamping occurs, the next value is carried to or borrowed from as needed,
- e.g. (3 5 1) ((1 nil) (1 2) (1 3)) yields (5 1 1).
- However, some lists are not carriable.
- In this case, the function signals an error."
- ;; We need to have alternate versions of subtract, modulo and integer division
- ;; that treat nil as infinity.
- (flet ((-* (subtractand subtractor)
- (when subtractand
- (- subtractand subtractor -1))) ; add 1 back for inclusiveness
- (mod* (number divisor)
- (if divisor
- (mod number divisor)
- number))
- (/* (dividend divisor)
- (if divisor
- (floor (/ dividend divisor))
- 0)))
- (let* ((mins (mapcar #'first limits))
- (maxs (mapcar #'second limits))
- (ranges (mapcar #'-* maxs mins))
- (working-copy (copy-list original)))
- (dotimes (i (length original))
- (setf working-copy
- (let* ((norm-origs (mapcar #'- working-copy mins))
- (remainders (mapcar #'mod* norm-origs ranges))
- (carries (append
- (cdr (mapcar #'/* norm-origs ranges))
- (list 0))))
- (mapcar #'+ remainders carries mins))))
- (if (every (lambda (tmin test tmax)
- (if tmax
- (<= tmin test tmax)
- (<= tmin test)))
- mins working-copy maxs)
- working-copy
- (error "List cannot be carried.")))))
Advertisement
Add Comment
Please, Sign In to add comment