Температура и цвет
Здесь демонстрируется использование вложенной условной операции, а также метода расширения Between для целых (по умолчанию он включает концы)
Здесь демонстрируется использование вложенной условной операции, а также метода расширения Between для целых (по умолчанию он включает концы)
begin
var t := ReadInteger; // температура
var color :=
if t.Between(-100, 0) then 'blue' else
if t.Between(1, 15) then 'green' else
if t.Between(16, 30) then 'yellow' else
if t.Between(31, 100) then 'red' else
'black';
Println($'Temperature color: {color}');
end.
❤9
♟ Решение задачи о 8 ферзях в PascalABC.NET
Классический алгоритм с рекурсией и проверкой конфликтов по столбцам и диагоналям. Каждое найденное расположение выводится на экран в виде массива: board[row] = column.
Один из самых коротких известных алгоритмов. Замените N на 10, 12, 16 и посмотрите, что будет на больших шахматных досках :)
Классический алгоритм с рекурсией и проверкой конфликтов по столбцам и диагоналям. Каждое найденное расположение выводится на экран в виде массива: board[row] = column.
const N = 8;
var board := new integer[N]; // board[row] = столбец ферзя в этой строке
procedure Place(row: integer);
begin
for var col := 0 to N-1 do
begin
// проверяем конфликты со всеми ранее поставленными ферзями
var conflict := False;
for var prevRow := 0 to row-1 do
if (board[prevRow] = col) or // тот же столбец
(abs(board[prevRow] - col) = abs(prevRow - row)) then // та же диагональ
begin
conflict := True;
break;
end;
if not conflict then
begin
board[row] := col; // ставим ферзя
if row = N-1 then
board.Println // выводим решение
else Place(row+1); // продолжаем рекурсию
end
end;
end;
begin
Println('Все решения задачи о 8 ферзях:');
Place(0);
end.
Один из самых коротких известных алгоритмов. Замените N на 10, 12, 16 и посмотрите, что будет на больших шахматных досках :)
👍7❤4
Линейная модель + активация = простейший ИИ в PascalABC.NET
Реализуем элементарный предсказатель на основе линейной комбинации признаков и функции активации.
Такой принцип лежит в основе логистической регрессии и нейронных сетей.
📌 В этом примере показано:
🔹 как считать линейную комбинацию x·w + b;
🔹 как применить сигмоиду — популярную функцию активации;
🔹 как через функциональные переменные передавать функцию в другую функцию;
🔹 как построить простейшую модель предсказания.
🧠 Это уже мини-модель машинного обучения — всё на чистом PascalABC.NET, без библиотек.
Реализуем элементарный предсказатель на основе линейной комбинации признаков и функции активации.
Такой принцип лежит в основе логистической регрессии и нейронных сетей.
function LinearCombination(x, w: array of real; b: real): real;
begin
Result := b;
for var i := 0 to x.Length - 1 do
Result += x[i] * w[i];
end;
function Sigmoid(z: real) := 1 / (1 + Exp(-z));
function Predict(x, w: array of real; b: real; activation: real -> real) :=
activation(LinearCombination(x, w, b));
begin
var weights := [0.8, -0.3, 0.5, -0.2];
var bias := 0.1;
var x := [45.0, 120.0, 5.5, 24.5];
var probability := Predict(x, weights, bias, Sigmoid);
Println('Вероятность диабета:', probability);
end.
📌 В этом примере показано:
🔹 как считать линейную комбинацию x·w + b;
🔹 как применить сигмоиду — популярную функцию активации;
🔹 как через функциональные переменные передавать функцию в другую функцию;
🔹 как построить простейшую модель предсказания.
🧠 Это уже мини-модель машинного обучения — всё на чистом PascalABC.NET, без библиотек.
👍9❤4
Градиентный спуск на PascalABC.NET
Хотим предсказывать итоговую оценку студента по двум параметрам:
x1 — часы подготовки
x2 — часы сна
Модель: линейная регрессия
Учимся на реальных парах данных, минимизируем квадратичную ошибку методом градиентного спуска.
Функция ошибки на одном наблюдении:
Частные производные:
Используем средний градиент по всей выборке.
Это базовый пример градиентного спуска без библиотек.
Хотим предсказывать итоговую оценку студента по двум параметрам:
x1 — часы подготовки
x2 — часы сна
Модель: линейная регрессия
Учимся на реальных парах данных, минимизируем квадратичную ошибку методом градиентного спуска.
Функция ошибки на одном наблюдении:
L = (w1*x1 + w2*x2 + b - y)**2
Частные производные:
dL/dw1 = 2*x1*(w1*x1 + w2*x2 + b - y)
dL/dw2 = 2*x2*(w1*x1 + w2*x2 + b - y)
dL/db = 2*(w1*x1 + w2*x2 + b - y)
Используем средний градиент по всей выборке.
function Loss(x1, x2, w1, w2, b, y: real) :=
(w1*x1 + w2*x2 + b - y)**2;
function dL_dw1(x1, x2, w1, w2, b, y: real) :=
2 * x1 * (w1*x1 + w2*x2 + b - y);
function dL_dw2(x1, x2, w1, w2, b, y: real) :=
2 * x2 * (w1*x1 + w2*x2 + b - y);
function dL_db(x1, x2, w1, w2, b, y: real) :=
2 * (w1*x1 + w2*x2 + b - y);
begin
var x: array of array of real := (
(2,6),(4,5),(5,7),(1,4),(3,6),
(6,5),(5,6),(7,8),(3,5),(4,7)
);
var y: array of real := (70,78,82,62,75,85,80,90,72,79);
var n := x.Length;
var w1 := 0.1; var w2 := 0.1; var b := 0.1;
// скорость обучения
var lr := 0.002;
var epochs := 20000;
for var epoch := 0 to epochs-1 do
begin
var grad_w1 := 0.0;
var grad_w2 := 0.0;
var grad_b := 0.0;
var total_loss := 0.0;
for var i := 0 to n-1 do
begin
var x1 := x[i][0];
var x2 := x[i][1];
var yi := y[i];
total_loss += Loss(x1,x2,w1,w2,b,yi);
grad_w1 += dL_dw1(x1,x2,w1,w2,b,yi);
grad_w2 += dL_dw2(x1,x2,w1,w2,b,yi);
grad_b += dL_db (x1,x2,w1,w2,b,yi);
end;
w1 -= lr * grad_w1 / n;
w2 -= lr * grad_w2 / n;
b -= lr * grad_b / n;
if (epoch+1) mod 5000 = 0 then
Println($'Эпоха {epoch+1}: ошибка={total_loss/n:0.0000};
w1={w1:0.000}; w2={w2:0.000}; b={b:0.000}');
end;
end.
Это базовый пример градиентного спуска без библиотек.
🔥8❤2🤡2👍1
Рост пользователей из Китая
По данным mail.ru с июля 2025 года наблюдается стремительный рост пользователей PascalABC.NET из Китая
По данным mail.ru с июля 2025 года наблюдается стремительный рост пользователей PascalABC.NET из Китая
🤩6❤3👍1
Task / Task<integer> в PascalABC.NET
Когда мы запускаем задачу через
В данном случае лямбда возвращает целое значение, и поэтому
Что такое t1.Result
Если задача ещё не закончила работу — при обращении к
Если же к моменту вызова
Пример: две задачи считают параллельно
Что происходит
🔹 Создаются две независимые задачи
🔹 Каждая считает свою сумму
🔹 Они работают одновременно
🔹 Когда мы обращаемся к
🔹 Затем выводим сумму двух результатов
Task — это задача, которая может выполняться параллельно с основной программой.Когда мы запускаем задачу через
Task.Run, мы передаём внутрь лямбда-выражение без параметров, которое что-то вычисляет и в конце пишет:Result := ...
В данном случае лямбда возвращает целое значение, и поэтому
Task.Run создаёт объект класса Task<integer>.Что такое t1.Result
t1.Result — это способ получить результат работы задачи.Если задача ещё не закончила работу — при обращении к
t1.Result программа приостановится, подождёт завершения задачи и потом вернёт её результат. Если же к моменту вызова
t1.Result задача закончила работу, то просто вернется результат как будто мы вызвали обычную функцию.Пример: две задачи считают параллельно
uses System.Threading.Tasks;
begin
var t1 := Task.Run(()->
begin
var s := 0;
for var i:=1 to 5_000_000 do
s += i;
Result := s // => t1 будет Task<integer>
end);
var t2 := Task.Run(()->
begin
var s := 0;
for var i:=1 to 5_000_000 do
s += i*i;
Result := s // => t2 будет Task<integer>
end);
// Ожидание завершения + получение результата
var r := t1.Result + t2.Result;
Println(r);
end.
Что происходит
🔹 Создаются две независимые задачи
🔹 Каждая считает свою сумму
🔹 Они работают одновременно
🔹 Когда мы обращаемся к
t1.Result и t2.Result, программа ждёт и получает результат🔹 Затем выводим сумму двух результатов
❤3👍3
Перегрузка операций - теперь без extensionmethod
Теперь в PascalABC.NET для перегрузки операций не надо писать extensionmethod
Операции перегружаются как обычные функции с именем operator@ где @ - значок операции
#новое
Теперь в PascalABC.NET для перегрузки операций не надо писать extensionmethod
Операции перегружаются как обычные функции с именем operator@ где @ - значок операции
#новое
👍11
🧠 ML: нормализация признаков в PascalABC.NET
При подготовке данных для моделей машинного обучения часто требуется нормализовать каждый признак (столбец матрицы): вычесть среднее и поделить на стандартное отклонение. В PascalABC.NET это можно сделать компактно и полностью функционально.
Нормализация столбцов — стандартный шаг при работе с датасетами: она улучшает сходимость моделей, делает признаки сопоставимыми и устраняет влияние масштаба. Благодаря функциональному стилю PascalABC.NET такие операции можно выразить очень компактно.
При подготовке данных для моделей машинного обучения часто требуется нормализовать каждый признак (столбец матрицы): вычесть среднее и поделить на стандартное отклонение. В PascalABC.NET это можно сделать компактно и полностью функционально.
function Normalize(a: array of real): array of real;
begin
var mean := a.Average;
var std := Sqrt(a.ConvertAll(x -> (x-mean)**2).Average);
Result := a.ConvertAll(x -> (x-mean)/std);
end;
function NormalizeCols(a: array[,] of real): array[,] of real
:= MatrByCol(a.Cols.ConvertAll(col -> Normalize(col)));
begin
var a := Matr([1.1,2,3],[4.3,5,6],[7.0,8,9],[5.7,2,8]);
NormalizeCols(a).Print(7,1)
end.
Нормализация столбцов — стандартный шаг при работе с датасетами: она улучшает сходимость моделей, делает признаки сопоставимыми и устраняет влияние масштаба. Благодаря функциональному стилю PascalABC.NET такие операции можно выразить очень компактно.
👍7❤1
Массивы и списки - это последовательности
В PascalABC.NET есть специальный тип-последовательность - набор элементов, которые можно перебрать один за другим циклом foreach.
Если нужно написать некоторый алгоритм и перебрать элементы, то лучше использовать не конкретный тип - массив или список, а последовательность:
В PascalABC.NET есть специальный тип-последовательность - набор элементов, которые можно перебрать один за другим циклом foreach.
Если нужно написать некоторый алгоритм и перебрать элементы, то лучше использовать не конкретный тип - массив или список, а последовательность:
function SumSquares(s: sequence of integer): integer;
begin
Result := 0;
foreach var x in s do
Result += x*x;
end;
begin
SumSquares(Arr(1,2,3)).Print;
SumSquares(Lst(2,3,4)).Print;
end.
✍6👍1
Количество простых чисел
Как вычислить количество простых чисел, меньших заданного n?
Используем LINQ и функциональное программирование.
Два способа: обычный и с распараллеливанием.
Linq автоматически распараллеливает проверки для разных чисел на простоту по различным потокам.
Скорость распараллеленной версии - примерно в 6 раз меньше - значит, процессор шестиядерный.
Как вычислить количество простых чисел, меньших заданного n?
Используем LINQ и функциональное программирование.
Два способа: обычный и с распараллеливанием.
##
function IsPrime(x: integer) := (2..x.Sqrt.Round).All(i -> x.NotDivs(i));
var n := 4000000;
(2..n).Where(IsPrime).Count.Println;
MillisecondsDelta.Println;
(2..n).AsParallel.Where(IsPrime).Count.Println;
MillisecondsDelta.Println;
Linq автоматически распараллеливает проверки для разных чисел на простоту по различным потокам.
Скорость распараллеленной версии - примерно в 6 раз меньше - значит, процессор шестиядерный.
👍9❤🔥1
Умножение матриц в стиле LINQ
Для умножения матриц используем метод Zip и срезы матрицы по строке и столбцу
Результат:
Для умножения матриц используем метод Zip и срезы матрицы по строке и столбцу
function Dot(a1, a2: array of real): real := a1.Zip(a2,(x,y) -> x*y).Sum;
function Mult(a, b: array[,] of real): array[,] of real :=
MatrGen(a.RowCount, b.ColCount, (i,j) -> Dot(a[i,:],b[:,j]));
begin
var a := Matr([1.1,2,3],[4.3,5,6],[7.0,8,9],[5.7,2,8]);
var b := Matr([4.0,5],[8.2,4],[3.0,9]);
a.Print(7,1); Println;
b.Print(7,1); Println;
Mult(a,b).Print(7,1);
end.
Результат:
1.1 2.0 3.0
4.3 5.0 6.0
7.0 8.0 9.0
5.7 2.0 8.0
4.0 5.0
8.2 4.0
3.0 9.0
29.8 40.5
76.2 95.5
120.6 148.0
63.2 108.5
👍5🤩2
🔧 Замена текста внутри квадратных скобок
Если требуется заменить текст внутри [...], можно воспользоваться методами строк
Первую открывающую скобку ищем до цикла, а в самом цикле переходим к следующей уже со строки позиции конечной скобки.
Приём подходит для любой задачи, где нужно обработать фрагменты между парными символами.
Если требуется заменить текст внутри [...], можно воспользоваться методами строк
IndexOf, Remove и Insert.Первую открывающую скобку ищем до цикла, а в самом цикле переходим к следующей уже со строки позиции конечной скобки.
begin
var s := 'Клад зарыт на [юго-западе] под [пальмой]';
var replaceStr := 'скрыто';
var startPos := s.IndexOf('[');
while startPos <> -1 do
begin
var endPos := s.IndexOf(']', startPos + 1);
if endPos = -1 then break;
s := s.Remove(startPos + 1, endPos - startPos - 1);
s := s.Insert(startPos + 1, replaceStr);
startPos := s.IndexOf('[', endPos); // безопасно в PascalABC.NET
end;
Println(s);
end.
Приём подходит для любой задачи, где нужно обработать фрагменты между парными символами.
👍9
Находим элементы, встречающиеся в последовательности ровно один раз
Используем два множества: одно для потенциально уникальных значений, второе — для повторяющихся.
Ровно один раз встретившиеся элементы выводятся в отсортированном виде.
Используем два множества: одно для потенциально уникальных значений, второе — для повторяющихся.
begin
var data := [1, 2, 3, 2, 4, 5, 3, 6, 7, 1, 8, 9, 4, 10];
data.Println;
var unique, multi: set of integer;
foreach var num in data do
begin
if num in multi then
continue;
if num in unique then
begin
unique -= num;
multi += num;
end
else unique += num;
end;
unique.Order.Println;
end.
Ровно один раз встретившиеся элементы выводятся в отсортированном виде.
👍9
Решето Эратосфена - максимально компактно и понятно
Решето Эратосфена — это один из наиболее эффективных алгоритмов для нахождения всех простых чисел до заданного предела n. Он отличается высокой производительностью и простотой реализации.
Алгоритм обладает асимптотической сложностью O(n * log log n), что делает его значительно быстрее простейших методов определения простоты через деление.
А что такое ISqrt(n) - читайте в справке!
Решето Эратосфена — это один из наиболее эффективных алгоритмов для нахождения всех простых чисел до заданного предела n. Он отличается высокой производительностью и простотой реализации.
Алгоритм обладает асимптотической сложностью O(n * log log n), что делает его значительно быстрее простейших методов определения простоты через деление.
##
function SieveOfEratosthenes(n: integer): array of integer;
begin
var isPrime := [False] * 2 + [True] * (n - 1);
for var i := 2 to ISqrt(n) do
if isPrime[i] then
for var j := i * i to n step i do
isPrime[j] := False;
Result := (2..n).Where(i -> isPrime[i]).ToArray;
end;
SieveOfEratosthenes(1000).Println;
А что такое ISqrt(n) - читайте в справке!
❤4👍2🔥1
Фабрика предикатов
Напишем функцию, которая возвращает лямбду-предикат с параметром. Функция принимает параметр, лямбда его захватывает.
В результате вместо лямбды можно писать вызов функции с параметром
Напишем функцию, которая возвращает лямбду-предикат с параметром. Функция принимает параметр, лямбда его захватывает.
В результате вместо лямбды можно писать вызов функции с параметром
function less(a: integer): integer -> boolean
:= x -> x < a;
begin
Arr(1..9).Where(less(5)).Print
end.
🔥6👍3
2000 подписчиков в нашем телеграм-канале!
Прямо сейчас: нас - 2000!
👉 https://tgstat.ru/channel/@pascalabc_official/stat
И это особенно приятно, потому что канал растёт естественно:
🔹без накруток
🔹без покупной рекламы
🔹без «случайных» подписчиков
Здесь собираются те, кому действительно интересен современный PascalABC.NET:
🔹живые примеры кода
🔹новые возможности языка
🔹приёмы, о которых не пишут в учебниках
🔹актуальные подходы и современные парадигмы программирования
Спасибо каждому, кто читает, думает, пробует и пишет код на PascalABC.NET вместе с нами 🚀
Прямо сейчас: нас - 2000!
👉 https://tgstat.ru/channel/@pascalabc_official/stat
И это особенно приятно, потому что канал растёт естественно:
🔹без накруток
🔹без покупной рекламы
🔹без «случайных» подписчиков
Здесь собираются те, кому действительно интересен современный PascalABC.NET:
🔹живые примеры кода
🔹новые возможности языка
🔹приёмы, о которых не пишут в учебниках
🔹актуальные подходы и современные парадигмы программирования
Спасибо каждому, кто читает, думает, пробует и пишет код на PascalABC.NET вместе с нами 🚀
🎉23👍9❤7🔥1👏1🤗1
match — это case по типам
В современном PascalABC.NET можно элегантно обрабатывать значение в зависимости от его типа, а не только от значения.
Что важно:
🔹выбор ветки происходит по типу объекта
🔹при совпадении тип сразу доступен в переменной (i, s)
🔹код получается короче и понятнее, чем цепочки if obj is ...
По сути, это case, который работает с типами.
В современном PascalABC.NET можно элегантно обрабатывать значение в зависимости от его типа, а не только от значения.
begin
var obj: object := 'Hello PascalABC.NET!';
match obj with
integer(i): Println(i * i);
string(s): Println(s.Length);
else Println(TypeName(obj));
end;
end.
Что важно:
🔹выбор ветки происходит по типу объекта
🔹при совпадении тип сразу доступен в переменной (i, s)
🔹код получается короче и понятнее, чем цепочки if obj is ...
По сути, это case, который работает с типами.
👍11🔥1
Сколько слов в строке каждой длины
Если строка состоит из слов, легко посчитать, сколько слов каждой длины, используя комбинацию методов GropupBy и Each. Метод Each возвращает словарь, который можно отсортировать по ключу и вывести
Если строка состоит из слов, легко посчитать, сколько слов каждой длины, используя комбинацию методов GropupBy и Each. Метод Each возвращает словарь, который можно отсортировать по ключу и вывести
begin
var s := 'как однажды жак звонарь головой сломал фонарь';
s.ToWords
.GroupBy(word -> word.Length)
.Each(word -> word.Count)
.OrderBy(kv -> kv.Key)
.PrintLines(kv -> $'{kv.Key}-буквенных - {kv.Value} шт')
end.
🥰5👍2❤1