Skip to content

Instantly share code, notes, and snippets.

@alandipert
Last active July 26, 2023 15:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alandipert/9b7befbdb442bac2167595a8ffc24bf5 to your computer and use it in GitHub Desktop.
Save alandipert/9b7befbdb442bac2167595a8ffc24bf5 to your computer and use it in GitHub Desktop.
(defun find-terms (num-terms max-size
&optional (desired-sum 0)
&aux (iterations 0))
"Returns a list of terms in the range -max-size ... +max-size,
inclusive, that sum to desired-sum.
Has strange properties. Likelier to blow the stack as max-size
increases. Seems to spend most time backtracking on the last few
terms.
This feels like a glorified brute-force approach, and I think there
has to be a cleaner, closed-form way to generate similar
sequences. What would young Gauss do?"
(labels ((rand-term ()
(- (+ desired-sum max-size)
(random (1+ (* 2 max-size)))))
(find* (terms len running-sum)
(incf iterations)
(cond ((and (= len num-terms)
(= desired-sum running-sum))
terms)
((> (abs running-sum)
(* max-size (- num-terms len)))
(find* (rest terms)
(1- len)
(- running-sum (first terms))))
(t (let ((next-term (rand-term)))
(find* (cons next-term terms)
(1+ len)
(+ running-sum next-term)))))))
(values (find* '() 0 0) iterations)))
;;CL-USER> (find-terms 10 5)
;;(0 5 5 0 -2 -5 -4 1 4 -4)
;;29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment