в pascale все unchecked. указатели (на размерные типы) можно использовать без всяких флажков.
- Константы не
unchecked
. - Есть не мало случаев когда как раз надо
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). Меня интересует несколько вопросов.
- Вы позиционируете свое творение как платформу (или язык?) для .NET программирования. Возможности вашей IDE - это подключение .Net классов и создание .Net класса я правильно понял? Т.е. .NET проекты IDE не создает. Все ограничивается WinForm, Concole и DLL.
- “Близким по идеологии к 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; то получим код, который почти вдесятеро дольше, выполняется, чем приведенный цикл.
Здравствуйте.
- Как язык. А какие NET-проекты кроме консольного и оконного имеете в виду?
- Да, надо убрать RemObjects Oxygene - он малораспространён. В своё время embarcadero присоединила к себе Prism, потом отсоединила - что то пошло не так. Delphi заняла свою нишу, учебной в этой нише уже нет.
- Связали с .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.
Программа “злого преподавателя” или как там его выполняется за 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;