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

в pascale все unchecked. указатели (на размерные типы) можно использовать без всяких флажков.

  1. Константы не unchecked.
  2. Есть не мало случаев когда как раз надо checked, я его как само собой прилагающееся имел в виду. Ну а вообще можно написать функцию для этого и будет вполне вменяемо работать. Можете подсказать как оно работает, чтоб не изобретать велосипед?

В языках как C++ массивы передаются указателем на элемент, есть какой то аналог такому в паскале?

Насколько помню, в PascalABC.NET указатели с особеностями. Но вот вопрос: к чему они вообще в ссылочной модели? К чему они в системе, где сбором мусора управляет системная служба - чтобы висячими объектами с убитыми предками “от криворуких программистов” кушать память? Честно говоря, я вообще не могу представить, зачем в PascalABC.NET могут быть нужны указатели…

К сожелению криворукие не только программисты а и сборка мусора) К примеру 2 объекта ссылающиеся не соберутся с мусором. Ну это так себе пример, отследить такие случаи не сложно, но я вот сейчас у себя борюсь в программе чтоб они не жрала гигабайт оперативки на ровном месте, и знаете, как то не помогает то что за меня что то заранее продумали, всё равно приходится абсолютно всё изучать и много тестировать.

Это не так. Соберутся.

помогает. ибо надо думать о задаче, а не изобретать очередной неработающий велосипед.

Имеется код, написанный “злобным преподавателем”, считающим, что “все эти нововведения в стиле функционального программирования - зло”.

  type tMas=array[1..100] of integer;

  var
    N:integer;
    a:tMas:=(520,46904,58684,2215,83967,66560,96722,41600,16921,
        99150,1151,86738,63634,71238,13216,32406,49880,1558,75516,
        73929,7482,58804,47776,65890,47698,18548,26752,98776,82750,
        87389,23938,55437,86701,10204,93551,24241,16244,44138,25003,
        22798,83587,70257,65030,83983,81229,67478,78077,42619,73533,
        41772,49635,31721,77620,34630,63560,41716,99129,92794,54518,
        65419,39808,97947,58850,29532,75212,45715,37,53430,77687,
        88976,16163,5742,76556,52718,90343,37226,93774,63793,84661,
        80220,40472,84134,25243,40979,37755,92218,77818,52072,46645,
        51836,25112,23450,89621,59584,82991,85640,11407,35498,8771,35515);

  function In3(n:integer):boolean;
  begin
    var F:boolean:=False;
    while n<>0 do begin
      if n mod 10=3 then F:=True;
      n:=n div 10; 
      end;
    In3:=F;
  end;
  
begin
  var k:=1000000;
  N:=100;
  Milliseconds;
  loop k do begin
    var max:=-1;
    var p:=1;
    var Y:=False;
    for i:integer:=1 to N do
      if (a[i]>max) and (In3(a[i])) then begin
        max:=a[i]; p:=i; Y:=True;
      end;
    if Y then begin
      //writeln(max); 
      //writeln('i=',p);
      end
    else
      //writeln('Элементы, содержащие цифру 3 отсутствуют')
    end;
  var t:=MillisecondsDelta;
  Writeln(t/k);
end.

Имеется попытка показать, что функциональное программирование по крайней мере не хуже тридиционного для языка Паскаль:

function Has3(n:Integer):boolean;
begin
  while n<>0 do begin
    if n mod 10=3 then begin Result:=True; Exit end;
    n:=n div 10; 
    end;
  Result:=False
end;

begin
  var a:=Arr(520,46904,58684,2215,83967,66560,96722,41600,16921,
        99150,1151,86738,63634,71238,13216,32406,49880,1558,75516,
        73929,7482,58804,47776,65890,47698,18548,26752,98776,82750,
        87389,23938,55437,86701,10204,93551,24241,16244,44138,25003,
        22798,83587,70257,65030,83983,81229,67478,78077,42619,73533,
        41772,49635,31721,77620,34630,63560,41716,99129,92794,54518,
        65419,39808,97947,58850,29532,75212,45715,37,53430,77687,
        88976,16163,5742,76556,52718,90343,37226,93774,63793,84661,
        80220,40472,84134,25243,40979,37755,92218,77818,52072,46645,
        51836,25112,23450,89621,59584,82991,85640,11407,35498,8771,35515);
  var k:=1000000;
  Milliseconds;
  loop k do begin
    var b:=a.Where(t->Has3(t)).ToArray;
    if b.Length>0 then begin
      var max:=b.Max; 
      var kk:=a.IndexOf(max); 
      //writeln('a[',kk+1,']=',max);
      end
    else
      writeln('Элементы, содержащие цифру 3 отсутствуют');
    end;
  var t:=MillisecondsDelta;  
  Writeln(t/k);
