Wikiversity
betawikiversity
https://beta.wikiversity.org/wiki/Main_Page
MediaWiki 1.47.0-wmf.8
first-letter
Media
Special
Talk
User
User talk
Wikiversity
Wikiversity talk
File
File talk
MediaWiki
MediaWiki talk
Template
Template talk
Help
Help talk
Category
Category talk
TimedText
TimedText talk
Module
Module talk
Translations
Translations talk
Event
Event talk
Біологія людини/Біологічна система. Будова людської клітини
0
55803
385112
385110
2026-06-28T15:07:45Z
Віталій Васильович Івчук
55643
385112
wikitext
text/x-wiki
== Клітина як відкрита біологічна система ==
Клітина є елементарною структурно-функціональною одиницею живого, яка характеризується всіма ознаками організму: ростом, розвитком, подразливістю, метаболізмом та здатністю до самовідтворення. У контексті системного підходу клітина розглядається як ''[[Відкрита біологічна система|відкрита біологічна система]]''. Це визначення означає, що для підтримання власної організації ([[Гомеостаз|гомеостазу]]) вона перебуває у безперервному діалозі з позаклітинним середовищем.
Відкритість системи реалізується через постійний трансмембранний транспорт речовин. Клітина споживає з навколишнього середовища субстрати ([[Глюкоза|глюкозу]], [[Амінокислоти|амінокислоти]], [[Іони|іони]], [[Кисень|кисень]]), які використовує як джерела енергії та будівельного матеріалу. У процесі [[Катаболічні реакції|катаболічних реакцій]] відбувається розщеплення складних молекул із вивільненням енергії, необхідної для синтезу [[АТФ]]. Продукти метаболізму ([[Вуглекислий газ|вуглекислий газ]], [[Сечовина|сечовина]], надлишок [[Вода|води]]) виводяться назовні. Таким чином, потік речовин та енергії через мембрану є необхідною умовою існування клітини як цілісної системи. Припинення цього обміну означає її смерть.
== Структурно-функціональна організація клітини ==
Досконалість клітини як системи забезпечується суворою відповідністю між будовою її компонентів та виконуваними функціями. Основними структурними елементами людської клітини є [[Плазматична мембрана|плазматична мембрана]], [[Цитоплазма|цитоплазма]] з [[Органели|органелами]] та [[Ядро|ядро]].
* ''[[Плазматична мембрана]] (плазмалема)''. Це бімолекулярний шар [[Фосфоліпіди|фосфоліпідів]] з інтегрованими в нього [[Білки|білками]] ([[Рецептори|рецепторами]], [[Ферменти|ферментами]], [[Іонні канали|каналами]]). Основна функція мембрани — бар’єрно-транспортна. Вона виступає вибірковим фільтром, забезпечуючи [[Вибіркова проникність|вибіркову проникність]] (напівпроникність). Завдяки наявності [[Глікокалікс|глікокаліксу]] (зовнішнього [[Вуглеводи|вуглеводного]] шару) мембрана бере участь у [[Міжклітинна взаємодія|міжклітинній взаємодії]] ([[Адгезія|адгезії]]) та розпізнаванні [[Сигнальні молекули|сигнальних молекул]], що є невід'ємною частиною регуляції системи.
* ''[[Цитоплазма]] та [[Органели|органели]]''. Цитоплазма являє собою внутрішнє [[Колоїди|колоїдне]] середовище ([[Цитозоль|цитозоль]]) та [[Цитоскелет|цитоскелет]], у якому розташовані органели.
** ''[[Мітохондрія|Мітохондрії]]'' — двомембранні органели, власна [[ДНК]] яких кодує [[Ферменти дихального ланцюга|ферменти дихального ланцюга]]. Їхня будова (наявність [[Кристи|крист]] для збільшення площі внутрішньої мембрани) максимально пристосована для синтезу [[АТФ]] у процесі [[Окисне фосфорилювання|окисного фосфорилювання]]. Вони є «енергетичними станціями» системи.
** ''[[Ендоплазматичний ретикулум]] (ЕР)'' — система мембранних цистерн. [[Гранулярний ендоплазматичний ретикулум|Гранулярний ЕР]] (з [[Рибосома|рибосомами]]) забезпечує синтез [[Білок|білків]] для експорту, тоді як [[Агранулярний ендоплазматичний ретикулум|агранулярний ЕР]] відповідає за синтез [[Ліпіди|ліпідів]] та [[Детоксикація|детоксикацію]]. [[Рибосоми]], що знаходяться на [[Ендоплазматичний ретикулум|ЕР]] або вільно, є немембранними структурами, які забезпечують трансляцію генетичного коду.
** ''[[Апарат Гольджі]]'' — виконує функцію сортування, модифікації та пакування синтезованих речовин у [[Везикули|везикули]] (секреторні бульбашки), забезпечуючи спрямований транспорт продуктів як всередину клітини, так і назовні.
** ''[[Лізосома|Лізосоми]]'' — [[Везикули|везикули]] з [[Гідролітичні ферменти|гідролітичними ферментами]], що забезпечують [[Внутрішньоклітинне травлення|внутрішньоклітинне травлення]] ([[Автофагія|автофагію]]) — оновлення зношених [[Органели|органел]], що підтримує динамічну рівновагу системи.
** ''[[Цитоскелет]] ([[Мікротрубочки|мікротрубочки]] та [[Мікрофіламенти|мікрофіламенти]])'' формує опорно-руховий апарат, що дозволяє клітині змінювати форму та забезпечує внутрішнє переміщення [[Органели|органел]].
* ''[[Ядро]]''. [[Ядро]] є інформаційним та регуляторним центром системи. Обмежене подвійною ядерною мембраною з [[Ядерні пори|ядерними порами]], воно містить [[Хроматин|хроматин]] (комплекс [[ДНК]] з [[Білки гістони|білками гістонами]]) та [[Ядерце|ядерце]]. Будова [[Ядро|ядра]] забезпечує збереження, [[реплікація|реплікацію]] та [[транскрипція|транскрипцію]] [[Спадкова інформація|спадкової інформації]]. Саме [[Ядро|ядро]] керує синтезом специфічних [[Білки|білків]] через утворення [[Матрична РНК|матричних РНК]], визначаючи, які [[Метаболічні шляхи|метаболічні шляхи]] будуть активовані у відповідь на зовнішні чи внутрішні сигнали.
== Взаємозв’язок компонентів та цілісність системи ==
Клітина функціонує як єдина система завдяки суворій узгодженості роботи всіх її відділів. Цей взаємозв'язок забезпечується через [[Сигнальні молекули|сигнальні молекули]], потоки [[Іони кальцію|іонів кальцію]] та [[Каскади ферментативних реакцій|каскади ферментативних реакцій]].
Розглянемо [[Цикл забезпечення енергією|цикл забезпечення енергією]]: надходження [[Глюкоза|глюкози]] через [[Рецептори мембрани клітини|рецептори мембрани]] активує [[Ферменти цитоплазми|ферменти цитоплазми]] ([[Гліколіз|гліколіз]]). Продукти [[Гліколіз|гліколізу]] транспортуються в [[Мітохондрія|мітохондрії]], де утворюється [[АТФ]]. Енергія [[АТФ]] використовується [[Апарат Гольджі|апаратом Гольджі]] для [[Активний транспорт речовин|активного транспорту речовин]], а також [[Цитоскелет|цитоскелетом]] для руху. Якщо в клітині накопичуються пошкоджені [[Білок|білки]], [[Ядро|ядро]] активує [[Гени клітинного стресу|гени "клітинного стресу"]], що призводить до посилення роботи [[Лізосома|лізосом]] або запуску механізму [[Апоптоз|апоптозу]] (програмованої загибелі) для порятунку організму. Таким чином, будь-яка зміна в одному компоненті викликає адаптивну зміну в інших, що підтримує системну рівновагу ([[Гомеостаз|гомеостаз]]).
[[Метаболізм]] (сукупність [[Катаболізм|катаболізму]] та [[Анаболізм|анаболізму]]) є інтегральною властивістю системи, яка виникає завдяки сукупній взаємодії [[Органели|органел]], а не є сумою їхніх окремих функцій.
== Клітина як основа організменної ієрархії ==
Клітина є першим (елементарним) [[Рівні структурної організації живого|рівнем структурної організації живого]] в організмі людини. Вона є базовим модулем, на основі якого будується весь організм.
Одноманітні за будовою та походженням клітини, об'єднані [[Міжклітинні контакти|міжклітинними контактами]] та [[Міжклітинна речовина|міжклітинною речовиною]], формують ''[[Тканини|тканини]]'' (епітеліальну, сполучну, м'язову, нервову). Різні типи тканин, скоординовано взаємодіючи, утворюють ''[[Органи|органи]]'', кожен з яких виконує специфічну функцію (серце, печінка, нирка). Органи об'єднуються в ''[[Системи органів|системи органів]]'' (травну, дихальну, кровоносну), які забезпечують життєдіяльність цілісного багатоклітинного організму.
Отже, зміни або порушення функцій на рівні окремої клітини (наприклад, через [[Генетична мутація|генетичну мутацію]] чи вплив [[Токсин|токсинів]]) неминуче відбиваються на функціональному стані [[Тканина|тканини]], [[Орган|органу]] і, зрештою, всього [[Організм|організму]]. Це підкреслює [[Фундаментальний принцип біології|фундаментальний принцип біології]]: [[Клітина|клітина]] є не просто частиною цілого, а базовою одиницею, яка визначає всі [[Рівні організації людського тіла|рівні організації людського тіла]]. Таким чином, вивчення будови та функцій [[Клітина|клітини]] є необхідною передумовою для розуміння [[Фізіологія|фізіології]], [[Патологія|патології]] та [[Медицина|медицини]] загалом.
[[Category:UK]]
[[Category:Біологія людини]]
[[Category:Основний простір]]
4d8nb2vfq2he70gp9alu5dryqw9hrg3
385113
385112
2026-06-28T15:09:38Z
Віталій Васильович Івчук
55643
385113
wikitext
text/x-wiki
== Клітина як відкрита біологічна система ==
Клітина є елементарною структурно-функціональною одиницею живого, яка характеризується всіма ознаками організму: ростом, розвитком, подразливістю, метаболізмом та здатністю до самовідтворення. У контексті системного підходу клітина розглядається як ''[[Відкрита біологічна система|відкрита біологічна система]]''. Це визначення означає, що для підтримання власної організації ([[Гомеостаз|гомеостазу]]) вона перебуває у безперервному діалозі з позаклітинним середовищем.
Відкритість системи реалізується через постійний [[Трансмембранний транспорт речовин|трансмембранний транспорт речовин]]. Клітина споживає з навколишнього середовища субстрати ([[Глюкоза|глюкозу]], [[Амінокислоти|амінокислоти]], [[Іони|іони]], [[Кисень|кисень]]), які використовує як джерела енергії та будівельного матеріалу. У процесі [[Катаболічні реакції|катаболічних реакцій]] відбувається розщеплення складних молекул із вивільненням енергії, необхідної для синтезу [[АТФ]]. Продукти метаболізму ([[Вуглекислий газ|вуглекислий газ]], [[Сечовина|сечовина]], надлишок [[Вода|води]]) виводяться назовні. Таким чином, потік речовин та енергії через мембрану є необхідною умовою існування клітини як цілісної системи. Припинення цього обміну означає її смерть.
== Структурно-функціональна організація клітини ==
Досконалість клітини як системи забезпечується суворою відповідністю між будовою її компонентів та виконуваними функціями. Основними структурними елементами людської клітини є [[Плазматична мембрана|плазматична мембрана]], [[Цитоплазма|цитоплазма]] з [[Органели|органелами]] та [[Ядро|ядро]].
* ''[[Плазматична мембрана]] (плазмалема)''. Це бімолекулярний шар [[Фосфоліпіди|фосфоліпідів]] з інтегрованими в нього [[Білки|білками]] ([[Рецептори|рецепторами]], [[Ферменти|ферментами]], [[Іонні канали|каналами]]). Основна функція мембрани — бар’єрно-транспортна. Вона виступає вибірковим фільтром, забезпечуючи [[Вибіркова проникність|вибіркову проникність]] (напівпроникність). Завдяки наявності [[Глікокалікс|глікокаліксу]] (зовнішнього [[Вуглеводи|вуглеводного]] шару) мембрана бере участь у [[Міжклітинна взаємодія|міжклітинній взаємодії]] ([[Адгезія|адгезії]]) та розпізнаванні [[Сигнальні молекули|сигнальних молекул]], що є невід'ємною частиною регуляції системи.
* ''[[Цитоплазма]] та [[Органели|органели]]''. Цитоплазма являє собою внутрішнє [[Колоїди|колоїдне]] середовище ([[Цитозоль|цитозоль]]) та [[Цитоскелет|цитоскелет]], у якому розташовані органели.
** ''[[Мітохондрія|Мітохондрії]]'' — двомембранні органели, власна [[ДНК]] яких кодує [[Ферменти дихального ланцюга|ферменти дихального ланцюга]]. Їхня будова (наявність [[Кристи|крист]] для збільшення площі внутрішньої мембрани) максимально пристосована для синтезу [[АТФ]] у процесі [[Окисне фосфорилювання|окисного фосфорилювання]]. Вони є «енергетичними станціями» системи.
** ''[[Ендоплазматичний ретикулум]] (ЕР)'' — система мембранних цистерн. [[Гранулярний ендоплазматичний ретикулум|Гранулярний ЕР]] (з [[Рибосома|рибосомами]]) забезпечує синтез [[Білок|білків]] для експорту, тоді як [[Агранулярний ендоплазматичний ретикулум|агранулярний ЕР]] відповідає за синтез [[Ліпіди|ліпідів]] та [[Детоксикація|детоксикацію]]. [[Рибосоми]], що знаходяться на [[Ендоплазматичний ретикулум|ЕР]] або вільно, є немембранними структурами, які забезпечують трансляцію генетичного коду.
** ''[[Апарат Гольджі]]'' — виконує функцію сортування, модифікації та пакування синтезованих речовин у [[Везикули|везикули]] (секреторні бульбашки), забезпечуючи спрямований транспорт продуктів як всередину клітини, так і назовні.
** ''[[Лізосома|Лізосоми]]'' — [[Везикули|везикули]] з [[Гідролітичні ферменти|гідролітичними ферментами]], що забезпечують [[Внутрішньоклітинне травлення|внутрішньоклітинне травлення]] ([[Автофагія|автофагію]]) — оновлення зношених [[Органели|органел]], що підтримує динамічну рівновагу системи.
** ''[[Цитоскелет]] ([[Мікротрубочки|мікротрубочки]] та [[Мікрофіламенти|мікрофіламенти]])'' формує опорно-руховий апарат, що дозволяє клітині змінювати форму та забезпечує внутрішнє переміщення [[Органели|органел]].
* ''[[Ядро]]''. [[Ядро]] є інформаційним та регуляторним центром системи. Обмежене подвійною ядерною мембраною з [[Ядерні пори|ядерними порами]], воно містить [[Хроматин|хроматин]] (комплекс [[ДНК]] з [[Білки гістони|білками гістонами]]) та [[Ядерце|ядерце]]. Будова [[Ядро|ядра]] забезпечує збереження, [[реплікація|реплікацію]] та [[транскрипція|транскрипцію]] [[Спадкова інформація|спадкової інформації]]. Саме [[Ядро|ядро]] керує синтезом специфічних [[Білки|білків]] через утворення [[Матрична РНК|матричних РНК]], визначаючи, які [[Метаболічні шляхи|метаболічні шляхи]] будуть активовані у відповідь на зовнішні чи внутрішні сигнали.
== Взаємозв’язок компонентів та цілісність системи ==
Клітина функціонує як єдина система завдяки суворій узгодженості роботи всіх її відділів. Цей взаємозв'язок забезпечується через [[Сигнальні молекули|сигнальні молекули]], потоки [[Іони кальцію|іонів кальцію]] та [[Каскади ферментативних реакцій|каскади ферментативних реакцій]].
Розглянемо [[Цикл забезпечення енергією|цикл забезпечення енергією]]: надходження [[Глюкоза|глюкози]] через [[Рецептори мембрани клітини|рецептори мембрани]] активує [[Ферменти цитоплазми|ферменти цитоплазми]] ([[Гліколіз|гліколіз]]). Продукти [[Гліколіз|гліколізу]] транспортуються в [[Мітохондрія|мітохондрії]], де утворюється [[АТФ]]. Енергія [[АТФ]] використовується [[Апарат Гольджі|апаратом Гольджі]] для [[Активний транспорт речовин|активного транспорту речовин]], а також [[Цитоскелет|цитоскелетом]] для руху. Якщо в клітині накопичуються пошкоджені [[Білок|білки]], [[Ядро|ядро]] активує [[Гени клітинного стресу|гени "клітинного стресу"]], що призводить до посилення роботи [[Лізосома|лізосом]] або запуску механізму [[Апоптоз|апоптозу]] (програмованої загибелі) для порятунку організму. Таким чином, будь-яка зміна в одному компоненті викликає адаптивну зміну в інших, що підтримує системну рівновагу ([[Гомеостаз|гомеостаз]]).
[[Метаболізм]] (сукупність [[Катаболізм|катаболізму]] та [[Анаболізм|анаболізму]]) є інтегральною властивістю системи, яка виникає завдяки сукупній взаємодії [[Органели|органел]], а не є сумою їхніх окремих функцій.
== Клітина як основа організменної ієрархії ==
Клітина є першим (елементарним) [[Рівні структурної організації живого|рівнем структурної організації живого]] в організмі людини. Вона є базовим модулем, на основі якого будується весь організм.
Одноманітні за будовою та походженням клітини, об'єднані [[Міжклітинні контакти|міжклітинними контактами]] та [[Міжклітинна речовина|міжклітинною речовиною]], формують ''[[Тканини|тканини]]'' (епітеліальну, сполучну, м'язову, нервову). Різні типи тканин, скоординовано взаємодіючи, утворюють ''[[Органи|органи]]'', кожен з яких виконує специфічну функцію (серце, печінка, нирка). Органи об'єднуються в ''[[Системи органів|системи органів]]'' (травну, дихальну, кровоносну), які забезпечують життєдіяльність цілісного багатоклітинного організму.
Отже, зміни або порушення функцій на рівні окремої клітини (наприклад, через [[Генетична мутація|генетичну мутацію]] чи вплив [[Токсин|токсинів]]) неминуче відбиваються на функціональному стані [[Тканина|тканини]], [[Орган|органу]] і, зрештою, всього [[Організм|організму]]. Це підкреслює [[Фундаментальний принцип біології|фундаментальний принцип біології]]: [[Клітина|клітина]] є не просто частиною цілого, а базовою одиницею, яка визначає всі [[Рівні організації людського тіла|рівні організації людського тіла]]. Таким чином, вивчення будови та функцій [[Клітина|клітини]] є необхідною передумовою для розуміння [[Фізіологія|фізіології]], [[Патологія|патології]] та [[Медицина|медицини]] загалом.
[[Category:UK]]
[[Category:Біологія людини]]
[[Category:Основний простір]]
guh88ro1w5kp3ls5sh2ij555ypz7bxz
385114
385113
2026-06-28T15:13:35Z
Віталій Васильович Івчук
55643
385114
wikitext
text/x-wiki
== Клітина як відкрита біологічна система ==
Клітина є елементарною структурно-функціональною одиницею живого, яка характеризується всіма ознаками організму: ростом, розвитком, подразливістю, метаболізмом та здатністю до самовідтворення. У контексті системного підходу клітина розглядається як ''[[Відкрита біологічна система|відкрита біологічна система]]''. Це визначення означає, що для підтримання власної організації ([[Гомеостаз|гомеостазу]]) вона перебуває у безперервному діалозі з позаклітинним середовищем.
Відкритість системи реалізується через постійний [[Трансмембранний транспорт речовин|трансмембранний транспорт речовин]]. Клітина споживає з навколишнього середовища субстрати ([[Глюкоза|глюкозу]], [[Амінокислоти|амінокислоти]], [[Іони|іони]], [[Кисень|кисень]]), які використовує як джерела енергії та будівельного матеріалу. У процесі [[Катаболічні реакції|катаболічних реакцій]] відбувається розщеплення складних молекул із вивільненням енергії, необхідної для синтезу [[АТФ]]. Продукти метаболізму ([[Вуглекислий газ|вуглекислий газ]], [[Сечовина|сечовина]], надлишок [[Вода|води]]) виводяться назовні. Таким чином, потік речовин та енергії через мембрану є необхідною умовою існування клітини як цілісної системи. Припинення цього обміну означає її смерть.
== Структурно-функціональна організація клітини ==
Досконалість клітини як системи забезпечується суворою відповідністю між будовою її компонентів та виконуваними функціями. Основними структурними елементами людської клітини є [[Плазматична мембрана|плазматична мембрана]], [[Цитоплазма|цитоплазма]] з [[Органели|органелами]] та [[Ядро|ядро]].
* ''[[Плазматична мембрана]] (плазмалема)''. Це бімолекулярний шар [[Фосфоліпіди|фосфоліпідів]] з інтегрованими в нього [[Білки|білками]] ([[Рецептори|рецепторами]], [[Ферменти|ферментами]], [[Іонні канали|каналами]]). Основна функція мембрани — бар’єрно-транспортна. Вона виступає вибірковим фільтром, забезпечуючи [[Вибіркова проникність|вибіркову проникність]] (напівпроникність). Завдяки наявності [[Глікокалікс|глікокаліксу]] (зовнішнього [[Вуглеводи|вуглеводного]] шару) мембрана бере участь у [[Міжклітинна взаємодія|міжклітинній взаємодії]] ([[Адгезія|адгезії]]) та розпізнаванні [[Сигнальні молекули|сигнальних молекул]], що є невід'ємною частиною регуляції системи.
* ''[[Цитоплазма]] та [[Органели|органели]]''. Цитоплазма являє собою внутрішнє [[Колоїди|колоїдне]] середовище ([[Цитозоль|цитозоль]]) та [[Цитоскелет|цитоскелет]], у якому розташовані органели.
** ''[[Мітохондрія|Мітохондрії]]'' — двомембранні органели, власна [[ДНК]] яких кодує [[Ферменти дихального ланцюга|ферменти дихального ланцюга]]. Їхня будова (наявність [[Кристи|крист]] для збільшення площі внутрішньої мембрани) максимально пристосована для синтезу [[АТФ]] у процесі [[Окисне фосфорилювання|окисного фосфорилювання]]. Вони є «енергетичними станціями» системи.
** ''[[Ендоплазматичний ретикулум]] (ЕР)'' — система мембранних цистерн. [[Гранулярний ендоплазматичний ретикулум|Гранулярний ЕР]] (з [[Рибосома|рибосомами]]) забезпечує синтез [[Білок|білків]] для експорту, тоді як [[Агранулярний ендоплазматичний ретикулум|агранулярний ЕР]] відповідає за синтез [[Ліпіди|ліпідів]] та [[Детоксикація|детоксикацію]]. [[Рибосоми]], що знаходяться на [[Ендоплазматичний ретикулум|ЕР]] або вільно, є немембранними структурами, які забезпечують трансляцію генетичного коду.
** ''[[Апарат Гольджі]]'' — виконує функцію сортування, модифікації та пакування синтезованих речовин у [[Везикули|везикули]] (секреторні бульбашки), забезпечуючи спрямований транспорт продуктів як всередину клітини, так і назовні.
** ''[[Лізосома|Лізосоми]]'' — [[Везикули|везикули]] з [[Гідролітичні ферменти|гідролітичними ферментами]], що забезпечують [[Внутрішньоклітинне травлення|внутрішньоклітинне травлення]] ([[Автофагія|автофагію]]) — оновлення зношених [[Органели|органел]], що підтримує динамічну рівновагу системи.
** ''[[Цитоскелет]] ([[Мікротрубочки|мікротрубочки]] та [[Мікрофіламенти|мікрофіламенти]])'' формує опорно-руховий апарат, що дозволяє клітині змінювати форму та забезпечує внутрішнє переміщення [[Органели|органел]].
* ''[[Ядро]]''. [[Ядро]] є інформаційним та регуляторним центром системи. Обмежене подвійною ядерною мембраною з [[Ядерні пори|ядерними порами]], воно містить [[Хроматин|хроматин]] (комплекс [[ДНК]] з [[Білки гістони|білками гістонами]]) та [[Ядерце|ядерце]]. Будова [[Ядро|ядра]] забезпечує збереження, [[реплікація|реплікацію]] та [[транскрипція|транскрипцію]] [[Спадкова інформація|спадкової інформації]]. Саме [[Ядро|ядро]] керує синтезом специфічних [[Білки|білків]] через утворення [[Матрична РНК|матричних РНК]], визначаючи, які [[Метаболічні шляхи|метаболічні шляхи]] будуть активовані у відповідь на зовнішні чи внутрішні сигнали.
== Взаємозв’язок компонентів та цілісність системи ==
Клітина функціонує як єдина система завдяки суворій узгодженості роботи всіх її відділів. Цей взаємозв'язок забезпечується через [[Сигнальні молекули|сигнальні молекули]], потоки [[Іони кальцію|іонів кальцію]] та [[Каскади ферментативних реакцій|каскади ферментативних реакцій]].
Розглянемо [[Цикл забезпечення енергією|цикл забезпечення енергією]]: надходження [[Глюкоза|глюкози]] через [[Рецептори мембрани клітини|рецептори мембрани]] активує [[Ферменти цитоплазми|ферменти цитоплазми]] ([[Гліколіз|гліколіз]]). Продукти [[Гліколіз|гліколізу]] транспортуються в [[Мітохондрія|мітохондрії]], де утворюється [[АТФ]]. Енергія [[АТФ]] використовується [[Апарат Гольджі|апаратом Гольджі]] для [[Активний транспорт речовин|активного транспорту речовин]], а також [[Цитоскелет|цитоскелетом]] для руху. Якщо в клітині накопичуються пошкоджені [[Білок|білки]], [[Ядро|ядро]] активує [[Гени клітинного стресу|гени "клітинного стресу"]], що призводить до посилення роботи [[Лізосома|лізосом]] або запуску механізму [[Апоптоз|апоптозу]] (програмованої загибелі) для порятунку організму. Таким чином, будь-яка зміна в одному компоненті викликає адаптивну зміну в інших, що підтримує системну рівновагу ([[Гомеостаз|гомеостаз]]).
[[Метаболізм]] (сукупність [[Катаболізм|катаболізму]] та [[Анаболізм|анаболізму]]) є інтегральною властивістю системи, яка виникає завдяки сукупній взаємодії [[Органели|органел]], а не є сумою їхніх окремих функцій.
== Клітина як основа організменної ієрархії ==
Клітина є першим (елементарним) [[Рівні структурної організації живого|рівнем структурної організації живого]] в організмі людини. Вона є базовим модулем, на основі якого будується весь організм.
Одноманітні за будовою та походженням клітини, об'єднані [[Міжклітинні контакти|міжклітинними контактами]] та [[Міжклітинна речовина|міжклітинною речовиною]], формують ''[[Тканини|тканини]]'' (епітеліальну, сполучну, м'язову, нервову). Різні типи тканин, скоординовано взаємодіючи, утворюють ''[[Органи|органи]]'', кожен з яких виконує специфічну функцію (серце, печінка, нирка). Органи об'єднуються в ''[[Системи органів|системи органів]]'' (травну, дихальну, кровоносну), які забезпечують життєдіяльність цілісного багатоклітинного організму.
Отже, зміни або порушення функцій на рівні окремої клітини (наприклад, через [[Генетична мутація|генетичну мутацію]] чи вплив [[Токсин|токсинів]]) неминуче відбиваються на функціональному стані [[Тканина|тканини]], [[Орган|органу]] і, зрештою, всього [[Організм|організму]]. Це підкреслює [[Фундаментальний принцип біології|фундаментальний принцип біології]]: клітина є не просто частиною цілого, а базовою одиницею, яка визначає всі [[Рівні організації людського тіла|рівні організації людського тіла]]. Таким чином, вивчення будови та функцій клітини є необхідною передумовою для розуміння [[Фізіологія|фізіології]], [[Патологія|патології]] та [[Медицина|медицини]] загалом.
[[Category:UK]]
[[Category:Біологія людини]]
[[Category:Основний простір]]
7o3lli8gxzziu5tdugm2mag75aj07qs
Зображення/Біологічна система. Будова людської клітини
0
55804
385111
385107
2026-06-28T14:22:55Z
Віталій Васильович Івчук
55643
385111
wikitext
text/x-wiki
__NOTOC__
== Біологічна система. Будова та функції людської клітини ==
[[File:Біологічна система. Будова та функції людської клітини.png|thumb|center|Біологічна система. Будова та функції людської клітини]]
[[Category:UK]]
[[Category:Зображення]]
[[Category:Основний простір]]
1j54nele43y1pbh4g0r0a3b59pcwi8s
Рэндэрынг мноства Мандэльброта на C++
0
55805
385115
2026-06-29T05:34:15Z
Aokoroko
55658
Created page with "{{Language|be}} {| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;" |- ! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++» |- | '''Факультэт:''' || Інфармацыйныя тэхналогіі |- | '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў |- | '''Патрабаванні пасля:''' || Навыкі аптыміза..."
385115
wikitext
text/x-wiki
{{Language|be}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[Category:be:Computer science]]
hkwbx1h93wja19sjoxmwd1lfgxgizm9
385117
385115
2026-06-29T05:51:48Z
Aokoroko
55658
385117
wikitext
text/x-wiki
{{Language|be}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[uk:Рендеринг множини Мандельброта на C++]]
[[Category:be:Computer science]]
d1ic506e9z8ni4b9yjpbs9rjkrti753
385119
385117
2026-06-29T06:13:05Z
Aokoroko
55658
385119
wikitext
text/x-wiki
{{Language|be}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[betawikiversity:uk:Рендеринг множини Мандельброта на C++]]
[[Category:be:Computer science]]
4fx6tym6e5wzypx38j2awcp0sjzbg0c
385121
385119
2026-06-29T06:17:22Z
Aokoroko
55658
385121
wikitext
text/x-wiki
{{Language|be}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[uk:Рендеринг множини Мандельброта на C++|uk:]]
[[Category:be:Computer science]]
8ui4d2gq4t5ub7g9c9avqggox24yrqp
385123
385121
2026-06-29T06:23:16Z
Aokoroko
55658
385123
wikitext
text/x-wiki
{{Language|be}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[uk:Рендеринг множини Мандельброта на C++|uk]]
[[Category:be:Computer science]]
hsdy4unyhn79jkv7y6ajtcdusvjgbcr
385125
385123
2026-06-29T06:28:07Z
Aokoroko
55658
385125
wikitext
text/x-wiki
{{Language|be}}
<div style="background: #f8f9fa; border: 1px solid #a2a9b1; padding: 10px; margin-bottom: 15px; border-radius: 4px;">
'''Мовы курса / Мови курсу:'''
* 🇷🇺 [[ruwikiversity:Рендеринг_множества_Мандельброта_на_C%2B%2B|Русский (ru)]]
* 🇧🇾 '''Беларуская (be)'''
* 🇺🇦 [[uk:Рендеринг множини Мандельброта на C++|Українська (uk)]]
</div>
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[Category:be:Computer science]]
48qu1yrqfgmqd5o0jnsvzajers6tp1r
385127
385125
2026-06-29T06:37:37Z
Aokoroko
55658
385127
wikitext
text/x-wiki
{{Language|be}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[Category:be:Computer science]]
hkwbx1h93wja19sjoxmwd1lfgxgizm9
385129
385127
2026-06-29T06:47:03Z
Aokoroko
55658
385129
wikitext
text/x-wiki
{{Language|be}}
{{Interwiki|ru=ruwikiversity:Рендеринг_множества_Мандельброта_на_C%2B%2B|uk=uk:Рендеринг множини Мандельброта на C++}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[Category:be:Computer science]]
bn00jmv9biv2w4gbxy92n89jl74pkio
385131
385129
2026-06-29T06:59:18Z
Aokoroko
55658
385131
wikitext
text/x-wiki
{{Language|be}}
{{Interwiki|ru=ruwikiversity:Рендеринг_множества_Мандельброта_на_C%2B%2B|uk=Рендеринг множини Мандельброта на C++}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[Category:be:Computer science]]
3tnis5q5lrz8zpkbhaxoo7d2l94q9s5
385133
385131
2026-06-29T07:06:50Z
Aokoroko
55658
385133
wikitext
text/x-wiki
{{Language|be}} <span style="font-size:90%; color:#54595d;">Мовы курса:</span> [[ruwikiversity:Рендеринг_множества_Мандельброта_на_C%2B%2B|🇷🇺 Русский]] • '''🇧🇾 Беларуская''' • [[Рендеринг множини Мандельброта на C++|🇺🇦 Українська]]
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[Category:be:Computer science]]
4xasuv4c9y5ef294ux607fkia4mi813
385135
385133
2026-06-29T07:16:20Z
Aokoroko
55658
385135
wikitext
text/x-wiki
{{Language|be}} <span style="font-size:90%; color:#54595d;">Мовы курса:</span> [https://wikiversity.org 🇷🇺 Русский] • '''🇧🇾 Беларуская''' • [[Рендеринг множини Мандельброта на C++|🇺🇦 Українська]]
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[Category:be:Computer science]]
amv1jgnzwsuy2uw3m3emyk8bn1utxjn
385137
385135
2026-06-29T07:22:58Z
Aokoroko
55658
385137
wikitext
text/x-wiki
{{Language|be}} <span style="font-size:90%; color:#54595d;">Мовы курса:</span> [https://ru.wikiversity.org/wiki/Рендеринг_множества_Мандельброта_на_C%2B%2B 🇷🇺 Русский] • '''🇧🇾 Беларуская''' • [[Рендеринг множини Мандельброта на C++|🇺🇦 Українська]]
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рэндэрынг мноства Мандэльброта на C++»
|-
| '''Факультэт:''' || Інфармацыйныя тэхналогіі
|-
| '''Прэрэквізіты:''' || Веданне сінтаксісу C++ і камплексных лікаў
|-
| '''Патрабаванні пасля:''' || Навыкі аптымізацыі рэндэрынгу фракталаў
|-
| '''Выкладчык:''' || [[User:Aokoroko]]
|}
== Уводзіны ==
Дадзены практыкум змяшчае арыгінальны зыходны код на C++ для высокадакладнага рэндэрынгу фрагментаў мноства Мандэльброта з выкарыстаннем алгарытмаў аптымізацыі (уключаючы тэорыю абурэнняў) і глыбокага згладжвання (8x8 SSAA). Аўтар алгарытму і выяў: [[User:Aokoroko]].
== Ключавыя асаблівасці ==
* Разлік апорнай траекторыі на 5000 біт усяго адзін раз.
* Рэактыўны разлік мільярда пікселяў на апаратным double.
* Пры выкарыстанні лікаў з плаваючай коскай двайной дакладнасці (парадку 10⁻¹⁵) тэорыя абурэнняў дазваляе наблізіцца да ўзроўню 10⁻³08 - не далей.
* Рэвалюцыйны алгарытм Reference Reset to Zero.
* Сапраўдны SSAA 8x8 для ідэальна згладжанага малюнка без аліасінгу.
* Паралелізм OpenMP для высокахуткаснага шматпаточнага рэндэрынгу.
== Зыходны код C++ ==
Ніжэй прадстаўлены зыходны код праграмы, які выкарыстоўваўся для генерацыі 100-мегапіксельных выбраных выяў на Вікісховішчы.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Прыклады выяў ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 108.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 109.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
File:Mandelbrot Set Image 110.png|Фрагмент мноства, тэорыя абурэнняў. Адрознівальная здольнасць 10000 x 10000 пікселяў.
</gallery>
== Спасылкі ==
* [https://github.com/Divetoxx/Mandelbrot Афіцыйны рэпазіторый праекта Mandelbrot CLI на GitHub] — зыходны код, дакументацыя і гатовыя рэлізы праграмы рэндэрынгу.
[[Category:be:Computer science]]
999jdfqb0k9uxygv77mjqzyv5j90xyv
Рендеринг множини Мандельброта на C++
0
55806
385116
2026-06-29T05:45:41Z
Aokoroko
55658
Created page with "{{Language|uk}} {| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;" |- ! colspan="2" | Курс «Рендеринг множини Мандельброта на C++» |- | '''Факультет:''' || Інформаційні технології |- | '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел |- | '''Постреквізити:''' || Навички оптимізації р..."
385116
wikitext
text/x-wiki
{{Language|uk}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[Category:uk:Computer science]]
npqiy6fv0hm33gykfv5dg0ns3602ej2
385118
385116
2026-06-29T05:52:56Z
Aokoroko
55658
385118
wikitext
text/x-wiki
{{Language|uk}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[be:Рэндэрынг мноства Мандэльброта на C++]]
[[Category:uk:Computer science]]
mgs349bfpbeo7qnhedouyzj4dw4nbc2
385120
385118
2026-06-29T06:14:15Z
Aokoroko
55658
385120
wikitext
text/x-wiki
{{Language|uk}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[betawikiversity:be:Рэндэрынг мноства Мандэльброта на C++]]
[[Category:uk:Computer science]]
hotkl8orexy5jns95125gs3po0ybs41
385122
385120
2026-06-29T06:18:04Z
Aokoroko
55658
385122
wikitext
text/x-wiki
{{Language|uk}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[be:Рэндэрынг мноства Мандэльброта на C++|be:]]
[[Category:uk:Computer science]]
hcowh57l87efiv2tkdt2y2s562xz6pm
385124
385122
2026-06-29T06:23:50Z
Aokoroko
55658
385124
wikitext
text/x-wiki
{{Language|uk}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[be:Рэндэрынг мноства Мандэльброта на C++|be]]
[[Category:uk:Computer science]]
9k7semcdrohmuakv9ouo4ps67fa69ak
385126
385124
2026-06-29T06:29:07Z
Aokoroko
55658
385126
wikitext
text/x-wiki
{{Language|uk}}
<div style="background: #f8f9fa; border: 1px solid #a2a9b1; padding: 10px; margin-bottom: 15px; border-radius: 4px;">
'''Мовы курса / Мови курсу:'''
* 🇷🇺 [[ruwikiversity:Рендеринг_множества_Мандельброта_на_C%2B%2B|Русский (ru)]]
* 🇧🇾 [[be:Рэндэрынг мноства Мандэльброта на C++|Беларуская (be)]]
* 🇺🇦 '''Українська (uk)'''
</div>
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[Category:uk:Computer science]]
0v9m4abd4cpd6eegg3p1rudcde6a46w
385128
385126
2026-06-29T06:37:55Z
Aokoroko
55658
385128
wikitext
text/x-wiki
{{Language|uk}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[Category:uk:Computer science]]
npqiy6fv0hm33gykfv5dg0ns3602ej2
385130
385128
2026-06-29T06:47:46Z
Aokoroko
55658
385130
wikitext
text/x-wiki
{{Language|uk}}
{{Interwiki|ru=ruwikiversity:Рендеринг_множества_Мандельброта_на_C%2B%2B|be=be:Рэндэрынг мноства Мандэльброта на C++}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[Category:uk:Computer science]]
5agvir3hl4dfet1ahz94ih4ub99eipf
385132
385130
2026-06-29T07:01:03Z
Aokoroko
55658
385132
wikitext
text/x-wiki
{{Language|uk}}
{{Interwiki|ru=ruwikiversity:Рендеринг_множества_Мандельброта_на_C%2B%2B|be=Рэндэрынг мноства Мандэльброта на C++}}
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[Category:uk:Computer science]]
bkjcu3j490hfi55ug4f92a9vmc1289z
385134
385132
2026-06-29T07:07:56Z
Aokoroko
55658
385134
wikitext
text/x-wiki
{{Language|uk}} <span style="font-size:90%; color:#54595d;">Мови курсу:</span> [[ruwikiversity:Рендеринг_множества_Мандельброта_на_C%2B%2B|🇷🇺 Русский]] • [[Рэндэрынг мноства Мандэльброта на C++|🇧🇾 Беларуская]] • '''🇺🇦 Українська'''
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[Category:uk:Computer science]]
ro5j04mybk265u55l84mri9c7nzj9t2
385136
385134
2026-06-29T07:17:21Z
Aokoroko
55658
385136
wikitext
text/x-wiki
{{Language|uk}} <span style="font-size:90%; color:#54595d;">Мови курсу:</span> [https://wikiversity.org 🇷🇺 Русский] • [[Рэндэрынг мноства Мандэльброта на C++|🇧🇾 Беларуская]] • '''🇺🇦 Українська'''
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[Category:uk:Computer science]]
7ihmympvysgpxzni8qbeclcf9iufac4
385138
385136
2026-06-29T07:24:38Z
Aokoroko
55658
385138
wikitext
text/x-wiki
{{Language|uk}} <span style="font-size:90%; color:#54595d;">Мови курсу:</span> [https://ru.wikiversity.org/wiki/Рендеринг_множества_Мандельброта_на_C%2B%2B 🇷🇺 Русский] • [[Рэндэрынг мноства Мандэльброта на C++|🇧🇾 Беларуская]] • '''🇺🇦 Українська'''
{| class="wikitable" style="float: right; margin: 0 0 1em 1em; width: 300px;"
|-
! colspan="2" | Курс «Рендеринг множини Мандельброта на C++»
|-
| '''Факультет:''' || Інформаційні технології
|-
| '''Пререквізити:''' || Знання синтаксису C++ та комплексних чисел
|-
| '''Постреквізити:''' || Навички оптимізації рендерингу фракталів
|-
| '''Викладач:''' || [[User:Aokoroko]]
|}
== Вступ ==
Даний практикум містить оригінальний вихідний код на C++ для високоточного рендерингу фрагментів множини Мандельброта з використанням алгоритмів оптимізації (включаючи теорію збурень) та глибокого згладжування (8x8 SSAA). Автор алгоритму та зображень: [[User:Aokoroko]].
== Ключові особливості ==
* Розрахунок опорної траєкторії на 5000 біт усього один раз.
* Реактивний розрахунок мільярда пікселів на апаратному double.
* При використанні чисел із плаваючою комою подвійної точності (порядку 10⁻¹⁵) теорія збурень дозволяє наблизитися до рівня 10⁻³⁰⁸ - не далі.
* Революційний алгоритм Reference Reset to Zero.
* Справжній SSAA 8x8 для ідеально згладженого зображення без аліасингу.
* Паралелізм OpenMP для високошвидкісного багатопотокового рендерингу.
== Вихідний код C++ ==
Ниже представлений вихідний код програми, що використовувався для генерації 100-мегапіксельних вибраних зображень на Вікісховищі.
<syntaxhighlight lang="cpp">
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <string>
#include <atomic>
#include <omp.h>
#include <cstdio>
#include <iomanip>
#include <gmp.h>
#include <mpfr.h>
using namespace std;
const double PI = 3.14159265358979323846;
const mpfr_prec_t MPFR_BITS = 5000;
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint16_t reserved1{0};
uint16_t reserved2{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xpelsPerMeter{2834};
int32_t ypelsPerMeter{2834};
uint32_t clrUsed{0};
uint32_t clrImportant{0};
};
#pragma pack(pop)
struct ComplexDouble {
double re;
double im;
};
void save_bmp(const string& filename, const vector<uint8_t>& data, int w, int h) {
int rowSize = (w * 3 + 3) & ~3;
BMPHeader header;
header.width = w;
header.height = h;
header.sizeImage = rowSize * h;
header.size = header.sizeImage + 54;
ofstream f(filename, ios::binary);
f.write(reinterpret_cast<char*>(&header), 54);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
f.close();
}
int main() {
string absc_str, ordi_str, size_str;
absc_str = "-1.74907816150520173167912454515663360420734509948112463480292338384";
ordi_str = "-0.00000550991906629096602513098567268615714673236269915508056068145";
size_str = "0.0000000000000000000000000000000000000000000000000000000000000153";
const int targetW = 10000;
const int targetH = 10000;
const int scale = 8;
const int rawW = targetW * scale;
const int rawH = targetH * scale;
cout << "Step 1: Calculating Raw Map (" << rawW << "x" << rawH << ") using Perturbation..." << endl;
vector<uint8_t> iterMap((size_t)rawW * rawH);
mpfr_t rx, ry, zr, zi, zr2, zi2, tmp, sz, st;
mpfr_inits2(MPFR_BITS, rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
mpfr_set_str(rx, absc_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(ry, ordi_str.c_str(), 10, MPFR_RNDN);
mpfr_set_str(sz, size_str.c_str(), 10, MPFR_RNDN);
mpfr_div_ui(st, sz, rawW, MPFR_RNDN);
double step_d = mpfr_get_d(st, MPFR_RNDN);
double ref_rec_d = mpfr_get_d(rx, MPFR_RNDN);
double ref_imc_d = mpfr_get_d(ry, MPFR_RNDN);
vector<ComplexDouble> ref_orbit_double(50005);
mpfr_set_ui(zr, 0, MPFR_RNDN);
mpfr_set_ui(zi, 0, MPFR_RNDN);
mpfr_set_ui(zr2, 0, MPFR_RNDN);
mpfr_set_ui(zi2, 0, MPFR_RNDN);
uint32_t ref_i = 0;
bool escaped = false;
while (ref_i < 50000) {
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
mpfr_mul(tmp, zr, zi, MPFR_RNDN);
mpfr_mul_ui(zi, tmp, 2, MPFR_RNDN);
mpfr_add(zi, zi, ry, MPFR_RNDN);
mpfr_sub(zr, zr2, zi2, MPFR_RNDN);
mpfr_add(zr, zr, rx, MPFR_RNDN);
mpfr_mul(zr2, zr, zr, MPFR_RNDN);
mpfr_mul(zi2, zi, zi, MPFR_RNDN);
if (escaped) {
ref_i++;
break;
}
mpfr_add(tmp, zr2, zi2, MPFR_RNDN);
if (mpfr_cmp_d(tmp, 4.0) >= 0) {
escaped = true;
}
ref_i++;
}
ref_orbit_double[ref_i].re = mpfr_get_d(zr, MPFR_RNDN);
ref_orbit_double[ref_i].im = mpfr_get_d(zi, MPFR_RNDN);
uint32_t max_valid_ref_iter = ref_i;
mpfr_clears(rx, ry, zr, zi, zr2, zi2, tmp, sz, st, NULL);
atomic<int> linesDone{0};
#pragma omp parallel for schedule(dynamic)
for (size_t b = 0; b < (size_t)rawH; ++b) {
for (size_t a = 0; a < (size_t)rawW; ++a) {
double delta_rec = (double)((long long)a - (rawW / 2)) * step_d;
double delta_imc = (double)((long long)b - (rawH / 2)) * step_d;
uint32_t index = 0;
double delta_re = 0.0;
double delta_im = 0.0;
double z_re = 0.0;
double z_im = 0.0;
uint32_t i = 0;
const ComplexDouble* ref_ptr = ref_orbit_double.data();
while (i < max_valid_ref_iter) {
if ((z_re * z_re + z_im * z_im) >= 40000.0) {
break;
}
if ((z_re * z_re + z_im * z_im) < (delta_re * delta_re + delta_im * delta_im)) {
index = 0;
delta_re = z_re;
delta_im = z_im;
}
for (int step = 0; step < 2; ++step) {
double Ur = ref_ptr[index].re;
double Ui = ref_ptr[index].im;
double next_delta_im = 2.0 * Ur * delta_im + 2.0 * Ui * delta_re + 2.0 * delta_re * delta_im + delta_imc;
delta_re = 2.0 * Ur * delta_re - 2.0 * Ui * delta_im + delta_re * delta_re - delta_im * delta_im + delta_rec;
delta_im = next_delta_im;
index++;
}
z_re = ref_ptr[index].re + delta_re;
z_im = ref_ptr[index].im + delta_im;
i += 2;
}
int final_t = 50000 - i;
if (final_t == 0) {
iterMap[b * (size_t)rawW + a] = 255;
} else {
iterMap[b * (size_t)rawW + a] = (uint8_t)(final_t % 254);
}
}
if (++linesDone % 100 == 0) cout << "Progress: " << linesDone << "/" << rawH << "\r" << flush;
}
uint8_t pal[256][3];
for (int a = 0; a < 255; ++a) {
pal[a][0] = (uint8_t)round(127.0 + 127.0 * cos(2.0 * PI * a / 255.0)); // Blue
pal[a][1] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Green
pal[a][2] = (uint8_t)round(127.0 + 127.0 * sin(2.0 * PI * a / 255.0)); // Red
}
pal[255][0] = 255; pal[255][1] = 255; pal[255][2] = 255;
cout << "\nStep 2: Rendering frames..." << endl;
int rowSize = (targetW * 3 + 3) & ~3;
for (int frame = 0; frame < 255; ++frame) {
vector<uint8_t> frameData(rowSize * targetH);
#pragma omp parallel for schedule(static)
for (int y = 0; y < targetH; ++y) {
for (int x = 0; x < targetW; ++x) {
uint32_t rSum = 0, gSum = 0, bSum = 0;
for (int j = 0; j < scale; ++j) {
size_t mapRowIdx = (size_t)(y * scale + j) * rawW;
for (int i = 0; i < scale; ++i) {
uint8_t t = iterMap[mapRowIdx + (x * scale + i)];
int colorIdx;
if (t == 255) {
colorIdx = 255;
} else {
colorIdx = (t - frame + 255) % 255;
}
bSum += pal[colorIdx][0];
gSum += pal[colorIdx][1];
rSum += pal[colorIdx][2];
}
}
int outIdx = y * rowSize + x * 3;
frameData[outIdx + 0] = (uint8_t)(bSum >> 6);
frameData[outIdx + 1] = (uint8_t)(gSum >> 6);
frameData[outIdx + 2] = (uint8_t)(rSum >> 6);
}
}
string filename = "Mandelbrot" + to_string(1000 + frame).substr(1) + ".bmp";
save_bmp(filename, frameData, targetW, targetH);
cout << "Frame " << frame << "/254 saved. \r" << flush;
}
return 0;
}
</syntaxhighlight>
== Приклади зображень ==
<gallery mode="packed" heights="200">
File:Mandelbrot Set Image 107.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 108.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 109.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
File:Mandelbrot Set Image 110.png|Фрагмент множини, теорія збурень. Роздільна здатність 10000 x 10000 пікселів.
</gallery>
== Посилання ==
* [https://github.com/Divetoxx/Mandelbrot Офіційний репозиторій проєкту Mandelbrot CLI на GitHub] — вихідний код, документація та готові релізи програми рендерингу.
[[Category:uk:Computer science]]
bc66vlgqz4gzdqzskjuns3dfsl5nl8e
Category:Be:Computer science
14
55807
385139
2026-06-29T08:20:51Z
Aokoroko
55658
Created page with "[[Category:Computer science]]"
385139
wikitext
text/x-wiki
[[Category:Computer science]]
nafyhsyu57q8bfwcbvoy4q7xbyabn5q
Category:Uk:Computer science
14
55808
385140
2026-06-29T08:21:53Z
Aokoroko
55658
Created page with "[[Category:Computer science]]"
385140
wikitext
text/x-wiki
[[Category:Computer science]]
nafyhsyu57q8bfwcbvoy4q7xbyabn5q
Template:Wv/syl/Move
10
55809
385141
2026-06-29T10:55:44Z
Пан Хаунд 2
52749
Copied content from [[:w:uk:Шаблон: Перейменувати]]. See source page history for attribution.
385141
wikitext
text/x-wiki
<span class="nowrap"><span class="opinion-template-image">[[Файл:Symbol move vote.svg|15px|→|link=]] </span>'''{{{текст|Перейменувати}}}'''</span>{{#if: {{{1|}}} |  на [[{{{1}}}]] }}<noinclude>{{doc}}</noinclude>
o2e0hvtxl6ny2tnoiev7hd19zjt5ppn
385142
385141
2026-06-29T10:56:17Z
Пан Хаунд 2
52749
/* */
385142
wikitext
text/x-wiki
<span class="nowrap"><span class="opinion-template-image">[[File:Symbol move vote.svg|15px|→|link=]] </span>'''{{{text|Move}}}'''</span>{{#if: {{{1|}}} |  to [[{{{1}}}]] }}<noinclude>{{Wv/syl/Documentation}}</noinclude>
kxhkey1qgdf1o2hnosqpr6gbrssifn5