Странное дело: первое возведение тройки в тысячную степень занимает 1 секунду, а каждое следующее возведение увеличивает это время примерно на секунду, пока к пятой итерации не достигает 4,5 секунд. На этой скорости происходит стабилизация: сотое повторение занимает те же 4,5 секунды.
Подозреваю, проблема в том, что списки длиной более 100 элементов работают медленнее, чем массивы. Впрочем, так как стабилизация таки происходит, проблема некритична. Учитывая, что возведение тройки в десятитысячную степень занимает уже пять минут, следует предположить, что я отловил грань, за которой длина списка становится критичной.
; Добить нулями num до длины len
(define (big-leading-zero len num)
(append (dup 0 (- len (length num))) num))
; Выровнять большие числа по длине
(define (big-align)
(let (len (apply max (map length (args))))
(map (curry big-leading-zero len) (args))))
; 123 -> '(1 2 3)
(define (int-to-big num)
(map int (explode (string num))))
; '(1 2 3) -> 123
(define (big-to-int big)
(int (join (apply string big))))
; '(1 2 3) -> "123"
(define (big-to-string big)
(join (map string big)))
; "123" -> '(1 2 3)
(define (string-to-big big)
(map int (explode big)))
; "Упаковать" число так, чтобы в каждом разряде сидело не больше 9
(define (big-pack num)
(let (num (reverse num) o-num '() dig nil tra 0 lead nil)
(while (or (> tra) (not (null? num)))
(set 'dig (+ (or (pop num) 0) tra))
(push (% dig 10) o-num)
(set 'tra (/ dig 10)))
(if (set 'lead (find 0 o-num <)) (lead o-num) '(0))))
; Сложить большие числа
(define (big-add)
(big-pack (map (fn (x) (apply + x)) (transpose (apply big-align (args))))))
; Умножить два больших числа
(define (big-mul-2 num1 num2)
(apply big-add
(map (fn (y) (append y (dup 0 $idx)))
(reverse (map (fn (x) (map (curry mul x) num2)) num1)))))
; Перемножить большие числа
(define (big-mul)
(apply big-mul-2 (args) 2))
; Возвести большое число в большую степень
(define (big-pow num pw)
(let (pw2 (list num))
(dotimes (x (- (length (bits pw)) 1))
(push (apply big-mul-2 (dup (if pw2 (first pw2) num) 2)) pw2))
(apply big-mul
(map (fn (x y) (if (= x "1") y '(1))) (explode (bits pw)) pw2))))
А вот довесочек, проверяющий скорость:
; Проверка скорости
(dotimes (x 1000)
(println x ": " (time (big-pow '(3) 1000))))
Комментариев нет:
Отправить комментарий