Викиучебник ruwikibooks https://ru.wikibooks.org/wiki/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0 MediaWiki 1.47.0-wmf.14 first-letter Медиа Служебная Обсуждение Участник Обсуждение участника Викиучебник Обсуждение Викиучебника Файл Обсуждение файла MediaWiki Обсуждение MediaWiki Шаблон Обсуждение шаблона Справка Обсуждение справки Категория Обсуждение категории Полка Обсуждение полки Импортировано Обсуждение импортированного Рецепт Обсуждение рецепта Задача Обсуждение задачи TimedText TimedText talk Модуль Обсуждение модуля Event Event talk Рецепт:Мясо по-милански 104 4187 269735 255319 2026-08-04T12:25:38Z Byzantine 50481 орфография 269735 wikitext text/x-wiki {{Рецепт |Изображение = |Категория = Вторые блюда |Кухня = |Порций = |Время = |Сложность = |Энергетическая ценность = |Ингредиенты = Свинина }} == Cпособ готовки == (Делается все слоями) Можно готовить в блюде для запеканок или почастно. Блюдо смазывается подсолнечным маслом. Кусочки свинины нежирной посолить и поперчить, слегка обжарить на масле, затем обложить ими дно блюда. Очищенный сырой картофель протереть через терку на свинину. Лук репчатый порезать полукольцами, нарезать помидор кольцами и разложить поверх лука (можно приправить), чуть-чуть майонеза размазать, натереть сыр и обильно посыпать сверху. Запекать при 180-200 °C до золотистой корки. Так же готовится мясо «по-французски», где лишь вместо свинины берут телятину. 8actfqi1wu4ys06k4im5k7b398phuvw Множество Мандельброта 0 19810 269738 269560 2026-08-04T18:00:22Z Aokoroko 47596 /* Примеры программ */ 269738 wikitext text/x-wiki {{Название учебника | Категория = Программирование, Математика | Тип = Одностраничный | Готовность = 25% }} [[Файл:Mandelset hires.png|thumb|300px|Множество Мандельброта]]{{Wikipedia}} '''Мно́жество Мандельбро́та''' — это множество таких точек ''c'' на комплексной плоскости, для которых рекуррентное соотношение <math>z_{n+1} = {z_n}^2 + c</math> при <math>z_0 = 0</math> задаёт ограниченную последовательность. То есть, это множество таких ''c'', для которых существует такое действительное ''R'', что неравенство |''z''<sub>''n''</sub>|<''R'' выполняется при всех натуральных ''n''. == Построение множества == Несложно доказать, что как только модуль ''z''<sub>''n''</sub> окажется больше 2 (или, в терминах действительной и мнимой частей, ''x''<sub>''n''</sub><sup>2</sup>+''y''<sub>''n''</sub><sup>2</sup>>4), последовательность станет стремиться к бесконечности. В случае |''c''|≤2 это можно доказать с помощью метода математической индукции. При |''c''|>2 точка ''c'' заведомо не принадлежит множеству Мандельброта, что также можно вывести методом индукции, используя равенство ''z''<sub>0</sub>=0. (Хотя в этом случае может существовать другое ''z''<sub>0</sub>, для которого соответствующая последовательность ограничена по модулю, но для некоторого ''n'' выполняется неравенство |''z''<sub>''n''</sub>|>2.) Сравнение |''z''<sub>''n''</sub>| с этим числом (в англоязычной литературе его называют «bail-out») позволяет выделять точки, не попадающие внутрь множества. Для точек, лежащих внутри множества, последовательность не будет иметь тенденции к бесконечности и никогда не достигнет этого числа, поэтому после определённого числа итераций расчёт необходимо принудительно завершить. Максимальное число итераций, после которых число считается попавшим внутрь множества, задается в программе. Изображение, полученное таким способом, является лишь приближением к реальному множеству Мандельброта. Более качественные результаты можно получать, увеличивая максимальное количество итераций, однако при этом пропорционально вырастает и время расчётов. === Примеры программ === ==== Консольный рендерер Мандельброта с методом возмущений и предела 10<sup>−308</sup> (на языке программирования [[C++]]) ==== Ключевые особенности * Расчёт опорной траектории на 5000 бит всего один раз. * Реактивный расчёт миллиарда пикселей на аппаратном double. * При использовании чисел с плавающей запятой двойной точности (порядка 10⁻¹⁵) теория возмущений позволяет приблизиться к уровню 10⁻³⁰⁸ - не дальше. * Революционный алгоритм Reference Reset to Zero. * Настоящий SSAA 8x8 для идеально сглаженного изображения без алиасинга. * Параллелизм OpenMP для высокоскоростного многопоточного рендеринга. <syntaxhighlight lang="c++"> #include <atomic> #include <cmath> #include <cstdint> #include <cstdio> #include <vector> #include <algorithm> #include <mpfr.h> #include <omp.h> using std::vector; using std::min; const char * CENTER_RE = "-1.99999543561201124623198345433951143502785679245726844745821388800402678499411681518036306219179273434395557574279985918047221291197081186140687781560831995"; const char * CENTER_IM = "-0.00000000000000000000000026198152173811047783694060060607013913873144250985383083459221663448338433592617272786772587281530484110756597337683912309313885172"; const char * VIEW_SIZE = "1.15e-119"; const int WIDTH = 2160; const int HEIGHT = 2160; const int AA = 8; const int MAX_ITER = 50000; const double ESCAPE_RADIUS_SQUARED = 50000.0; const int PALETTE_FRAME = 200; const char * OUTPUT_FILE = "Mandelbrot Set Image 112.bmp"; const mpfr_prec_t PRECISION_BITS = 1000; struct Complex { double re; double im; }; #pragma pack(push, 1) struct BMPHeader { uint16_t type{0x4D42}; uint32_t size{0}; uint32_t reserved{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 xPixelsPerMeter{2834}; int32_t yPixelsPerMeter{2834}; uint32_t colorsUsed{0}; uint32_t colorsImportant{0}; }; #pragma pack(pop) int main() { const double startTime = omp_get_wtime(); const long rawWidth = static_cast<long>(WIDTH) * AA; const long rawHeight = static_cast<long>(HEIGHT) * AA; mpfr_t centerRe, centerIm, zReMp, zImMp, tmp1, tmp2, viewSizeMp; mpfr_inits2(PRECISION_BITS, centerRe, centerIm, zReMp, zImMp, tmp1, tmp2, viewSizeMp, static_cast<mpfr_ptr>(nullptr)); mpfr_set_str(centerRe, CENTER_RE, 10, MPFR_RNDN); mpfr_set_str(centerIm, CENTER_IM, 10, MPFR_RNDN); mpfr_set_str(viewSizeMp, VIEW_SIZE, 10, MPFR_RNDN); const double sampleStep = mpfr_get_d(viewSizeMp, MPFR_RNDN) / rawWidth; vector<Complex> referenceOrbit; referenceOrbit.reserve(MAX_ITER + 200); mpfr_set_ui(zReMp, 0, MPFR_RNDN); mpfr_set_ui(zImMp, 0, MPFR_RNDN); for (int iter = 0; iter <= MAX_ITER + 150; ++iter) { Complex z{mpfr_get_d(zReMp, MPFR_RNDN), mpfr_get_d(zImMp, MPFR_RNDN)}; referenceOrbit.push_back(z); if (z.re * z.re + z.im * z.im > ESCAPE_RADIUS_SQUARED && iter > MAX_ITER) { break; } mpfr_mul(tmp1, zReMp, zImMp, MPFR_RNDN); mpfr_sqr(tmp2, zReMp, MPFR_RNDN); mpfr_sqr(zReMp, zImMp, MPFR_RNDN); mpfr_sub(zReMp, tmp2, zReMp, MPFR_RNDN); mpfr_add(zReMp, zReMp, centerRe, MPFR_RNDN); mpfr_mul_2ui(tmp1, tmp1, 1, MPFR_RNDN); mpfr_add(zImMp, tmp1, centerIm, MPFR_RNDN); } const int referenceLength = static_cast<int>(referenceOrbit.size()); mpfr_clears(centerRe, centerIm, zReMp, zImMp, tmp1, tmp2, viewSizeMp, static_cast<mpfr_ptr>(nullptr)); std::fprintf(stderr, "Reference orbit: %d points\n", referenceLength); std::fprintf(stderr, "Precomputing skip100 matrices...\n"); vector<Complex> coeff_A(referenceLength, {1.0, 0.0}); vector<Complex> coeff_B(referenceLength, {0.0, 0.0}); vector<double> rad_R(referenceLength, 2.0); #pragma omp parallel for for (int i = 0; i < MAX_ITER; ++i) { double min_r = 2.0; for (int k = 0; k < 100; ++k) { if (i + k >= referenceLength) break; double r_re = referenceOrbit[i + k].re; double r_im = referenceOrbit[i + k].im; double abs_s = std::sqrt(r_re * r_re + r_im * r_im); double aS = (abs_s < 2.0) ? abs_s : 0.0; min_r = min(min_r, aS); double next_A_re = 2.0 * (r_re * coeff_A[i].re - r_im * coeff_A[i].im); double next_A_im = 2.0 * (r_re * coeff_A[i].im + r_im * coeff_A[i].re); double next_B_re = 2.0 * (r_re * coeff_B[i].re - r_im * coeff_B[i].im) + 1.0; double next_B_im = 2.0 * (r_re * coeff_B[i].im + r_im * coeff_B[i].re); coeff_A[i].re = next_A_re; coeff_A[i].im = next_A_im; coeff_B[i].re = next_B_re; coeff_B[i].im = next_B_im; } rad_R[i] = min_r; } const double PI = 3.14159265358979323846; uint8_t palette[256][3]; for (int i = 0; i < 255; ++i) { palette[i][0] = static_cast<uint8_t>(std::lround(127.0 + 127.0 * std::cos(2.0 * PI * i / 255.0))); palette[i][1] = static_cast<uint8_t>(std::lround(127.0 + 127.0 * std::sin(2.0 * PI * i / 255.0))); palette[i][2] = palette[i][1]; } palette[255][0] = 255; palette[255][1] = 255; palette[255][2] = 255; const int rowBytes = (WIDTH * 3 + 3) & ~3; vector<uint8_t> image(static_cast<size_t>(rowBytes) * HEIGHT, 0); std::atomic<int> completedRows{0}; const Complex * reference = referenceOrbit.data(); #pragma omp parallel for schedule(dynamic) for (int y = 0; y < HEIGHT; ++y) { uint8_t * row = image.data() + static_cast<size_t>(y) * rowBytes; for (int x = 0; x < WIDTH; ++x) { unsigned blueSum = 0; unsigned greenSum = 0; unsigned redSum = 0; for (int sampleY = 0; sampleY < AA; ++sampleY) { const double deltaCIm = (static_cast<long>(y) * AA + sampleY - rawHeight / 2) * sampleStep; for (int sampleX = 0; sampleX < AA; ++sampleX) { const double deltaCRe = (static_cast<long>(x) * AA + sampleX - rawWidth / 2) * sampleStep; double deltaRe = 0.0; double deltaIm = 0.0; double zRe = 0.0; double zIm = 0.0; int referenceIndex = 0; int iter = 0; while (iter < MAX_ITER) { if (zRe * zRe + zIm * zIm >= ESCAPE_RADIUS_SQUARED) { break; } double eps_abs2 = deltaRe * deltaRe + deltaIm * deltaIm; double limit_r2 = 1e-60 * rad_R[referenceIndex] * rad_R[referenceIndex]; if (eps_abs2 < limit_r2 && (referenceIndex + 100 < referenceLength - 1) && (iter + 100 < MAX_ITER)) { double backup_deltaRe = deltaRe; double backup_deltaIm = deltaIm; int backup_refIdx = referenceIndex; int backup_iter = iter; double next_eps_re = (coeff_A[referenceIndex].re * deltaRe - coeff_A[referenceIndex].im * deltaIm) + (coeff_B[referenceIndex].re * deltaCRe - coeff_B[referenceIndex].im * deltaCIm); double next_eps_im = (coeff_A[referenceIndex].re * deltaIm + coeff_A[referenceIndex].im * deltaRe) + (coeff_B[referenceIndex].re * deltaCIm + coeff_B[referenceIndex].im * deltaCRe); deltaRe = next_eps_re; deltaIm = next_eps_im; referenceIndex += 100; iter += 100; zRe = reference[referenceIndex].re + deltaRe; zIm = reference[referenceIndex].im + deltaIm; if (zRe * zRe + zIm * zIm >= ESCAPE_RADIUS_SQUARED) { deltaRe = backup_deltaRe; deltaIm = backup_deltaIm; referenceIndex = backup_refIdx; iter = backup_iter; } else { continue; } } const double a = 2.0 * reference[referenceIndex].re + deltaRe; const double b = 2.0 * reference[referenceIndex].im + deltaIm; const double nextDeltaRe = a * deltaRe - b * deltaIm + deltaCRe; deltaIm = a * deltaIm + b * deltaRe + deltaCIm; deltaRe = nextDeltaRe; ++referenceIndex; ++iter; zRe = reference[referenceIndex].re + deltaRe; zIm = reference[referenceIndex].im + deltaIm; if (zRe * zRe + zIm * zIm < deltaRe * deltaRe + deltaIm * deltaIm || referenceIndex == referenceLength - 1) { deltaRe = zRe; deltaIm = zIm; referenceIndex = 0; } } const int remaining = MAX_ITER - iter; const uint8_t colorIndex = (remaining == 0) ? 255 : static_cast<uint8_t>(remaining % 254); const int paletteIndex = (colorIndex == 255) ? 255 : (colorIndex - PALETTE_FRAME + 255) % 255; blueSum += palette[paletteIndex][0]; greenSum += palette[paletteIndex][1]; redSum += palette[paletteIndex][2]; } } const int samples = AA * AA; row[x * 3 + 0] = static_cast<uint8_t>(blueSum / samples); row[x * 3 + 1] = static_cast<uint8_t>(greenSum / samples); row[x * 3 + 2] = static_cast<uint8_t>(redSum / samples); } const int done = ++completedRows; if (done % 50 == 0 || done == HEIGHT) { std::fprintf(stderr, "\rProgress: %d/%d rows (%.1f%%)", done, HEIGHT, 100.0 * done / HEIGHT); } } BMPHeader header; header.width = WIDTH; header.height = HEIGHT; header.sizeImage = static_cast<uint32_t>(image.size()); header.size = header.sizeImage + 54; FILE * file = std::fopen(OUTPUT_FILE, "wb"); if (!file) { std::perror(OUTPUT_FILE); return 1; } std::fwrite(&header, sizeof header, 1, file); std::fwrite(image.data(), 1, image.size(), file); std::fclose(file); std::fprintf(stderr, "\nDone: \"%s\" saved in %.1f s\n", OUTPUT_FILE, omp_get_wtime() - startTime); 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://rosettacode.org/wiki/Mandelbrot_set#Perturbation_Theory Реализация теории возмущений на C++] в международной библиотеке алгоритмов Rosetta Code. * [https://github.com/Divetoxx/Mandelbrot Официальный репозиторий проекта Mandelbrot CLI на GitHub] — исходный код, документация и готовые релизы программы рендеринга. ==== Пример программы построения множества (на языке программирования [[PHP]]) ==== <syntaxhighlight lang="php"> <?php /* Множество Мандельброта. */ /* Время создания */ set_time_limit(120); function re_microtime() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } /* Засекаем */ $time_start = re_microtime(); /* Размер картинки */ $img_w = 900; $img_h = 600; /* Начало и конец чертежа */ $x_min = -2; $x_max = 1; $y_min = -1; $y_max = 1; /* Подсчёт шага */ if($x_min >= 0 && $x_max >= 0){ $step = ($x_min + $x_max)/$img_w; } elseif($x_min < 0 && $x_max >= 0) { $step = ($x_max - $x_min)/$img_w; } else { $step = (-$x_min + $x_max)/$img_w; } $img = imagecreatetruecolor($img_w,$img_h); $c = array(); $yy = 0; for($y = $y_min; $y < $y_max; $y = $y + $step){ $xx = 0; for($x = $x_min; $x < $x_max; $x = $x + $step){ $c['x'] = $x; $c['y'] = $y; $X = $x; $Y = $y; $ix=0; $iy=0; $n=0; while(($ix*$ix + $iy*$iy < 5) and ($n < 64)){ $ix = $X*$X - $Y*$Y + $c['x']; $iy = 2*$X*$Y + $c['y']; $X = $ix; $Y = $iy; $n++; } $col = imagecolorallocate($img, 255-$n*5, 0, 0); imagesetpixel($img, $xx, $yy, $col); $xx++; } $yy++; } $time_end = re_microtime(); header("Content-type: image/png"); /* выводим в заголовках время создания */ header ("X-Exec-Time: ".($time_end - $time_start)); imagepng($img); imagedestroy($img); ?> </syntaxhighlight> ==== Пример программы построения множества (на языке программирования [[C Sharp|C#]]) ==== <syntaxhighlight lang="csharp"> using System; namespace Mnoj { class Program { static void Main(string[] args) { double realCoord, imagCoord; double realTemp, imagTemp, realTemp2, arg; int iterations; for (imagCoord = 1.2; imagCoord >= -1.2; imagCoord -= 0.05) { for (realCoord = -0.6; realCoord <= 1.77; realCoord += 0.03) { iterations = 0; realTemp = realCoord; imagTemp = imagCoord; arg = (realCoord * realCoord) + (imagCoord * imagCoord); while ((arg < 4) && (iterations < 40)) { realTemp2 = (realTemp * realTemp) - (imagTemp * imagTemp) + realCoord; imagTemp = (2 * realTemp * imagTemp) + imagCoord; realTemp = realTemp2; arg = (realTemp * realTemp) + (imagTemp * imagTemp); iterations += 1; } switch (iterations % 4) { case 0: Console.Write("."); break; case 1: Console.Write("o"); break; case 2: Console.Write("0"); break; case 3: Console.Write("@"); break; } } Console.Write("\n"); } Console.ReadKey(); } } } </syntaxhighlight> ==== Пример программы построения множества (на языке программирования [[Паскаль (язык программирования)|паскаль]]) ==== <syntaxhighlight lang="pascal"> uses System.Drawing, System.Windows.Forms, System.Threading, FormsABC; procedure DrawMandelbrot(g: Graphics; w,h: integer; scale: real; dx,dy: integer); const max = 10; begin for var ix:=0 to w-1 do for var iy:=0 to h-1 do begin var x := 0.0; var y := 0.0; var cx := scale * (ix - dx); var cy := scale * (iy - dy); var i := 1; while i<255 do begin var x1 := x*x-y*y+cx; var y1 := 2*x*y+cy; x := x1; y := y1; if (abs(x)>max) and (abs(y)>max) then break; i += 1; end; if i>=255 then g.FillRectangle(Brushes.Red,ix,iy,1,1) else g.FillRectangle(new SolidBrush(Color.FromArgb(255,255-i,255-i)),ix,iy,1,1) end; end; var Scale := new RealField('Масштаб: '); l1 := new FlowBreak; dx := new IntegerField('dx: '); l2 := new FlowBreak; dy := new IntegerField('dy: '); l3 := new FlowBreak(20); b := new Button(' Нарисовать '); p: PaintBox; procedure Draw; begin var g := p.Graphics; DrawMandelbrot(g,p.Width,p.Height,Scale.Value,dx.Value,dy.Value); p.Invalidate; end; procedure My(o: Object); begin Draw; end; procedure Click; begin ThreadPool.QueueUserWorkItem(My); end; begin MainForm.Title := 'Множество Мандельброта'; MainForm.SetSize(700, 600); MainPanel.Dock := Dockstyle.Left; MainPanel.Width := 120; Scale.Value := 0.0035; dx.Value := 430; dy.Value := 280; b.Click += Click; ParentControl := MainForm; p := new PaintBox; p.Dock := DockStyle.Fill; ThreadPool.QueueUserWorkItem(My); end. </syntaxhighlight> ==== Пример программы построения множества (на языке программирования [[C++]] с использованием SFML) ==== <syntaxhighlight lang="c++"> ///Heared.hpp #pragma once #include <SFML\Graphics.hpp> //#include <boost\math\bindings\rr.hpp> typedef long double TYPE; template<typename T> struct Complex { T re; T im; Complex operator += (const Complex & other) { re += other.re; im += other.im; return *this; } Complex operator + (const Complex & other) { Complex c(*this); return c += other; } Complex operator *= (const Complex & other) { Complex c; c.re = re * other.re - im * other.im; c.im = re * other.im + im * other.re; *this = c; return *this; } Complex operator * (const Complex & other) { Complex c(*this); return c *= other; } Complex operator = (const Complex & other) { re = other.re; im = other.im; return *this; } Complex(): re((T)0), im((T)0) { } Complex(const Complex& other) : re(other.re), im(other.im) { } Complex(const T& re, const T& im) : re(re), im(im) { } Complex(const T& re) : re(re), im((T)0) { } T module_sqr()const { return re * re + im * im; } }; //void drawM(sf::Vector2<TYPE> x, sf::Vector2<TYPE> y); ///draw.cpp #include "Header.hpp" void step_clr(sf::Color & clr) { clr.r = clr.r + 5 < 0x100 ? clr.r + 5 : 0xff; clr.g = clr.g + 3 < 0x100 ? clr.g + 5 : 0xff; clr.b = clr.b + 2 < 0x100 ? clr.b + 5 : 0xff; } void drawM(sf::Vector2<TYPE> x, sf::Vector2<TYPE> y) { const TYPE epsilon = 0.005; sf::Vector2i sizewindow((int)((x.y - x.x) / epsilon), (int)((y.y - y.x) / epsilon)); sf::RenderWindow window(sf::VideoMode(sizewindow.x, sizewindow.y), "Mandelbroth"); sf::Image im; const int max_it = 250; const int infinity_sqr = 10000; im.create(sizewindow.x, sizewindow.y); sf::Color clr; int xim = 0, yim = 0; for (TYPE currx = x.x; currx <= x.y; currx += epsilon, ++xim) { yim = 0; while (xim >= sizewindow.x) --xim; for (TYPE curry = y.x; curry <= y.y; curry += epsilon, ++yim) { while (yim >= sizewindow.y) --yim; clr = sf::Color::Black; Complex<TYPE> curr; im.setPixel(xim, yim, sf::Color::Black); for (int i = 0; i < max_it; ++i) { if (curr.module_sqr() >= infinity_sqr) { im.setPixel(xim, yim, clr); break; } curr = curr * curr + Complex<TYPE>(currx, curry); step_clr(clr); } } } sf::Sprite s; sf::Texture t; t.loadFromImage(im); s.setTexture(t); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); } window.clear(); window.draw(s); window.display(); } } ///main.cpp #include "Header.hpp" #include "draw.cpp" #include <iostream> int main() { TYPE x1, x2, y1, y2; //std::cin >> x1 >> x2 >> y1 >> y2; x1 = -2.5; x2 = 2; y1 = -1.5; y2 = 1.5; drawM(sf::Vector2<TYPE>(x1, x2), sf::Vector2<TYPE>(y1, y2)); } </syntaxhighlight> === Добавление цвета === [[Файл:Mandel zoom 11 satellite double spiral.jpg|thumb|Фрагмент границы множества Мандельброта в цветном варианте]] Строго математически, изображения множеств Мандельброта и Жюлиа должны быть чёрно-белыми. Точка либо попадает внутрь множества, либо нет. Несмотря на это, с помощью компьютера мы можем построить и цветные изображения. Самым распространённым способом является раскрашивание точек снаружи множества в цвет, соответствующий количеству итераций, за которое точка уходит в «бесконечность» или, с точки зрения программы, на определённое расстояние от нуля. Порядок определения, попадает ли точка ''z''<sub>0</sub> внутрь множества (традиционно закрашиваемого чёрным цветом) или нет (закрашивается цветом, зависящим от скорости движения к бесконечности) следующий: на каждой итерации для ''z''<sub>''n''</sub>=''x''<sub>''n''</sub>+''y<sub>''n''</sub>·i'' вычисляется значение модуля <math>|z_n| = \sqrt{x_n^2 + y_n^2}</math>, которое затем сравнивается с «границей бесконечности» (обычно берётся значение, равное 2). Здесь важно обратить внимание, что уже на данном этапе можно ввести определённую оптимизацию вычислений, если проверять не <math>\sqrt{x_n^2 + y_n^2} > 2</math>, а <math>x_n^2 + y_n^2 > 4</math>, что значительно снизит время расчётов. Таким образом, если |''z''<sub>''n''</sub>|<sup>2</sup> ≤ 4 при любом числе итераций (на практике — при всех вычисленных итерациях), то цвет точки чёрный, в противном случае он зависит от последнего значения ''n'', при котором |''z''<sub>''n''</sub>|<sup>2</sup> ≤ 4. Значение ''n'', фактически, обозначает скорость движения ''z''<sub>''n''</sub> в бесконечность, и может быть просто индексом в таблице цветов, или использоваться как параметр в более сложном алгоритме. Данный алгоритм определяет, что если точка удаляется больше чем на 2 от начала координат, то она лежит снаружи множества Мандельброта. Для того, чтобы определить, что точка лежит внутри множества есть много способов. Самое простое решение — ограничить количество итераций неким максимумом. Если точка не вышла за указанную границу, можно считать, что она находится внутри множества. Точкам около границы множества нужно больше итераций для ухода в бесконечность. Поэтому такие области прорисовываются заметно дольше. Чем дальше от границ множества, тем выше скорость ухода в бесконечность. Для таких точек требуется меньше итераций. ==== Пример добавления цвета (на PHP) ==== <syntaxhighlight lang="php"> <?php // Default: http://<host>/<dir>/<filename>.php?iter1=64&width=600&height=400&coef=32 function BN($n, $l, $r) {return $n>$l && $n<=$r;} function SQR($a) {return $a*$a;} define("COEF", $_GET["coef"]); $iter1 = $_GET["iter1"]; $width = $_GET["width"]; $height = $_GET["height"]; header("Content-type: image/png"); $img = imagecreatetruecolor($width, $height); $iter2 = 0.01/($width/300); $yy = -1; for ($y = -1; $y < 1; $y = $y + $iter2) { $yy++; $xx=-1; for($x = -2; $x < 1; $x = $x + $iter2) { $xx++; $Cx = $x; $Cy = $y; $X = $x; $Y = $y; $ix = 0; $iy = 0; $n = 0; while ((SQR($ix) + SQR($iy) < 4) and ($n < $iter1)) { $ix = SQR($X) - SQR($Y) + $Cx; $iy = 2*$X*$Y + $Cy; $X = $ix; $Y = $iy; $n++; } if(BN($n,0,7)) $col = imagecolorallocate($img,COEF*$n,0,0); elseif(BN($n,7,14)) $col = imagecolorallocate($img,COEF*$n,COEF*$n,0); elseif(BN($n,14,21))$col = imagecolorallocate($img,COEF*$n,0,COEF*$n); elseif(BN($n,21,28))$col = imagecolorallocate($img,0,COEF*$n,0); elseif(BN($n,28,35))$col = imagecolorallocate($img,COEF*$n,COEF*$n,0); elseif(BN($n,35,42))$col = imagecolorallocate($img,0,COEF*$n,COEF*$n); elseif(BN($n,42,49))$col = imagecolorallocate($img,0,0,COEF*$n); elseif(BN($n,49,56))$col = imagecolorallocate($img,COEF*$n,0,COEF*$n); elseif(BN($n,56,64))$col = imagecolorallocate($img,0,COEF*$n,COEF*$n); imagesetpixel($img, $xx, $yy, $col); } } imagepng($img); imagedestroy($img); ?> </syntaxhighlight> ==== Пример добавления цвета (на C++) ==== <syntaxhighlight lang="c++"> ///draw.cpp #include "Header.hpp" void step_clr(float & red, float & green, float & blue) { red = (int)(red + 5) < 0xff ? red + 5 : 0xff; if((int)red == 0xff) green = (int)(green + 3.5) < 0xff ? green + 3.5 : 0xff; if((int)green == 0xff) blue = (int)(blue + 2.2) < 0xff ? blue + 2.2 : 0xff; } void drawM(sf::Vector2<TYPE> x, sf::Vector2<TYPE> y) { const TYPE epsilon = 0.005; sf::Vector2i sizewindow((int)((x.y - x.x) / epsilon), (int)((y.y - y.x) / epsilon)); sf::RenderWindow window(sf::VideoMode(sizewindow.x, sizewindow.y), "Mandelbroth"); sf::Image im; const int max_it = 250; const int infinity_sqr = 10000; im.create(sizewindow.x, sizewindow.y); sf::Color clr; int xim = 0, yim = 0; for (TYPE currx = x.x; currx <= x.y; currx += epsilon, ++xim) { yim = 0; while (xim >= sizewindow.x) --xim; for (TYPE curry = y.x; curry <= y.y; curry += epsilon, ++yim) { while (yim >= sizewindow.y) --yim; clr = sf::Color::Black; Complex<TYPE> curr; float red = 0, green = 0, blue = 0; im.setPixel(xim, yim, sf::Color::Black); for (int i = 0; i < max_it; ++i) { if (curr.module_sqr() >= infinity_sqr) { clr = sf::Color(red, green, blue); im.setPixel(xim, yim, clr); break; } curr = curr * curr + Complex<TYPE>(currx, curry); step_clr(red, green, blue); } } } sf::Sprite s; sf::Texture t; t.loadFromImage(im); s.setTexture(t); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); } window.clear(); window.draw(s); window.display(); } } </syntaxhighlight> 46ir0nf5pz3piowxpn9ae13be94tr56 269739 269738 2026-08-04T18:07:42Z Aokoroko 47596 /* Примеры программ */ 269739 wikitext text/x-wiki {{Название учебника | Категория = Программирование, Математика | Тип = Одностраничный | Готовность = 25% }} [[Файл:Mandelset hires.png|thumb|300px|Множество Мандельброта]]{{Wikipedia}} '''Мно́жество Мандельбро́та''' — это множество таких точек ''c'' на комплексной плоскости, для которых рекуррентное соотношение <math>z_{n+1} = {z_n}^2 + c</math> при <math>z_0 = 0</math> задаёт ограниченную последовательность. То есть, это множество таких ''c'', для которых существует такое действительное ''R'', что неравенство |''z''<sub>''n''</sub>|<''R'' выполняется при всех натуральных ''n''. == Построение множества == Несложно доказать, что как только модуль ''z''<sub>''n''</sub> окажется больше 2 (или, в терминах действительной и мнимой частей, ''x''<sub>''n''</sub><sup>2</sup>+''y''<sub>''n''</sub><sup>2</sup>>4), последовательность станет стремиться к бесконечности. В случае |''c''|≤2 это можно доказать с помощью метода математической индукции. При |''c''|>2 точка ''c'' заведомо не принадлежит множеству Мандельброта, что также можно вывести методом индукции, используя равенство ''z''<sub>0</sub>=0. (Хотя в этом случае может существовать другое ''z''<sub>0</sub>, для которого соответствующая последовательность ограничена по модулю, но для некоторого ''n'' выполняется неравенство |''z''<sub>''n''</sub>|>2.) Сравнение |''z''<sub>''n''</sub>| с этим числом (в англоязычной литературе его называют «bail-out») позволяет выделять точки, не попадающие внутрь множества. Для точек, лежащих внутри множества, последовательность не будет иметь тенденции к бесконечности и никогда не достигнет этого числа, поэтому после определённого числа итераций расчёт необходимо принудительно завершить. Максимальное число итераций, после которых число считается попавшим внутрь множества, задается в программе. Изображение, полученное таким способом, является лишь приближением к реальному множеству Мандельброта. Более качественные результаты можно получать, увеличивая максимальное количество итераций, однако при этом пропорционально вырастает и время расчётов. === Примеры программ === ==== Консольный рендерер Мандельброта с методом возмущений и предела 10<sup>−308</sup> (на языке программирования [[C++]]) ==== Ключевые особенности * Расчёт опорной траектории на 1000 бит всего один раз. * Реактивный расчёт миллиарда пикселей на аппаратном double. * Расчет можно выполнить существенно быстрее, если использовать билинейную аппроксимацию. * При использовании чисел с плавающей запятой двойной точности (порядка 10⁻¹⁵) теория возмущений позволяет приблизиться к уровню 10⁻³⁰⁸ - не дальше. * Революционный алгоритм Reference Reset to Zero. * Настоящий SSAA 8x8 для идеально сглаженного изображения без алиасинга. * Параллелизм OpenMP для высокоскоростного многопоточного рендеринга. <syntaxhighlight lang="c++"> #include <atomic> #include <cmath> #include <cstdint> #include <cstdio> #include <vector> #include <algorithm> #include <mpfr.h> #include <omp.h> using std::vector; using std::min; const char * CENTER_RE = "-1.99999543561201124623198345433951143502785679245726844745821388800402678499411681518036306219179273434395557574279985918047221291197081186140687781560831995"; const char * CENTER_IM = "-0.00000000000000000000000026198152173811047783694060060607013913873144250985383083459221663448338433592617272786772587281530484110756597337683912309313885172"; const char * VIEW_SIZE = "1.15e-119"; const int WIDTH = 2160; const int HEIGHT = 2160; const int AA = 8; const int MAX_ITER = 50000; const double ESCAPE_RADIUS_SQUARED = 50000.0; const int PALETTE_FRAME = 200; const char * OUTPUT_FILE = "Mandelbrot Set Image 112.bmp"; const mpfr_prec_t PRECISION_BITS = 1000; struct Complex { double re; double im; }; #pragma pack(push, 1) struct BMPHeader { uint16_t type{0x4D42}; uint32_t size{0}; uint32_t reserved{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 xPixelsPerMeter{2834}; int32_t yPixelsPerMeter{2834}; uint32_t colorsUsed{0}; uint32_t colorsImportant{0}; }; #pragma pack(pop) int main() { const double startTime = omp_get_wtime(); const long rawWidth = static_cast<long>(WIDTH) * AA; const long rawHeight = static_cast<long>(HEIGHT) * AA; mpfr_t centerRe, centerIm, zReMp, zImMp, tmp1, tmp2, viewSizeMp; mpfr_inits2(PRECISION_BITS, centerRe, centerIm, zReMp, zImMp, tmp1, tmp2, viewSizeMp, static_cast<mpfr_ptr>(nullptr)); mpfr_set_str(centerRe, CENTER_RE, 10, MPFR_RNDN); mpfr_set_str(centerIm, CENTER_IM, 10, MPFR_RNDN); mpfr_set_str(viewSizeMp, VIEW_SIZE, 10, MPFR_RNDN); const double sampleStep = mpfr_get_d(viewSizeMp, MPFR_RNDN) / rawWidth; vector<Complex> referenceOrbit; referenceOrbit.reserve(MAX_ITER + 200); mpfr_set_ui(zReMp, 0, MPFR_RNDN); mpfr_set_ui(zImMp, 0, MPFR_RNDN); for (int iter = 0; iter <= MAX_ITER + 150; ++iter) { Complex z{mpfr_get_d(zReMp, MPFR_RNDN), mpfr_get_d(zImMp, MPFR_RNDN)}; referenceOrbit.push_back(z); if (z.re * z.re + z.im * z.im > ESCAPE_RADIUS_SQUARED && iter > MAX_ITER) { break; } mpfr_mul(tmp1, zReMp, zImMp, MPFR_RNDN); mpfr_sqr(tmp2, zReMp, MPFR_RNDN); mpfr_sqr(zReMp, zImMp, MPFR_RNDN); mpfr_sub(zReMp, tmp2, zReMp, MPFR_RNDN); mpfr_add(zReMp, zReMp, centerRe, MPFR_RNDN); mpfr_mul_2ui(tmp1, tmp1, 1, MPFR_RNDN); mpfr_add(zImMp, tmp1, centerIm, MPFR_RNDN); } const int referenceLength = static_cast<int>(referenceOrbit.size()); mpfr_clears(centerRe, centerIm, zReMp, zImMp, tmp1, tmp2, viewSizeMp, static_cast<mpfr_ptr>(nullptr)); std::fprintf(stderr, "Reference orbit: %d points\n", referenceLength); std::fprintf(stderr, "Precomputing skip100 matrices...\n"); vector<Complex> coeff_A(referenceLength, {1.0, 0.0}); vector<Complex> coeff_B(referenceLength, {0.0, 0.0}); vector<double> rad_R(referenceLength, 2.0); #pragma omp parallel for for (int i = 0; i < MAX_ITER; ++i) { double min_r = 2.0; for (int k = 0; k < 100; ++k) { if (i + k >= referenceLength) break; double r_re = referenceOrbit[i + k].re; double r_im = referenceOrbit[i + k].im; double abs_s = std::sqrt(r_re * r_re + r_im * r_im); double aS = (abs_s < 2.0) ? abs_s : 0.0; min_r = min(min_r, aS); double next_A_re = 2.0 * (r_re * coeff_A[i].re - r_im * coeff_A[i].im); double next_A_im = 2.0 * (r_re * coeff_A[i].im + r_im * coeff_A[i].re); double next_B_re = 2.0 * (r_re * coeff_B[i].re - r_im * coeff_B[i].im) + 1.0; double next_B_im = 2.0 * (r_re * coeff_B[i].im + r_im * coeff_B[i].re); coeff_A[i].re = next_A_re; coeff_A[i].im = next_A_im; coeff_B[i].re = next_B_re; coeff_B[i].im = next_B_im; } rad_R[i] = min_r; } const double PI = 3.14159265358979323846; uint8_t palette[256][3]; for (int i = 0; i < 255; ++i) { palette[i][0] = static_cast<uint8_t>(std::lround(127.0 + 127.0 * std::cos(2.0 * PI * i / 255.0))); palette[i][1] = static_cast<uint8_t>(std::lround(127.0 + 127.0 * std::sin(2.0 * PI * i / 255.0))); palette[i][2] = palette[i][1]; } palette[255][0] = 255; palette[255][1] = 255; palette[255][2] = 255; const int rowBytes = (WIDTH * 3 + 3) & ~3; vector<uint8_t> image(static_cast<size_t>(rowBytes) * HEIGHT, 0); std::atomic<int> completedRows{0}; const Complex * reference = referenceOrbit.data(); #pragma omp parallel for schedule(dynamic) for (int y = 0; y < HEIGHT; ++y) { uint8_t * row = image.data() + static_cast<size_t>(y) * rowBytes; for (int x = 0; x < WIDTH; ++x) { unsigned blueSum = 0; unsigned greenSum = 0; unsigned redSum = 0; for (int sampleY = 0; sampleY < AA; ++sampleY) { const double deltaCIm = (static_cast<long>(y) * AA + sampleY - rawHeight / 2) * sampleStep; for (int sampleX = 0; sampleX < AA; ++sampleX) { const double deltaCRe = (static_cast<long>(x) * AA + sampleX - rawWidth / 2) * sampleStep; double deltaRe = 0.0; double deltaIm = 0.0; double zRe = 0.0; double zIm = 0.0; int referenceIndex = 0; int iter = 0; while (iter < MAX_ITER) { if (zRe * zRe + zIm * zIm >= ESCAPE_RADIUS_SQUARED) { break; } double eps_abs2 = deltaRe * deltaRe + deltaIm * deltaIm; double limit_r2 = 1e-60 * rad_R[referenceIndex] * rad_R[referenceIndex]; if (eps_abs2 < limit_r2 && (referenceIndex + 100 < referenceLength - 1) && (iter + 100 < MAX_ITER)) { double backup_deltaRe = deltaRe; double backup_deltaIm = deltaIm; int backup_refIdx = referenceIndex; int backup_iter = iter; double next_eps_re = (coeff_A[referenceIndex].re * deltaRe - coeff_A[referenceIndex].im * deltaIm) + (coeff_B[referenceIndex].re * deltaCRe - coeff_B[referenceIndex].im * deltaCIm); double next_eps_im = (coeff_A[referenceIndex].re * deltaIm + coeff_A[referenceIndex].im * deltaRe) + (coeff_B[referenceIndex].re * deltaCIm + coeff_B[referenceIndex].im * deltaCRe); deltaRe = next_eps_re; deltaIm = next_eps_im; referenceIndex += 100; iter += 100; zRe = reference[referenceIndex].re + deltaRe; zIm = reference[referenceIndex].im + deltaIm; if (zRe * zRe + zIm * zIm >= ESCAPE_RADIUS_SQUARED) { deltaRe = backup_deltaRe; deltaIm = backup_deltaIm; referenceIndex = backup_refIdx; iter = backup_iter; } else { continue; } } const double a = 2.0 * reference[referenceIndex].re + deltaRe; const double b = 2.0 * reference[referenceIndex].im + deltaIm; const double nextDeltaRe = a * deltaRe - b * deltaIm + deltaCRe; deltaIm = a * deltaIm + b * deltaRe + deltaCIm; deltaRe = nextDeltaRe; ++referenceIndex; ++iter; zRe = reference[referenceIndex].re + deltaRe; zIm = reference[referenceIndex].im + deltaIm; if (zRe * zRe + zIm * zIm < deltaRe * deltaRe + deltaIm * deltaIm || referenceIndex == referenceLength - 1) { deltaRe = zRe; deltaIm = zIm; referenceIndex = 0; } } const int remaining = MAX_ITER - iter; const uint8_t colorIndex = (remaining == 0) ? 255 : static_cast<uint8_t>(remaining % 254); const int paletteIndex = (colorIndex == 255) ? 255 : (colorIndex - PALETTE_FRAME + 255) % 255; blueSum += palette[paletteIndex][0]; greenSum += palette[paletteIndex][1]; redSum += palette[paletteIndex][2]; } } const int samples = AA * AA; row[x * 3 + 0] = static_cast<uint8_t>(blueSum / samples); row[x * 3 + 1] = static_cast<uint8_t>(greenSum / samples); row[x * 3 + 2] = static_cast<uint8_t>(redSum / samples); } const int done = ++completedRows; if (done % 50 == 0 || done == HEIGHT) { std::fprintf(stderr, "\rProgress: %d/%d rows (%.1f%%)", done, HEIGHT, 100.0 * done / HEIGHT); } } BMPHeader header; header.width = WIDTH; header.height = HEIGHT; header.sizeImage = static_cast<uint32_t>(image.size()); header.size = header.sizeImage + 54; FILE * file = std::fopen(OUTPUT_FILE, "wb"); if (!file) { std::perror(OUTPUT_FILE); return 1; } std::fwrite(&header, sizeof header, 1, file); std::fwrite(image.data(), 1, image.size(), file); std::fclose(file); std::fprintf(stderr, "\nDone: \"%s\" saved in %.1f s\n", OUTPUT_FILE, omp_get_wtime() - startTime); 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://rosettacode.org/wiki/Mandelbrot_set#Perturbation_Theory Реализация теории возмущений на C++] в международной библиотеке алгоритмов Rosetta Code. * [https://github.com/Divetoxx/Mandelbrot Официальный репозиторий проекта Mandelbrot CLI на GitHub] — исходный код, документация и готовые релизы программы рендеринга. ==== Пример программы построения множества (на языке программирования [[PHP]]) ==== <syntaxhighlight lang="php"> <?php /* Множество Мандельброта. */ /* Время создания */ set_time_limit(120); function re_microtime() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } /* Засекаем */ $time_start = re_microtime(); /* Размер картинки */ $img_w = 900; $img_h = 600; /* Начало и конец чертежа */ $x_min = -2; $x_max = 1; $y_min = -1; $y_max = 1; /* Подсчёт шага */ if($x_min >= 0 && $x_max >= 0){ $step = ($x_min + $x_max)/$img_w; } elseif($x_min < 0 && $x_max >= 0) { $step = ($x_max - $x_min)/$img_w; } else { $step = (-$x_min + $x_max)/$img_w; } $img = imagecreatetruecolor($img_w,$img_h); $c = array(); $yy = 0; for($y = $y_min; $y < $y_max; $y = $y + $step){ $xx = 0; for($x = $x_min; $x < $x_max; $x = $x + $step){ $c['x'] = $x; $c['y'] = $y; $X = $x; $Y = $y; $ix=0; $iy=0; $n=0; while(($ix*$ix + $iy*$iy < 5) and ($n < 64)){ $ix = $X*$X - $Y*$Y + $c['x']; $iy = 2*$X*$Y + $c['y']; $X = $ix; $Y = $iy; $n++; } $col = imagecolorallocate($img, 255-$n*5, 0, 0); imagesetpixel($img, $xx, $yy, $col); $xx++; } $yy++; } $time_end = re_microtime(); header("Content-type: image/png"); /* выводим в заголовках время создания */ header ("X-Exec-Time: ".($time_end - $time_start)); imagepng($img); imagedestroy($img); ?> </syntaxhighlight> ==== Пример программы построения множества (на языке программирования [[C Sharp|C#]]) ==== <syntaxhighlight lang="csharp"> using System; namespace Mnoj { class Program { static void Main(string[] args) { double realCoord, imagCoord; double realTemp, imagTemp, realTemp2, arg; int iterations; for (imagCoord = 1.2; imagCoord >= -1.2; imagCoord -= 0.05) { for (realCoord = -0.6; realCoord <= 1.77; realCoord += 0.03) { iterations = 0; realTemp = realCoord; imagTemp = imagCoord; arg = (realCoord * realCoord) + (imagCoord * imagCoord); while ((arg < 4) && (iterations < 40)) { realTemp2 = (realTemp * realTemp) - (imagTemp * imagTemp) + realCoord; imagTemp = (2 * realTemp * imagTemp) + imagCoord; realTemp = realTemp2; arg = (realTemp * realTemp) + (imagTemp * imagTemp); iterations += 1; } switch (iterations % 4) { case 0: Console.Write("."); break; case 1: Console.Write("o"); break; case 2: Console.Write("0"); break; case 3: Console.Write("@"); break; } } Console.Write("\n"); } Console.ReadKey(); } } } </syntaxhighlight> ==== Пример программы построения множества (на языке программирования [[Паскаль (язык программирования)|паскаль]]) ==== <syntaxhighlight lang="pascal"> uses System.Drawing, System.Windows.Forms, System.Threading, FormsABC; procedure DrawMandelbrot(g: Graphics; w,h: integer; scale: real; dx,dy: integer); const max = 10; begin for var ix:=0 to w-1 do for var iy:=0 to h-1 do begin var x := 0.0; var y := 0.0; var cx := scale * (ix - dx); var cy := scale * (iy - dy); var i := 1; while i<255 do begin var x1 := x*x-y*y+cx; var y1 := 2*x*y+cy; x := x1; y := y1; if (abs(x)>max) and (abs(y)>max) then break; i += 1; end; if i>=255 then g.FillRectangle(Brushes.Red,ix,iy,1,1) else g.FillRectangle(new SolidBrush(Color.FromArgb(255,255-i,255-i)),ix,iy,1,1) end; end; var Scale := new RealField('Масштаб: '); l1 := new FlowBreak; dx := new IntegerField('dx: '); l2 := new FlowBreak; dy := new IntegerField('dy: '); l3 := new FlowBreak(20); b := new Button(' Нарисовать '); p: PaintBox; procedure Draw; begin var g := p.Graphics; DrawMandelbrot(g,p.Width,p.Height,Scale.Value,dx.Value,dy.Value); p.Invalidate; end; procedure My(o: Object); begin Draw; end; procedure Click; begin ThreadPool.QueueUserWorkItem(My); end; begin MainForm.Title := 'Множество Мандельброта'; MainForm.SetSize(700, 600); MainPanel.Dock := Dockstyle.Left; MainPanel.Width := 120; Scale.Value := 0.0035; dx.Value := 430; dy.Value := 280; b.Click += Click; ParentControl := MainForm; p := new PaintBox; p.Dock := DockStyle.Fill; ThreadPool.QueueUserWorkItem(My); end. </syntaxhighlight> ==== Пример программы построения множества (на языке программирования [[C++]] с использованием SFML) ==== <syntaxhighlight lang="c++"> ///Heared.hpp #pragma once #include <SFML\Graphics.hpp> //#include <boost\math\bindings\rr.hpp> typedef long double TYPE; template<typename T> struct Complex { T re; T im; Complex operator += (const Complex & other) { re += other.re; im += other.im; return *this; } Complex operator + (const Complex & other) { Complex c(*this); return c += other; } Complex operator *= (const Complex & other) { Complex c; c.re = re * other.re - im * other.im; c.im = re * other.im + im * other.re; *this = c; return *this; } Complex operator * (const Complex & other) { Complex c(*this); return c *= other; } Complex operator = (const Complex & other) { re = other.re; im = other.im; return *this; } Complex(): re((T)0), im((T)0) { } Complex(const Complex& other) : re(other.re), im(other.im) { } Complex(const T& re, const T& im) : re(re), im(im) { } Complex(const T& re) : re(re), im((T)0) { } T module_sqr()const { return re * re + im * im; } }; //void drawM(sf::Vector2<TYPE> x, sf::Vector2<TYPE> y); ///draw.cpp #include "Header.hpp" void step_clr(sf::Color & clr) { clr.r = clr.r + 5 < 0x100 ? clr.r + 5 : 0xff; clr.g = clr.g + 3 < 0x100 ? clr.g + 5 : 0xff; clr.b = clr.b + 2 < 0x100 ? clr.b + 5 : 0xff; } void drawM(sf::Vector2<TYPE> x, sf::Vector2<TYPE> y) { const TYPE epsilon = 0.005; sf::Vector2i sizewindow((int)((x.y - x.x) / epsilon), (int)((y.y - y.x) / epsilon)); sf::RenderWindow window(sf::VideoMode(sizewindow.x, sizewindow.y), "Mandelbroth"); sf::Image im; const int max_it = 250; const int infinity_sqr = 10000; im.create(sizewindow.x, sizewindow.y); sf::Color clr; int xim = 0, yim = 0; for (TYPE currx = x.x; currx <= x.y; currx += epsilon, ++xim) { yim = 0; while (xim >= sizewindow.x) --xim; for (TYPE curry = y.x; curry <= y.y; curry += epsilon, ++yim) { while (yim >= sizewindow.y) --yim; clr = sf::Color::Black; Complex<TYPE> curr; im.setPixel(xim, yim, sf::Color::Black); for (int i = 0; i < max_it; ++i) { if (curr.module_sqr() >= infinity_sqr) { im.setPixel(xim, yim, clr); break; } curr = curr * curr + Complex<TYPE>(currx, curry); step_clr(clr); } } } sf::Sprite s; sf::Texture t; t.loadFromImage(im); s.setTexture(t); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); } window.clear(); window.draw(s); window.display(); } } ///main.cpp #include "Header.hpp" #include "draw.cpp" #include <iostream> int main() { TYPE x1, x2, y1, y2; //std::cin >> x1 >> x2 >> y1 >> y2; x1 = -2.5; x2 = 2; y1 = -1.5; y2 = 1.5; drawM(sf::Vector2<TYPE>(x1, x2), sf::Vector2<TYPE>(y1, y2)); } </syntaxhighlight> === Добавление цвета === [[Файл:Mandel zoom 11 satellite double spiral.jpg|thumb|Фрагмент границы множества Мандельброта в цветном варианте]] Строго математически, изображения множеств Мандельброта и Жюлиа должны быть чёрно-белыми. Точка либо попадает внутрь множества, либо нет. Несмотря на это, с помощью компьютера мы можем построить и цветные изображения. Самым распространённым способом является раскрашивание точек снаружи множества в цвет, соответствующий количеству итераций, за которое точка уходит в «бесконечность» или, с точки зрения программы, на определённое расстояние от нуля. Порядок определения, попадает ли точка ''z''<sub>0</sub> внутрь множества (традиционно закрашиваемого чёрным цветом) или нет (закрашивается цветом, зависящим от скорости движения к бесконечности) следующий: на каждой итерации для ''z''<sub>''n''</sub>=''x''<sub>''n''</sub>+''y<sub>''n''</sub>·i'' вычисляется значение модуля <math>|z_n| = \sqrt{x_n^2 + y_n^2}</math>, которое затем сравнивается с «границей бесконечности» (обычно берётся значение, равное 2). Здесь важно обратить внимание, что уже на данном этапе можно ввести определённую оптимизацию вычислений, если проверять не <math>\sqrt{x_n^2 + y_n^2} > 2</math>, а <math>x_n^2 + y_n^2 > 4</math>, что значительно снизит время расчётов. Таким образом, если |''z''<sub>''n''</sub>|<sup>2</sup> ≤ 4 при любом числе итераций (на практике — при всех вычисленных итерациях), то цвет точки чёрный, в противном случае он зависит от последнего значения ''n'', при котором |''z''<sub>''n''</sub>|<sup>2</sup> ≤ 4. Значение ''n'', фактически, обозначает скорость движения ''z''<sub>''n''</sub> в бесконечность, и может быть просто индексом в таблице цветов, или использоваться как параметр в более сложном алгоритме. Данный алгоритм определяет, что если точка удаляется больше чем на 2 от начала координат, то она лежит снаружи множества Мандельброта. Для того, чтобы определить, что точка лежит внутри множества есть много способов. Самое простое решение — ограничить количество итераций неким максимумом. Если точка не вышла за указанную границу, можно считать, что она находится внутри множества. Точкам около границы множества нужно больше итераций для ухода в бесконечность. Поэтому такие области прорисовываются заметно дольше. Чем дальше от границ множества, тем выше скорость ухода в бесконечность. Для таких точек требуется меньше итераций. ==== Пример добавления цвета (на PHP) ==== <syntaxhighlight lang="php"> <?php // Default: http://<host>/<dir>/<filename>.php?iter1=64&width=600&height=400&coef=32 function BN($n, $l, $r) {return $n>$l && $n<=$r;} function SQR($a) {return $a*$a;} define("COEF", $_GET["coef"]); $iter1 = $_GET["iter1"]; $width = $_GET["width"]; $height = $_GET["height"]; header("Content-type: image/png"); $img = imagecreatetruecolor($width, $height); $iter2 = 0.01/($width/300); $yy = -1; for ($y = -1; $y < 1; $y = $y + $iter2) { $yy++; $xx=-1; for($x = -2; $x < 1; $x = $x + $iter2) { $xx++; $Cx = $x; $Cy = $y; $X = $x; $Y = $y; $ix = 0; $iy = 0; $n = 0; while ((SQR($ix) + SQR($iy) < 4) and ($n < $iter1)) { $ix = SQR($X) - SQR($Y) + $Cx; $iy = 2*$X*$Y + $Cy; $X = $ix; $Y = $iy; $n++; } if(BN($n,0,7)) $col = imagecolorallocate($img,COEF*$n,0,0); elseif(BN($n,7,14)) $col = imagecolorallocate($img,COEF*$n,COEF*$n,0); elseif(BN($n,14,21))$col = imagecolorallocate($img,COEF*$n,0,COEF*$n); elseif(BN($n,21,28))$col = imagecolorallocate($img,0,COEF*$n,0); elseif(BN($n,28,35))$col = imagecolorallocate($img,COEF*$n,COEF*$n,0); elseif(BN($n,35,42))$col = imagecolorallocate($img,0,COEF*$n,COEF*$n); elseif(BN($n,42,49))$col = imagecolorallocate($img,0,0,COEF*$n); elseif(BN($n,49,56))$col = imagecolorallocate($img,COEF*$n,0,COEF*$n); elseif(BN($n,56,64))$col = imagecolorallocate($img,0,COEF*$n,COEF*$n); imagesetpixel($img, $xx, $yy, $col); } } imagepng($img); imagedestroy($img); ?> </syntaxhighlight> ==== Пример добавления цвета (на C++) ==== <syntaxhighlight lang="c++"> ///draw.cpp #include "Header.hpp" void step_clr(float & red, float & green, float & blue) { red = (int)(red + 5) < 0xff ? red + 5 : 0xff; if((int)red == 0xff) green = (int)(green + 3.5) < 0xff ? green + 3.5 : 0xff; if((int)green == 0xff) blue = (int)(blue + 2.2) < 0xff ? blue + 2.2 : 0xff; } void drawM(sf::Vector2<TYPE> x, sf::Vector2<TYPE> y) { const TYPE epsilon = 0.005; sf::Vector2i sizewindow((int)((x.y - x.x) / epsilon), (int)((y.y - y.x) / epsilon)); sf::RenderWindow window(sf::VideoMode(sizewindow.x, sizewindow.y), "Mandelbroth"); sf::Image im; const int max_it = 250; const int infinity_sqr = 10000; im.create(sizewindow.x, sizewindow.y); sf::Color clr; int xim = 0, yim = 0; for (TYPE currx = x.x; currx <= x.y; currx += epsilon, ++xim) { yim = 0; while (xim >= sizewindow.x) --xim; for (TYPE curry = y.x; curry <= y.y; curry += epsilon, ++yim) { while (yim >= sizewindow.y) --yim; clr = sf::Color::Black; Complex<TYPE> curr; float red = 0, green = 0, blue = 0; im.setPixel(xim, yim, sf::Color::Black); for (int i = 0; i < max_it; ++i) { if (curr.module_sqr() >= infinity_sqr) { clr = sf::Color(red, green, blue); im.setPixel(xim, yim, clr); break; } curr = curr * curr + Complex<TYPE>(currx, curry); step_clr(red, green, blue); } } } sf::Sprite s; sf::Texture t; t.loadFromImage(im); s.setTexture(t); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); } window.clear(); window.draw(s); window.display(); } } </syntaxhighlight> rsh0euln2p26d2fb16135tmuxhtvnry АОН/Авиационная безопасность 0 28952 269736 269085 2026-08-04T16:57:06Z Leksey 3027 /* См. также */ 269736 wikitext text/x-wiki {{АОН страница}}{{Википедия|Авиационная безопасность}} Авиационная безопасность (англ. Aviation security или avsec) - деятельность по предотвращению так называемых "актов незаконного вмешательства в деятельность гражданской авиации". Из-за использования слово "безопасность" возникает путаница между авиационной безопасностью и [[АОН/Безопасность полетов|безопасностью полетов]]. Также в России имеется такое понятие как [[АОН/Транспортная безопасность|транспортная безопасность]] (ТБ). ==Что это такое== Авиационная безопасность это комплекс мер, предназначенных для защиты гражданской авиации от актов незаконного вмешательства. Таковыми являются прежде всего террористические угрозы. Весь досмотровый комплекс (рамки, интроскопы и пр.) в аэропортах и персонал (САБ) охраняющий сам аэропорт это и есть авиационная безопасность. == Отношение к АОН == К АОН данная тема имела долгие годы опосредованное отношение так как воздушные суда АОН в меньшей степени интересны для незаконного вмешательства, но ситуация в нормативном регулировании меняется. Но регулярно возникают законотворческие инициативы обязать пилотов АОН (а также аэродромы АОН) соблюдать сложные и неприятные правила из большой авиации или принудить их к выполнению крайне дорогих подходов к транспортной безопасности государственных объектов. Т.е. не дифференцируя риски, предложить всем летающим одинаковые правила. Например, установить интроскопы на входе на посадочную площадку или установить капитальное ограждение вокруг всей посадочной площадке. Т.е приравнять требования к вокзалу и к частному аэродрому. Если таковые инициативы реализуются в какой-то момент, то соблюдаться они не будут как нереальные (из-за большой финансовой нагрузки), но будет повод преследования как пилотов, так и владельцев аэродромов. ==Путаница== Очень часто возникает путаница между авиационная безопасностью и [[АОН/Безопасность полетов]]. ==См. также== * [[АОН/Транспортная безопасность|Транспортная безопасность]] *[[АОН/Ространснадзор|Ространснадзор]] [[Категория:АОН]] {{АОН}} ntzj2j2fmmqdftrscacay6wedqqzk25 269737 269736 2026-08-04T17:36:07Z Leksey 3027 Оформление 269737 wikitext text/x-wiki {{АОН страница}}{{Википедия|Авиационная безопасность}} Авиационная безопасность (англ. Aviation security или сокращенно "avsec") - деятельность по предотвращению так называемых "актов незаконного вмешательства в деятельность гражданской авиации". Также в России имеется такое понятие как [[АОН/Транспортная безопасность|транспортная безопасность]] (ТБ), в которую и входит авиационная безопасность, похоже. ==Что это такое== Авиационная безопасность это комплекс мер, предназначенных для защиты гражданской авиации от актов незаконного вмешательства. Таковыми являются прежде всего террористические угрозы. Весь досмотровый комплекс (рамки, интроскопы и пр.) в аэропортах и персонал (САБ) охраняющий сам аэропорт это и есть авиационная безопасность. Вне аэропортов авиационная безопасность не имеет смысла и отсутствует. == Требования для эксплуатанта == Для эксплуатантов авиаработ есть требование по обеспечению авиационной безопасности. == Отношение к АОН == К АОН данная тема имела долгие годы опосредованное отношение так как воздушные суда АОН в меньшей степени интересны для незаконного вмешательства, но ситуация в нормативном регулировании меняется. Но регулярно возникают законотворческие инициативы обязать пилотов АОН (а также аэродромы АОН) соблюдать сложные и неприятные правила из большой авиации или принудить их к выполнению крайне дорогих подходов к транспортной безопасности государственных объектов. Т.е. не дифференцируя риски, предложить всем летающим одинаковые правила. Например, установить интроскопы на входе на посадочную площадку или установить капитальное ограждение вокруг всей посадочной площадке. Т.е приравнять требования к вокзалу и к частному аэродрому. Если таковые инициативы реализуются в какой-то момент, то соблюдаться они не будут как нереальные (из-за большой финансовой нагрузки), но будет повод преследования как пилотов, так и владельцев аэродромов. ==Смешение с безопасностью полетов== Из-за использования слово "безопасность" в названии обоих понятий возникает путаница между "авиационной безопасностью" и [[АОН/Безопасность полетов|безопасностью полетов]]. ==См. также== * [[АОН/Транспортная безопасность|Транспортная безопасность]] *[[АОН/Ространснадзор|Ространснадзор]] [[Категория:АОН]] {{АОН}} 4exmmck5db5qzwavpy4vi85er9ku6s2 269740 269737 2026-08-04T18:28:13Z Leksey 3027 +Предупреждение 269740 wikitext text/x-wiki {{АОН страница}}{{Википедия|Авиационная безопасность}}{{Внимание|Глава "Авиационная безопасность" в [[АОН/ВК|Воздушном кодексе]] утратила силу с 1 марта 2025 г.}} Авиационная безопасность (англ. Aviation security или сокращенно "avsec") - деятельность по предотвращению так называемых "актов незаконного вмешательства в деятельность гражданской авиации". Также в России имеется такое понятие как [[АОН/Транспортная безопасность|транспортная безопасность]] (ТБ), в которую и входит авиационная безопасность, похоже. ==Что это такое== Авиационная безопасность это комплекс мер, предназначенных для защиты гражданской авиации от актов незаконного вмешательства. Таковыми являются прежде всего террористические угрозы. Весь досмотровый комплекс (рамки, интроскопы и пр.) в аэропортах и персонал (САБ) охраняющий сам аэропорт это и есть авиационная безопасность. Вне аэропортов авиационная безопасность не имеет смысла и отсутствует. == Требования для эксплуатанта == Для эксплуатантов авиаработ есть требование по обеспечению авиационной безопасности. == Отношение к АОН == К АОН данная тема имела долгие годы опосредованное отношение так как воздушные суда АОН в меньшей степени интересны для незаконного вмешательства, но ситуация в нормативном регулировании меняется. Но регулярно возникают законотворческие инициативы обязать пилотов АОН (а также аэродромы АОН) соблюдать сложные и неприятные правила из большой авиации или принудить их к выполнению крайне дорогих подходов к транспортной безопасности государственных объектов. Т.е. не дифференцируя риски, предложить всем летающим одинаковые правила. Например, установить интроскопы на входе на посадочную площадку или установить капитальное ограждение вокруг всей посадочной площадке. Т.е приравнять требования к вокзалу и к частному аэродрому. Если таковые инициативы реализуются в какой-то момент, то соблюдаться они не будут как нереальные (из-за большой финансовой нагрузки), но будет повод преследования как пилотов, так и владельцев аэродромов. ==Смешение с безопасностью полетов== Из-за использования слово "безопасность" в названии обоих понятий возникает путаница между "авиационной безопасностью" и [[АОН/Безопасность полетов|безопасностью полетов]]. ==См. также== * [[АОН/Транспортная безопасность|Транспортная безопасность]] *[[АОН/Ространснадзор|Ространснадзор]] [[Категория:АОН]] {{АОН}} cmvro2976hf8y2uhsfh0y59igtr23e4 269743 269740 2026-08-04T20:43:42Z Leksey 3027 Пояснение 269743 wikitext text/x-wiki {{АОН страница}}{{Википедия|Авиационная безопасность}}{{Внимание|Глава "Авиационная безопасность" в [[АОН/ВК|Воздушном кодексе]] утратила силу с 1 марта 2025 г. И можно сказать, что Авиационная безопасность теперь именуется в нормативных документах как [[АОН/Транспортная безопасность|Транспортная безопасность]].}} Авиационная безопасность (англ. Aviation security или сокращенно "avsec") - деятельность по предотвращению так называемых "актов незаконного вмешательства в деятельность гражданской авиации". С 2025 года АБ обозначается термином [[АОН/Транспортная безопасность|транспортная безопасность]] (ТБ) в нормативных документах российских. А понятие "Авиационная безопасность" продолжается применяться в документах ИКАО. ==Определение== Авиационная безопасность это комплекс мер, предназначенных для защиты гражданской авиации от актов незаконного вмешательства. Таковыми являются прежде всего террористические угрозы. Весь досмотровый комплекс (рамки, интроскопы и пр.) в аэропортах и персонал (САБ) охраняющий сам аэропорт это и есть авиационная безопасность. Вне аэропортов авиационная безопасность не имеет смысла и отсутствует. == Требования для эксплуатанта == Для эксплуатантов авиаработ есть требование по обеспечению авиационной безопасности. == Отношение к АОН == К АОН данная тема имела долгие годы опосредованное отношение так как воздушные суда АОН в меньшей степени интересны для незаконного вмешательства, но ситуация в нормативном регулировании меняется. Но регулярно возникают законотворческие инициативы обязать пилотов АОН (а также аэродромы АОН) соблюдать сложные и неприятные правила из большой авиации или принудить их к выполнению крайне дорогих подходов к транспортной безопасности государственных объектов. Т.е. не дифференцируя риски, предложить всем летающим одинаковые правила. Например, установить интроскопы на входе на посадочную площадку или установить капитальное ограждение вокруг всей посадочной площадке. Т.е приравнять требования к вокзалу и к частному аэродрому. Если таковые инициативы реализуются в какой-то момент, то соблюдаться они не будут как нереальные (из-за большой финансовой нагрузки), но будет повод преследования как пилотов, так и владельцев аэродромов. ==Смешение с безопасностью полетов== Из-за использования слово "безопасность" в названии обоих понятий возникает путаница между "авиационной безопасностью" и [[АОН/Безопасность полетов|безопасностью полетов]]. ==См. также== * [[АОН/Транспортная безопасность|Транспортная безопасность]] *[[АОН/Ространснадзор|Ространснадзор]] [[Категория:АОН]] {{АОН}} pk19tfr6zmympoqi6qss7e5b3gue8vo АОН/Транспортная безопасность 0 35753 269741 269114 2026-08-04T20:39:27Z Leksey 3027 Уточнение 269741 wikitext text/x-wiki {{АОН Страница}} {{Википедия}} '''{{SUBPAGENAME}}''' (ТБ) — требования к безопасности на транспорте. [[АОН/Авиационная безопасность|Авиационная безопасность]], по-видимому, является частью этого понятия. Требования ТБ распространяются на ВС, выполняющие [[АОН/Авиаработы|авиаработы]]. == ТБ и АОН == [[АОН/Эксплуатант|Эксплуатанты]] (в том числе АОН и авиаработ) обязаны соблюать за ТБ ТС:, для чего эксплуатанты разрабатывают так называемые Паспорта транспортной безопасности (ПТБ) на конкретные воздушные суда. Далее копии паспортов отправляются в разные инстанции. == Нормативные требования к транспортной безопасности == Основные требования ТБ в N 16-ФЗ "О транспортной безопасности", но про авиацию именно в постановлении №731. {{Цитата|2. Настоящий документ применяется в отношении следующих транспортных средств: а) воздушные суда гражданской авиации, используемые для ....... выполнения авиационных работ; б) ВС АОН, определенные Правительством РФ по представлению федерального органа исполнительной власти.|источник=Постановление N 731}} == Ссылки == * [https://ivo.garant.ru/#/document/404533138 Постановление №731] “Об утверждении требований по обеспечению транспортной безопасности, учитывающих уровни безопасности для транспортных средств воздушного транспорта ==Примечания== {{Примечания}} {{АОН}} br3itqz0klhk6yz5wz4ksizvvyo3km4 269742 269741 2026-08-04T20:41:08Z Leksey 3027 Важное уточнение 269742 wikitext text/x-wiki {{АОН Страница}}{{Внимание|Можно сказать, что [[АОН/Авиационная безопасность|Авиационная безопасность]] теперь фигурирует в нормативных документах под именем "Транспортная безопасность".}}{{Википедия}} '''{{SUBPAGENAME}}''' (ТБ) — требования к безопасности на транспорте. Требования ТБ распространяются на ВС, выполняющие [[АОН/Авиаработы|авиаработы]]. == ТБ и АОН == [[АОН/Эксплуатант|Эксплуатанты]] (в том числе АОН и авиаработ) обязаны соблюать за ТБ ТС:, для чего эксплуатанты разрабатывают так называемые Паспорта транспортной безопасности (ПТБ) на конкретные воздушные суда. Далее копии паспортов отправляются в разные инстанции. == Нормативные требования к транспортной безопасности == Основные требования ТБ в N 16-ФЗ "О транспортной безопасности", но про авиацию именно в постановлении №731. {{Цитата|2. Настоящий документ применяется в отношении следующих транспортных средств: а) воздушные суда гражданской авиации, используемые для ....... выполнения авиационных работ; б) ВС АОН, определенные Правительством РФ по представлению федерального органа исполнительной власти.|источник=Постановление N 731}} == Ссылки == * [https://ivo.garant.ru/#/document/404533138 Постановление №731] “Об утверждении требований по обеспечению транспортной безопасности, учитывающих уровни безопасности для транспортных средств воздушного транспорта ==Примечания== {{Примечания}} {{АОН}} mzbyoqgr9tfwtdh142dfcpj4j2tp4b1