Я пытаюсь решить задачу 14 в Project Euler (найти самую длинную последовательность Коллатца от 1 до 1000000).
Мой код состоит из рекурсивной запоминаемой функции для вычисления длины последовательностей Коллатца, за которой следует цикл для нахождения максимума. Пожалуйста, смотрите код ниже:
(defparameter *collatz* (make-hash-table))
(setf (gethash 1 *collatz*) 0)
(defun n-collatz (n)
(if (gethash n *collatz*)
(gethash n *collatz*)
(setf (gethash n *collatz*)
(if (evenp n)
(1+ (n-collatz (/ n 2)))
(1+ (n-collatz (1+ (* n 3))))))))
(loop for i from 1 to 1000000 maximize (n-collatz i))
Это отлично работало в Clozure, но вызывало переполнение кучи в Lispworks. Поскольку он вышел неизящно, я не мог узнать, что произошло. На самом деле, я не понимаю, почему это занимает так много места в куче — самая большая последовательность рекурсии — это 300 с чем-то вызовов. Я пропустил некоторую неэффективность в коде?
Любой вклад приветствуется. Также приветствуются дальнейшие комментарии к коду.
PS: я использую Lispworks Personal Edition, что накладывает ограничение на размер кучи.
ОБНОВЛЕНИЕ Я попытался скомпилировать, как предложил Райнер Джосвиг, но это не помогло.
Что касается комментариев coredump и sds, or
действительно лучше, чем if
в данном случае, но я не могу заменить хеш-таблицу вектором, потому что последовательность коллатца увеличивается примерно в 50% случаев. После запуска кода в хеш-таблице осталось около 2,5 миллионов записей.
Наконец, как ни странно, мне удалось воспроизвести ошибку при тестировании синтаксиса длинного цикла (миллион итераций), который просто жонглировал некоторыми переменными и вообще ничего не собирал. Я потерял код, к сожалению, LispWorks просто вышел из строя, увы. Я думаю, что во внутренностях LispWorks есть какая-то утечка или другой сбой управления памятью.
(if X X Y)
также пишется как(or X Y)
- person coredump   schedule 08.10.2015