end.

Увы, но время выполнения данного кода в пять (!) раз больше, чем у традиционного. Можно ли тут что-то сделать, сохранив прозрачность алгоритма?

Ну, существенно не ускоришь. В задачах поиска индекса последовательности не так эффективны - нужны массивы.

И конечно основное время съедает запрос a.Where(Has3).Max

Давайте ещё раз: последовательности - не для всех задач, и не для всех задач они одинаково эффективны. Последовательности позволяют хорошо масштабировать некоторые задачи средней сложности где ручные алгоритмы плохо справляются .

Вас погубило создание массива b. Я попытался заменить массив на список, задавая ему изначальную длину =a.Length но это едва ли помогло(0.009->0.007). Вообще в производительности разумеется будет выигрывать написанное методами, которые делают только самое необходимое и ничего лишнего. А преимущество у функционального программирования только 1:[quote=“ibond, post:240, topic:263”] ибо надо думать о задаче [/quote] Вряд ли удастся переубедить человека который привык что эта программа выполняется не пол секунды а пол минуты ;).

Кстати я вроде всё старался прочитать, но не помню примера когда последовательности оказываются лучше чем ручной алгоритм. Вы только показали как с ними можно сделать красивый код вроде такого:

uses GraphABC;

function RandomPoints: sequence of Point;
begin
  while True do
    yield Pnt(Random(Window.Width),Random(Window.Height));
end;

begin
  RandomPoints.ForEach(p->Circle(p.x,p.y,Random(3,6)));
end.

Здравствуйте! Прежде всего позвольте мне выразить восхищение вашей работой (ABCPascal). Меня интересует несколько вопросов.

  1. Вы позиционируете свое творение как платформу (или язык?) для .NET программирования. Возможности вашей IDE - это подключение .Net классов и создание .Net класса я правильно понял? Т.е. .NET проекты IDE не создает. Все ограничивается WinForm, Concole и DLL.
  2. “Близким по идеологии к PascalABC.NET является язык RemObjects Oxygene”… К сожалению я так и не нашел НОРМАЛЬНОЙ и ПОЛНОЙ документации по этому языку. Даже на сайте RemObject (возможно, подскажите где ее найти?), но копаясь в этой теме наткнулся на пару интересных моментов. а) В превый раз Oxygene упоминается в DELPHI PRIZM (2009) как язык схожий с DELPHI для .NET Начиная с X6 версии RAD studio (embarcadero) мне не удалось найти в ее составе Prizm, возможно ее нет и в более ранних версиях (Этот вопрос сейчас уточняется мной у embarcadero как и вопрос о том поддерживают ли они .NET программирование). Я пока не знаю ответа, но если поддержки .net нету, то боюсь Pascal (Delphi) отойдет в небытие. б) Как ОБУЧАЮЩИЙ язык ABCPascal хорош. Правда…TP -> ABCPascal -> C++ Изумительная лестница от простого к сложному. Учитывая что в ABCPascal есть ну почти все что и в С++. Для меня не совсем понятно зачем ABCPascal связали с .net… Но это субъективный взгляд. —Под какую версию .Net Framework заточен ABCPascal??? p.s. Извиняюсь за несвязность изложенного, начинающий программист. От себя добавлю - хорошие библиотеки. Мне нравится ваш проект. Удачи в развитии.

Про массивы - это я уже понял, сделав замеры. Вроде бы можно обойтись

var b:=a.Where(t->Has3(t));

потому что массив не нужен, но преобразование .ToArray ускоряет решение почти вдвое.

Абсолютно “убили” реализация .ToString, а также процедуры Str() и функции IntToStr() - лишь обращение к ним для преобразования целого в строку на порядок (!) медленнее, чем весь цикл

 while n<>0 do begin
    if n mod 10=3 then begin Result:=True; Exit end;
    n:=n div 10; 
    end;

Но эти тормоза, видимо, уже заложены в .NET. Т.е. если в процедуре только написать var s:=n.ToString; то получим код, который почти вдесятеро дольше, выполняется, чем приведенный цикл.

Здравствуйте.

  1. Как язык. А какие NET-проекты кроме консольного и оконного имеете в виду?
  2. Да, надо убрать RemObjects Oxygene - он малораспространён. В своё время embarcadero присоединила к себе Prism, потом отсоединила - что то пошло не так. Delphi заняла свою нишу, учебной в этой нише уже нет.
  3. Связали с .NET потому что компиляторы под .NET писать просто и библиотек много.

