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|}}} | &#32;на [[{{{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|}}} | &#32;to [[{{{1}}}]] }}<noinclude>{{Wv/syl/Documentation}}</noinclude> kxhkey1qgdf1o2hnosqpr6gbrssifn5