Кабінет психопатологічної евтаназіології (
euthanasepam) wrote2021-07-12 10:52 am
![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Entry tags:
Пролетарська рекурсія за ваш рахунок
На популярному сайті 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
no subject
no subject
От ти сам і відповів на своє питання :) Проблема в алгоритмові, а не в підході (ФП).
no subject
Але є ще одна проблема — в доречності використання рекурсії у таких випадках. Процесор не знає ні про жодні рекурсії та не вміє їх рахувати. Він тупий і не знає вищої математики, абстракцій, алгоритмів тощо. ФП, ООП і таке інше — лише «синтаксичний цукор» для зручності людей. А на рівні процесора сам знаєш що: нулі та одиниці та прості операції.
Отже, маємо такий алгоритм. Він починає істотно і помітно неозброєним оком тупити десь із 35-го числа. Після 45-го це вже забавки для фанатичних слоупокерів. Скільки воно буде рахувати після 50-го, я не знаю, а скільки буде для 50-го на моєму комп’ютері — напишу пізніше, я саме запустив. :)
P. S.
Порахувало:
P. S.
Порахувало для 51-го:
P. S.
І для 52-го:
Думаю, зрозуміло, що далі буде лише гірше. :)
no subject
На невеликих наборах даних рекурсія дозволяє зробити програму яснішою. У цьому її сенс. І кожен притомний спеціаліст знає про те, що алгоритми на ній просідають по перфомансу. Це для заліза загального призначення, звісно. Можливо, якесь спеціалізоване вміє оптимізувати рекурсію. Х.З.
no subject
Гаразд, порівняймо з дуже швидким і простим ітеративним рахуванням числа Фібоначчі на Пітоні:
Просто, швидко і рахує правильно. Примітивно? Без модних штучок-дрючок? То й нехай. :)
P. S.
Там у них є купа інших варіянтів, але я хотів якомога точнішої відповідності до того ітеративного, що вже маю на Паскалі.
no subject
no subject
P. S.
Досі рахує.
Коли закінчить рахувати, якщо я того дочекаю, то напишу. :)
P. S.
Нарешті порахувало для 64:
no subject
Ну ти й терплячий
no subject
Результат красномовний.
Як хтось розумний казав — чи то Кнут, чи то Вірт, — що простий і «тупий» алгоритм зазвичай кращий за кручений та вишуканий.
no subject
Але не цього разу :). Бо найпростіший алгоритм якраз рекурсивний.
no subject
До речі, не факт, що Сішечка стільки рекурсії витримає.
no subject
Можна спробувати переписати саме цей алгоритм на якусь функціональну мову і побачити, що буде.
no subject
У мене з функціональщини тільки Emacs Lisp 😁. Але навряд чи він осилить таке число без бубна. Точніше, порахує він швидше, тільки результат буде дивним. Я так думаю 😁.
no subject
Corman Lisp, github.com/sharplispers/cormanlisp
LispWorks, www.lispworks.com
Щодо алгоритмів, то є там само, де й паскалівський:
http://rosettacode.org/wiki/Fibonacci_sequence#Common_Lisp
http://rosettacode.org/wiki/Fibonacci_sequence#Emacs_Lisp
Я ще не пробував, тож не скажу, як воно.
no subject
Безкоштовних ліспів під що хочеш вистачає. Я на Андроїді, наприклад, бавлюся. Але ємаксовський найбільш практичний для моїх потреб.
no subject
Щодо числа, то, по-ідеї, int в ємакс, обмежено unsigned long long. Для С повинні бути якісь ліби для роботи з більшими числами, але я з цим не стикався. Натомість, python автоматично розширяє пам'ять, щоб вмістити число.
no subject
Цікаво, до речі, як воно влаштовано і який має вигляд «під капотом».
no subject
C там під капотом, математичні пакети саме на ньому і написані :) Але Пітон та швидкість, то речі погано сумісні. Я коли робив обробку текстів, то Пітон просідав раза в три ємаксу (правда скомпільованому). А найкращий результат був у grep/sed/awk.
no subject
no subject
https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic
no subject
Для багатьох програмувальних мов довга арифметика є лише у сторонніх бібліотеках і відтак відсутня в інсталяції:
http://rosettacode.org/wiki/Arbitrary-precision_integers_(included)
GMP — це 4 МБ розпакованих файлів. Звісно, програмного тексту в кілька разів менше, але є що читати.
DelphiBigNumbers (BigInteger, BigDecimal and BigRational for Delphi) теж доволі великий.
А от Big Decimal Math — це фактично один файл bigdecimalmath.pas обсягом 82 КБ.
no subject
Пітон автоматично вижирає пам'ять, якщо у цьому є потреба. Мені цей підхід якось не дуже подобається. Бо так можна вижрати багацько пам'яті, варто лише помилитися в алгоритмі.
Я допускаю, що десь можуть знадобитися такі цифри, але 18000+ знаків з коробки це більш ніж досить. А треба більше, просто збільши значення змінної.
no subject
ru.wikipedia.org/wiki/Число_Грэма
no subject
no subject
Не думаю, що саме через це.
Такі великі числа мало кому цікаві. Мені, за 25 років практики, тільки пару раз long не вистачило. І таких — переважна більшість. А от науковцям воно потрібно.
no subject
Отож.
Бо дивимось ув інші мови і бачимо там таке:
https://classic.startpage.com/do/asearch?q=pascal+largest+integer
Якщо нема спеціяльних засобів, то скрізь буде обмеження машини. А цього для наукових обчислень дуже мало.
> Такі великі числа мало кому цікаві.
Мені цікаві: це найперше, на що я дивлюся, коли дивлюся на якийсь інтерпретатор чи компілятор.
no subject
http://www.freepascal.ru/article/freepascal/20181215220000
no subject
А що, в літературі по Паскалю не кажуть про ці проблеми?
no subject
Нещодавно я в одному журналі з подивом читав, що працевлаштовані у великих ΙΤ-компаніях люди бува не знають про IEEE 754.
Часто в йойтішних книжках пишуть ото як ти кажеш: вам не треба тої довгої арифметики, то ми про неї не пишемо. Або й нічого про неї не згадують.
no subject
В книжках по С та Java пишуть, що буде якщо помилишся з діапазонами. Ну і в Java є BigNum. А що є в С ХЗ, непотрібно було.
no subject
Спробував піпіськомірку на ванільному ємаксі:
Вивело 18809 знаків. В принципі, ємакс навчився і bignum, такий як у python, але, наразі, щось там потрібно додатково включати.
no subject
Втім:
Вивело 21003 знаків.
Твій варіант на python:
Результати ті ж.
no subject
Ще тупіший алгоритм:
no subject