Решил не поднимать старую тему про развёртывание цикла, поэтому если кто-то знает и может ответить без нафталинного юмора и поучений:
Каждый инструмент и метод под свои задачи. Хотя развёртывание возможно только для известного количества линейных итераций без ветвления, как это вписывается в современную концепцию программирования, включая OpenMP ? Можно просто свежую ссылку на русском.
Думаю, вопрос решен. Вы полезли внутрь системного модуля в трассировку ввода куда Вас не должны были пускать. И в результате этого несанкционированного проникновения на Вас обвалилась пыльная полка.
var s := 0;
for var i := 1 to n do
begin
s += i;
end;
В это, где известно что n имеет значение от 3 до 5:
s += 1;
s += 2;
s += 3;
if n<4 then goto sum_end;
s += 4;
if n<5 then goto sum_end;
s += 5;
sum_end:
(да, можно чисто через if, без goto, но выглядит сложнее как для примера)
Тоже является развёртыванием в том же смысле, значит кол-во операций не обязательно должно быть полностью известно. Ну и конечно можно ещё добавить цикл в самом конце, таким образом развернув только несколько итераций любого цикла, хоть бесконечного.
А это вообще не понял с чего вдруг. Как ветвление может помешать развёртыванию? Даже goto выкидывающий точку выполнения за цикл - никак не помешает развернуть этот цикл.
Насчёт современного программирования - оно тут не то причём, ибо правила действуют старые. Развёртывание и распараллеливание (как OpenMP, OpenCL и т.п.) это 2 разные вещи, работающие по совершенно разному принципу и применимые в разных ситуациях.
Развёртывание сейчас у PABC.Net никак не реализовано. Если бы мне очень приспичило - я бы написал коротенькую программу которая автоматически генерировала версию моего кода, где развёрнуты все циклы, помеченные чем то типа {%UnWrap}. Но по моему оно того не стоит.
Распараллеливание же это совсем другая история, если уметь использовать - можно увеличить производительность в несколько раз. Но в случаях, где перезаписывается хотя бы 1 общая область в памяти (как сложение элементов массива) - будет больно. Максимум что можно распараллелить - это складывание значений парами, в несколько итераций.
Ну и, если всё же вернутся от абстракций к современному программированию…
Про то как использовать OpenMP написано в справке самого паскаля (директива $omp), а для OpenCL - есть примеры в папке C:\PABCWork.NET\Samples\OpenCL. Это (вроде) достаточно информации чтоб разобраться как их использовать.
Могу только добавить что OpenMP использует сразу все ядра CPU, но не используется GPU, а OpenCL использует вообще что угодно (но обычно только GPU, ибо скорость CPU в сравнении ничтожна). Поэтому использование OpenCL сложнее, но может дать бОльший прирост производительности.
P.S. Насчёт OpenMP ещё… Вообще, лучше вместо него используйте на прямую System.Threading.Tasks.Parallel, через которое оно реализовано. Ибо у $omp есть несколько тупых ограничений.
Как то, что если в 1 месте в программе выполняется секция с $omp - если другая попытается тоже использовать $omp - её выполнит синхронно. При чём реализовано это криво, так что в 2 потоках может одновременно запустится по секции $omp, и обе сработают параллельно. Ибо
if not InParallelSection then
begin
InParallelSection := true;
// асинхронное выполнение
InParallelSection := false;
end else
// синхронное выполнение
Если 2 потока одновременно выполнят if - получаем одновременное выполнение 2 $omp, потому что тот кто занимался распараллеливанием, почему то не знал что его надо закусывать lock-ами…
Ну, началось… PascalABC.NЕТ - это почти C#, обернутый в другой синтаксис. Темплейтов нет, но есть возможность создавать и использовать объекты на основе обобщенных типов данных, параметризуемые при их вызове. Есть Pattern Matching…
type
t1<T> = class
end;
function f1<T>(a: T) :=
default(T); // всегда нулевое значение
begin
f1(0); // T=integer - автоматически вычислился
f1&<byte>(0); // T=byte - явно указан
new t1<word>; // шаблонный тип класса всегда указывается явно
t1&<string>.Create; // если нужно вызвать что то статичное - надо опять знак & перед первой скобкой
end.
Шаблонных типов может быть несколько, они указываются через запятую в <>. Имена в теории можно придумывать самому, но обычно если шаблонный тип 1, его называют T. Если несколько - T1, T2, T3. Ну или в некоторых случаях их так же называют по смыслу:
Так же можно указывать ограничение на шаблонный тип, это уже читайте сами в справке. Ищите по слову where в указателе.
У меня версия 3.5 сборка 2084, и в проверенных Примерах есть некоторые коды с предупреждениями - это нормально?
Далее конкретнее по DeleteByMouse.pas, иногда “квадраты” перекрываются, что лучше контролировать по ходу: есть ли в Pascal Abc .Net новые способы избежать наложения или проще старый способ выноса в цикл:
repeat
var x := Random(Window.Width-50);
var y := Random(Window.Height-100);
until ObjectUnderPoint(x,y)=nil;
...
А где вы это нашли? У меня (сборка не выпущенная, я ради фиксов сам собрал билд, но у вас тоже явно не последняя версия) файл C:\PABCWork.NET\Samples\Games\DeleteByMouse.pas выглядит так:
uses WPFObjects;
const CountSquares = 20;
var
/// Текущая цифра
CurrentDigit: integer;
/// Количество ошибок
Mistakes: integer;
/// Строка информации
StatusRect: RectangleWPF;
/// Вывод информационной строки
procedure DrawStatusText;
begin
if CurrentDigit<=CountSquares then
StatusRect.Text := $'Удалено квадратов: {CurrentDigit-1} Ошибок: {Mistakes}'
else StatusRect.Text := $'Игра окончена. Время: {Milliseconds div 1000} с. Ошибок: {Mistakes}';
end;
/// Обработчик события мыши
procedure MyMouseDown(x,y: real; mb: integer);
begin
var ob := ObjectUnderPoint(x,y);
if (ob<>nil) and (ob is RectangleWPF) and (ob<>StatusRect) then
if ob.Number=CurrentDigit then
begin
ob.Destroy;
Inc(CurrentDigit);
DrawStatusText;
end
else
begin
ob.Color := Colors.Red;
Inc(Mistakes);
DrawStatusText;
end;
end;
begin
Window.Title := 'Игра: удали все квадраты по порядку';
for var i:=1 to CountSquares do
begin
var x := Random(Window.Width-50);
var y := Random(Window.Height-100);
var ob := RectangleWPF.Create(x,y,50,50,Colors.LightGreen).WithBorder;
ob.FontSize := 25;
ob.Number := i;
end;
StatusRect := RectangleWPF.Create(0,Window.Height-40,Window.Width,40,Colors.LightBlue);
CurrentDigit := 1;
Mistakes := 0;
DrawStatusText;
// Установка обработчиков
OnMouseDown := MyMouseDown;
end.
А код который привели вы - и не должен работать, переменные, объявленные в теле repeat-until, не видны в условии until.
for var i:=1 to CountSquares do
begin
var x := Random(Window.Width-50);
var y := Random(Window.Height-100);
var ob := RectangleWPF.Create(x,y,50,50,Colors.LightGreen).WithBorder;
ob.FontSize := 25;
ob.Number := i;
end;
может происходить наложение, поэтому желательно контролировать позиции X;Y.
По старинке это делали через Repeat или While, а как в новой версии. Спасибо.
Я загружал много примеров и смотрел реализацию, но некоторые выдают предупреждения - это только у меня так или допустимо?
Второй вопрос прямо не связан: Я попытался улучшить код, чтобы “квадраты” не накладывались, но не нашёл свойство вроде глубины или порядка рисования, не говоря о том, как для объекта лучше выбирать свободное место на экране, кроме циклов и, возможно, GOTO метки.
Спасибо за напоминание о видимости вложенных объявлений переменных, механически скопировал.
Это не нормально. И только у вас может быть только в том случае, если у вас стоит устаревшая версия. Но нужна конкретика, где идут какие предупреждения.
Можно придумать несколько алгоритмов для этого. Но 1. при чём тут свойство глубины и 2. при чём тут метки? Ни то ни то никак не поможет придумать такой алгоритм, а метки это ещё и то что не стоит использовать если вы не из пещеры вышли.
Вы всё ещё не объяснили как вы получили предупреждение. Я понимаю если бы это была ошибка. Но предупреждение?!
Мне смешно, смотрю на то, что там написано, а потом на свой код в 600 с лишнем строк, понимая что в книге все расписано, а я с дури все в кучу… Надо иногда хотя бы немного продумывать что пишу…