PascalABC.NET официальный канал
رفتن به کانال در Telegram
Официальный канал языка и системы программирования PascalABC.NET
نمایش بیشتر1 861
مشترکین
-624 ساعت
-57 روز
-2330 روز
آرشیو پست ها
🔧 Замена текста внутри квадратных скобок
Если требуется заменить текст внутри [...], можно воспользоваться методами строк
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.
Приём подходит для любой задачи, где нужно обработать фрагменты между парными символами.Умножение матриц в стиле LINQ
Для умножения матриц используем метод 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Количество простых чисел
Как вычислить количество простых чисел, меньших заданного 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 раз меньше - значит, процессор шестиядерный.Массивы и списки - это последовательности
В 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.Copy для массивов и матриц как метод расширения
Для создания копии массивов и матриц пользуемся методом расширения Copy
🧠 ML: нормализация признаков в 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 такие операции можно выразить очень компактно.Чему равен синус?
Проверим. Для этого просто напечатаем синус 👀
А синус оказывается - это функция 🤔
Перегрузка операций - теперь без extensionmethod
Теперь в PascalABC.NET для перегрузки операций не надо писать extensionmethod
Операции перегружаются как обычные функции с именем operator@ где @ - значок операции
#новое
Task / Task<integer> в PascalABC.NET — понятное объяснение
Task — это задача, которая может выполняться параллельно с основной программой.
Когда мы запускаем задачу через Task.Run, мы передаём внутрь лямбда-выражение без параметров, которое что-то вычисляет и в конце пишет:
Result := ...В данном случае лямбда возвращает целое значение, и поэтому
Task.Run создаёт объект класса Task<integer>.
Что такое t1.Result
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, программа ждёт и получает результат
🔹 Затем выводим сумму двух результатовРост пользователей из Китая
По данным mail.ru с июля 2025 года наблюдается стремительный рост пользователей PascalABC.NET из Китая
Градиентный спуск на PascalABC.NET
Хотим предсказывать итоговую оценку студента по двум параметрам:
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.
Это базовый пример градиентного спуска без библиотек.Линейная модель + активация = простейший ИИ в 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, без библиотек.♟ Решение задачи о 8 ферзях в PascalABC.NET
Классический алгоритм с рекурсией и проверкой конфликтов по столбцам и диагоналям. Каждое найденное расположение выводится на экран в виде массива: 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.
Один из самых коротких известных алгоритмовТемпература и цвет
Здесь демонстрируется использование вложенной условной операции, а также метода расширения 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.Чему равен корень из -1
А действительно - чему?
Это зависит от типа. Если тип - real, то это не число. В смысле число, которое называется NaN (Not a Number).
Если тип - Complex - то вполне себе нормальное комплексное число, примерно равное i - комплексной единице.
Различия между модулями и библиотеками
Данная таблица приводится в курсе Основы программирования в начале второго месяца обучения.
Все весьма сложные концепции разбираются в этом курсе подробно, эффективно и на ранних этапах
Модуль TurtleABC
Появился модуль TurtleABC для Linux
uses TurtleABC;
begin
SetScale(4);
SetOrigin(5,-35);
SetColor(Color.Blue);
Down;
loop 4 do
begin
Forw(20);
Turn(90);
end;
Up;
MoveTo(-30, 30);
Down;
SetColor(Color.Red);
loop 3 do
begin
Forw(15);
Turn(120);
end;
end.Машинное 𝜀
Машинным 𝜀 называется минимальное вещественное значение, для которого для которого 1 + 𝜀 > 1. Для типа real оно находится между 1e-15 и 1e-16.
Вот программа для вычисления машинного 𝜀
function MachineEpsilon: real;
begin
var eps := 1.0;
while 1.0 + eps > 1.0 do
eps := eps / 2.0;
Result := eps * 2.0;
end;
begin
var eps := MachineEpsilon;
Println('Машинный эпсилон =', eps);
Println('1 + eps = 1?', 1 + eps = 1);
Println('1 + eps/2 = 1?', 1 + eps/2 = 1);
end.Repost from PascalABC.NET официальный канал
Особые значения вещественного типа
Среди особых значений вещественного типа различают Бесконечность (положительную и отрицательную) и значение NaN - Not a Number (не число), которое возникает при некоторых некорректных операциях - например, при извлечении корня из отрицательного числа
##
// +∞: результат деления на 0 или константа PositiveInfinity
var posInf := real.PositiveInfinity;
var posInf2 := 1.0/0.0;
Println($'+∞: {posInf} Проверка: {real.IsPositiveInfinity(posInf)}');
Println($'1/0 → {posInf2}');
// -∞: отрицательное деление на 0 или константа NegativeInfinity
var negInf := real.NegativeInfinity;
var negInf2 := -1.0/0.0;
Println($'-∞: {negInf} Проверка: {real.IsNegativeInfinity(negInf)}');
Println($'-1/0 → {negInf2}');
// NaN: «не число» – результат недопустимых операций
var nanVal := real.NaN;
var nanVal2 := Sqrt(-1);
Println($'NaN: {nanVal} Проверка: {real.IsNaN(nanVal)}');
Println($'Sqrt(-1) → {nanVal2}');