Isoraqathedh

carry-or-borrow

Jul 5th, 2016
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 1.87 KB | None | 0 0
  1. (defun carry-or-borrow (original limits)
  2.   "Clamp the ORIGINAL list of numbers so each number appears between the LIMITS.
  3.  
  4. Furthermore, the list of numbers are considered to be a number
  5. with a variable base,
  6. which is one more than the difference between the first and second elements
  7. in each sublist of LIMITS.
  8. If clamping occurs, the next value is carried to or borrowed from as needed,
  9. e.g. (3 5 1) ((1 nil) (1 2) (1 3)) yields (5 1 1).
  10.  
  11. However, some lists are not carriable.
  12. In this case, the function signals an error."
  13.   ;; We need to have alternate versions of subtract, modulo and integer division
  14.   ;; that treat nil as infinity.
  15.   (flet ((-* (subtractand subtractor)
  16.            (when subtractand
  17.              (- subtractand subtractor -1))) ; add 1 back for inclusiveness
  18.          (mod* (number divisor)
  19.            (if divisor
  20.                (mod number divisor)
  21.                number))
  22.          (/* (dividend divisor)
  23.            (if divisor
  24.                (floor (/ dividend divisor))
  25.                0)))
  26.     (let* ((mins (mapcar #'first limits))
  27.            (maxs (mapcar #'second limits))
  28.            (ranges (mapcar #'-* maxs mins))
  29.           (working-copy (copy-list original)))
  30.       (dotimes (i (length original))
  31.         (setf working-copy
  32.               (let* ((norm-origs (mapcar #'- working-copy mins))
  33.                      (remainders (mapcar #'mod* norm-origs ranges))
  34.                      (carries    (append
  35.                                   (cdr (mapcar #'/* norm-origs ranges))
  36.                                   (list 0))))
  37.                 (mapcar #'+ remainders carries mins))))
  38.       (if (every (lambda (tmin test tmax)
  39.                    (if tmax
  40.                        (<= tmin test tmax)
  41.                        (<= tmin test)))
  42.                  mins working-copy maxs)
  43.           working-copy
  44.           (error "List cannot be carried.")))))
Advertisement
Add Comment
Please, Sign In to add comment