project-euler/p99.lisp

37 lines
1.3 KiB
Common Lisp

;;;; Approach: The exponents are reasonably similar, so when
;;;; necessary, see if the smaller base with larger exponent's extra
;;;; terms would exceed the ratio terms. Avoid large calculations by
;;;; normalizing to a single extra term.
(defun smallerp (sb se bb be)
"Given (< SB BB) and (> SE BE) ('S' meaning smaller base, 'B' meaning bigger), returns non-NIL if (< (EXPT SB SE) (EXPT BB BE))"
(let ((ratio (/ sb bb)))
(< sb
(expt ratio (/ be (- be se))))))
(defun exp< (n1 n2)
"Returns non-NIL if (< (APPLY #'EXPT N1) (APPLY #'EXPT N2)), assuming exponents are very large and erasonably similar"
(destructuring-bind (b1 e1) n1
(destructuring-bind (b2 e2) n2
(cond
;; Trivial cases
((and (< b1 b2) (< e1 e2)) t)
((and (>= b1 b2) (>= e1 e2)) nil)
;; Cases requiring actual calculation
((< b1 b2) (smallerp b1 e1 b2 e2))
(t (not (smallerp b2 e2 b1 e1)))))))
(defun largest-exponential (&optional lines)
(loop with biggest = nil
with biggest-line = nil
for line in (uiop:read-file-lines "0099_base_exp.txt")
for exponential = (mapcar #'parse-integer (uiop:split-string line :separator '(#\,)))
for i upfrom 0
while (or (not lines)
(< i lines))
do (when (or (not biggest)
(exp< biggest exponential))
(setf biggest-line (1+ i))
(setf biggest exponential))
finally (return biggest-line)))