Помощь новичкам

Решил не поднимать старую тему про развёртывание цикла, поэтому если кто-то знает и может ответить без нафталинного юмора и поучений:

  • Каждый инструмент и метод под свои задачи. Хотя развёртывание возможно только для известного количества линейных итераций без ветвления, как это вписывается в современную концепцию программирования, включая OpenMP ? Можно просто свежую ссылку на русском.

Спасибо.

Разумеется

Тогда вопрос решен? Мне что - нибудь еще нужно делать?

Думаю, вопрос решен. Вы полезли внутрь системного модуля в трассировку ввода куда Вас не должны были пускать. И в результате этого несанкционированного проникновения на Вас обвалилась пыльная полка.

3 лайка

А что вы называете развёртыванием цикла? А то у меня пара вариантов в голове, но все звучат тупо… И вот эта части ни в 1 из них не вписывается:

Классически, это когда вместо

begin
  var a := Arr(1, 5, 8, 2, 4);
  var s := 0;
  for var i := 0 to a.High do
    s += a[i];
  s.Println
end.

пишут примерно так:

begin
  var a := Arr(1, 5, 8, 2, 4);
  var s := 0;
  s += a[0];
  s += a[1];
  s += a[2];
  s += a[3];
  s += a[4];
  s.Println
end.

Ну вот я и говорю, не вписывается та часть.

  1. Превращение этого:
  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-ами…

+ вот ещё совсем недавно тут, от @Admin:

Надо запретить лямбды внутри OpenMP

Совершенно верно. Поддерживаю. omp так и моделируется и алгоритм там совсем простой

А есть ли в PascalABC.Net что - нибудь схожее с шаблонами функций, например, как в C++?

Ну, началось… PascalABC.NЕТ - это почти C#, обернутый в другой синтаксис. Темплейтов нет, но есть возможность создавать и использовать объекты на основе обобщенных типов данных, параметризуемые при их вызове. Есть Pattern Matching…

Например, я бы хотел создать 1 функцию, которая будет работать с несколькими типами данных. Как максимально эффективно без повторений это сделать?

Напишите, пожалуйста, более конкретно и возможно тогда Вам смогут что-то подсказать. А еще - почему бы для начала не посмотреть здесь:

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 в указателе.

И про патерн мачинг так же почитайте, он увеличивает удобства работы с шаблонами:
http://forum.mmcs.sfedu.ru/t/pattern-matching-v-pascalabc-net

1 лайк

У меня версия 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, а как в новой версии. Спасибо.

Так а какое предупреждение вы получили и как? Может всё же ошибка компилятора…

  1. Я загружал много примеров и смотрел реализацию, но некоторые выдают предупреждения - это только у меня так или допустимо?
  2. Второй вопрос прямо не связан: Я попытался улучшить код, чтобы “квадраты” не накладывались, но не нашёл свойство вроде глубины или порядка рисования, не говоря о том, как для объекта лучше выбирать свободное место на экране, кроме циклов и, возможно, GOTO метки.

Спасибо за напоминание о видимости вложенных объявлений переменных, механически скопировал.

Это не нормально. И только у вас может быть только в том случае, если у вас стоит устаревшая версия. Но нужна конкретика, где идут какие предупреждения.

Можно придумать несколько алгоритмов для этого. Но 1. при чём тут свойство глубины и 2. при чём тут метки? Ни то ни то никак не поможет придумать такой алгоритм, а метки это ещё и то что не стоит использовать если вы не из пещеры вышли.

Вы всё ещё не объяснили как вы получили предупреждение. Я понимаю если бы это была ошибка. Но предупреждение?!

Мне смешно, смотрю на то, что там написано, а потом на свой код в 600 с лишнем строк, понимая что в книге все расписано, а я с дури все в кучу… Надо иногда хотя бы немного продумывать что пишу…

Спасибо за эту научную работу