Ну здесь побочный эффект In3 вызывается только если a[i] > max, поэтому в разы быстрее. ToArray на погоду не влияет

Ну так здесь дело в сборщиках мусора, а в самом алгоритме. Что еще раз доказывает, что надо думать о задаче, а не о ручном управлении памяти, где мы выграем 2% времени.

function Has3(n:Integer):boolean;
begin
  while n<>0 do begin
    if n mod 10=3 then begin Result:=True; Exit end;
    n:=n div 10; 
    end;
  Result:=False
end;

function &Where<T>(self: array of T; pred: (T,T)->(boolean, T)): array of T; extensionmethod;
begin
  var initial := default(T);
  var lst := new List<T>;
  for var i := 0 to self.Length - 1 do
  begin
    var item := self[i];
    var res := pred(item, initial);
    initial := res.Item2;
    if res.Item1 then
      lst.Add(item);
  end;
  Result := lst.ToArray();
end;

begin
  var a:=Arr(520,46904,58684,2215,83967,66560,96722,41600,16921,
        99150,1151,86738,63634,71238,13216,32406,49880,1558,75516,
        73929,7482,58804,47776,65890,47698,18548,26752,98776,82750,
        87389,23938,55437,86701,10204,93551,24241,16244,44138,25003,
        22798,83587,70257,65030,83983,81229,67478,78077,42619,73533,
        41772,49635,31721,77620,34630,63560,41716,99129,92794,54518,
        65419,39808,97947,58850,29532,75212,45715,37,53430,77687,
        88976,16163,5742,76556,52718,90343,37226,93774,63793,84661,
        80220,40472,84134,25243,40979,37755,92218,77818,52072,46645,
        51836,25112,23450,89621,59584,82991,85640,11407,35498,8771,35515);
  var k:=1000000;
  Milliseconds;
  loop k do begin
    var b:=a.Where((t,max)->((t > max) and Has3(t))?(true,t):(false,max));
    if b.Length>0 then begin
      //writeln('a[',kk+1,']=',max);
      end
    else
      writeln('Элементы, содержащие цифру 3 отсутствуют');
    end;
   writeln(Milliseconds);
  var t:=MillisecondsDelta;  
  Writeln(t/k);
end.

:slight_smile:

Программа “злого преподавателя” или как там его выполняется за 0.002 миллисекунд на итерация цикла, а ваша 0.007. Кстати когда я заменил в программе RAlex’a массив на список - получил тот же результат в 0.007. [quote=“ibond, post:248, topic:263”] ToArray на погоду не влияет [/quote] .ToArray преобразовывает алгоритм заложенный в sequence в массив, ускоряя всё в 2 раза, потому что в программе сначала проверяется if b.Length>0 then(кстати тут пожалуй надо было поставить if b.Any then), для вычисления кол-во элементов вычисляется вся последовательность, а потом она ещё раз вычисляется в b.Max. Ну а основная проблема программы RAlex’a в том что создаётся отдельный массив, в программе преподавателя его не было и если сделать без него то программа опять же работает с выходом ~0.002.

И ещё хотелось бы добавить про 2%. Вот вам пример правила “минимум глобальных переменных” и красивый код который оно даёт, с не мешающимися в остальном классе именами:

procedure p1(i: integer);
begin
  var i2 := i + 1;
  var i3 := i2 + 1;
  var i4 := i3 + 1;
end;

begin
  
  var LT := System.DateTime.Now;
  
  loop 100000000 do
    p1(1);
  
  writeln(System.DateTime.Now - LT);

end.

И её оналог с глобальными переменными:

var
  i2,i3,i4:integer;

procedure p1(i: integer);
begin
  i2 := i + 1;
  i3 := i2 + 1;
  i4 := i3 + 1;
end;

begin
  
  var LT := System.DateTime.Now;
  
  loop 100000000 do
    p1(1);
  
  writeln(System.DateTime.Now - LT);
  
end.

И вот уже разница в 2 раза! Не поймите меня не правильно, когда надо написать что то на скорую руку - такие “трюки” очень даже полезны, но надо знать когда это уместно.

Сейчас же вопрос был в том чтоб оптимизировать программу, а не сделать красивое нагромождение.

Глобальные переменные - зло.

Запустите в режиме Release по Shift-F9, отключив в Опциях компиляции все галочки - результат будет противоположным: в 4 раза быстрее работают локальные переменные

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

    var pp: integer->boolean := In3;
    for i:integer:=1 to N do
      if (pp(a[i])) and (a[i]>max) then begin
        max:=a[i]; p:=i; Y:=True;
      end;