euthanasepam: Вата бородата (vata_borodata)
Кабінет психопатологічної евтаназіології ([personal profile] euthanasepam) wrote2021-07-12 10:52 am

Пролетарська рекурсія за ваш рахунок

 

На популярному сайті Rosetta Code з прикладами програм на розмаїтих програмувальних мовах є зразки вирішення всіляких типових математичних, алгоритмічних і хтозна ще яких проблем.

Погляньмо, наприклад, на рекурсивний пошук якогось числа у послідовності Фібоначчі, запрограмований мовою Паскаль:

http://rosettacode.org/wiki/Fibonacci_sequence#Pascal

function fib(n: integer): integer;
  begin
    if (n = 0) or (n = 1)
      then
        fib := n
      else
        fib := fib(n-1) + fib(n-2)
  end;


Гарно? Авжеж. Вельми гарно. Тішить серце і милує око.

Але коли ви цей алгоритм відкомпілюєте і запустите на виконання для числа, скажімо, 64, то встигнете посивіти поснідати й випити горнятко кави, а може й не одне. Дуже, дуже, дуже довго… Про якісь справді великі числа в цьому випадку говорити зайве.

Для порівняння: ітеративний алгоритм працює блискавично навіть для досить великих чисел, що вмістяться у комп’ютерну пам’ять.


Отож, мораль: коли вам якесь занюхане чмо велемудре цабе каже, що воно вміє рахувати всілякі математичні фокуси рекурсивно і функціонально, ви теє цабе негайно пиздіть по мармизі та женіть із хати геть. Бо якщо воно почне писати для вас програми, то буде вам клопіт, і горе, і видатки.



P. S.

Нарешті порахувало для 64:

10610209857723

real    5257m47,799s
user    0m0,000s
sys     0m0,015s






 
balu: (Default)

[personal profile] balu 2021-07-13 06:27 am (UTC)(link)

C там під капотом, математичні пакети саме на ньому і написані :) Але Пітон та швидкість, то речі погано сумісні. Я коли робив обробку текстів, то Пітон просідав раза в три ємаксу (правда скомпільованому). А найкращий результат був у grep/sed/awk.

balu: (Default)

[personal profile] balu 2021-07-14 05:37 am (UTC)(link)

https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic

balu: (Default)

[personal profile] balu 2021-07-14 01:14 pm (UTC)(link)

Пітон автоматично вижирає пам'ять, якщо у цьому є потреба. Мені цей підхід якось не дуже подобається. Бо так можна вижрати багацько пам'яті, варто лише помилитися в алгоритмі.

Since large bignums consume a lot of memory, Emacs limits the size of the largest bignum a Lisp program is allowed to create.

Я допускаю, що десь можуть знадобитися такі цифри, але 18000+ знаків з коробки це більш ніж досить. А треба більше, просто збільши значення змінної.

balu: (Default)

[personal profile] balu 2021-07-13 06:46 am (UTC)(link)

Не думаю, що саме через це.

  • По-перше, цій фічі менше 10-ти років.
  • По-друге, у python є кілька дуже вдалих моментів: це цукор для списків та словників, foreach, слайси, імпорт та мінімум бюрократії. Це дозволяє легко його використовувати непрограмістам.
  • По-третє, він був частиною дистрибутивів з маком включно, а науковці часто сидять саме на якихось ніксах. От і отримали на халяву простий інструмент.


Такі великі числа мало кому цікаві. Мені, за 25 років практики, тільки пару раз long не вистачило. І таких — переважна більшість. А от науковцям воно потрібно.

balu: (Default)

[personal profile] balu 2021-07-14 05:50 am (UTC)(link)

А що, в літературі по Паскалю не кажуть про ці проблеми?

balu: (Gene Kranz. Запарка.)

[personal profile] balu 2021-07-14 01:04 pm (UTC)(link)

В книжках по С та Java пишуть, що буде якщо помилишся з діапазонами. Ну і в Java є BigNum. А що є в С ХЗ, непотрібно було.

balu: (Default)

[personal profile] balu 2021-07-13 07:26 am (UTC)(link)

Спробував піпіськомірку на ванільному ємаксі:

(defun fibonacci (n)
  (let ( (vec) (i) (j) (k) )
    (if (< n 2) n
      (progn
          (setq vec (make-vector (+ n 1) 0) i 0 j 1 k 2)
          (setf (aref vec 1) 1)
          (while (<= k n)
            (setf (aref vec k) (+ (elt vec i) (elt vec j) ))
            (setq i (+ 1 i) j (+ 1 j) k (+ 1 k) ))
          (elt vec n) ))))

ELISP> (benchmark 1 (fibonacci 94000))
"Elapsed time: 0.000002s"
ELISP> (benchmark 1 (fibonacci 95000))
*** Eval error ***  Arithmetic overflow error

Вивело 18809 знаків. В принципі, ємакс навчився і bignum, такий як у python, але, наразі, щось там потрібно додатково включати.

balu: (Default)

[personal profile] balu 2021-07-13 07:30 am (UTC)(link)

Втім:

ELISP> integer-width
65536 (#o200000, #x10000)
ELISP> (setq integer-width 131072)
131072 (#o400000, #x20000)
ELISP> (benchmark 1 (fibonacci 100500))
"Elapsed time: 0.000003s"

Вивело 21003 знаків.


Твій варіант на python:

real    0m0,112s
user    0m0,088s
sys 0m0,004s

Результати ті ж.

Edited 2021-07-13 07:40 (UTC)
balu: (Gene Kranz. Запарка.)

[personal profile] balu 2021-07-13 08:09 am (UTC)(link)

Ще тупіший алгоритм:

(require 'cl)

(defun fib-loop (num)
  (cl-do ((n 0 (1+ n))
       (cur 0 next)
       (next 1 (+ cur next)))
      ((= num n) cur)))

ELISP> (benchmark 1 (fib-loop 100500))
"Elapsed time: 0.000002s"