вторник, 16 мая 2017 г.

Уменьшение объёма исполняемого файла Free Pascal

Проблема архивации скомпилированных *.exe-файлов чаще встаёт перед пользователями RAD-сред наподобие Delphi и Lazarus, но иногда возникает необходимость «обрезать» приложение, сделанное в обычном Free Pascal (например, в том случае, если вы храните свои программы на файлообменнике или бесплатном хостинге).

468x60

Чтобы выяснить, каким же образом можно сжать и без того небольшой файл, давайте обратимся к опыту визуального программирования. Что мы делаем, когда хотим минимизировать объём своего проекта в Lazarus? Во-первых, ещё до начала работы с кодом отключаем добавление отладочной информации (иначе есть шанс получить форму с двумя кнопками весом в 12 Мбайт), во-вторых, после компиляции запускаем утилиту strip или upx.

Итак, начнём наш эксперимент. У меня в папке bin лежит исходник с именем test.pas. Давайте попробуем скомпилировать его с разными вариантами настроек.

  • Стандартная конфигурация (только что установленный FPC без всяких наворотов) – 67521 байт.
  • Включаем «Generate smaller code» и «Create smartlinkable units» в меню «Options» -> «Compiler» -> «Generated code», выключаем «Range checking» и «Stack checking» - 67455 байт.
  • Включаем все три уровня оптимизации в том же меню – а вот это, как показала практика, не помогает вообще.

Теперь попробуем воспользоваться утилитой strip. Для её запуска нужно открыть командную строку, перейти в папку с файлом strip.exe (команда cd вам в помощь), а затем ввести в окне cmd инструкцию strip --strip-all путь_к_файлу_вашей_программы. Применив её к своему test.exe, я получила приложение объёмом 40448 байт.

Upx в «чистом» Free Pascal’е нет, поэтому грузим его отсюда: https://upx.github.io/. Архив распаковываем в ту же папку, что и strip. Полное руководство по этому пакету вы сможете найти в файле upx.doc, я подскажу только один вариант работы с программой:


  • Переходим с помощью команды cd в каталог, куда устанавливали upx.
  • Вбиваем строку upx --brute путь_к_файлу_вашей_программы и нажимаем Enter.

На этом этапе может открыться один из минусов такого способа сжатия exe-шников, а именно – очень натянутые отношения между архиватором и антивирусами вроде avast! Free Antivirus. Но если вас это не беспокоит, то вот результат использования утилиты upx: объём моего test.exe стал равен всего лишь 19968 байт.

Полезные ссылки по теме:
https://www.freepascal.org/docs-html/prog/progse51.html#x256-27000011.5 – «Tips to generate smaller code»
http://wiki.freepascal.org/File_size_and_smartlinking - это больше про Lazarus, но для Free Pascal тоже актуально.

вторник, 9 мая 2017 г.

Метод Монте-Карло: примеры для языка C++

Метод Монте-Карло используется для нахождения определённых интегралов путём определения среднего значения функции на отрезке интегрирования. Он применяется в физике (теория струн, физика плазмы, физика твёрдого тела), экономике, химии, теории управления, поэтому владение этим методом наверняка будет для вас полезным.

468x60 #2

В самом простом случае интегрирование способом Монте-Карло выглядит так: вы генерируете N чисел в пределах промежутка интегрирования [a;b], находите f(x) для каждого из них, складываете полученные значения, умножаете на (b-a) и делите на N. Чтобы было понятнее – простой пример.

Задача 1. Найти площадь фигуры, ограниченной половиной синусоиды.

//Половина синусоиды - это sin x при xє[0;pi]
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace std;
int main(){
    double res=0; //Значение определённого интеграла
    srand(time(0));
    for(int i=0;i<100;i++){ //Ищем f(x) для 100 случайных значений
        res+=sin(acos(-1)*rand()/RAND_MAX);
    }
    cout << res*acos(-1)/100 << '\n';
    system("pause");
    return 0;
}

Результат должен быть приблизительно равен двум.

Задача 2. Найти площадь фигуры, ограниченной параболой y=x2, прямой x=2 и осью абсцисс.

//Нарисуйте то, что описано в условии, и увидите простейший табличный интеграл
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main(){
    double res=0;
    srand(time(0));
    for(int i=0;i<100;i++){
        double x=2.0*rand()/RAND_MAX;
        res=res+x*x;
    }
    cout << res*0.02 << '\n';
    system("pause");
    return 0;
}

Но это ещё не всё – есть также геометрическая вариация метода Монте-Карло. Она немного сложнее вышеописанного алгоритма, и выглядит следующим образом: находим прямоугольник, такой, что любая его сторона содержит хотя бы одну точку графика функции, но не пересекает его, выбираем N случайных точек внутри него и смотрим, сколько из них попали под график функции (назовём эту величину K). Значение интеграла находится как площадь прямоугольника, умноженная на K/N.

Задача 3. Найти число π, вычислив площадь единичного круга геометрическим методом Монте-Карло

//Площадь круга S=pi*R^2, pi=S/R^2
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cmath>
using namespace std;
int main(){
    srand(time(0));
    int k=0;
    //Используем прямоугольник с левым верхним углом в (-1;1) и правым нижним в (1;0)
    //Найдём площадь половины круга как площадь под графиком функции y=sqrt(1-x^2)
    for(int i=0;i<1000;i++){
        double x=-1+2.0*rand()/RAND_MAX, y=1.0*rand()/RAND_MAX;
        if(y<=sqrt(1-x*x)){
            k++;
        }
    }
    double pi=k/250.0;
    cout << pi << '\n';
    system("pause");
    return 0;
}