Версия PascalABC.NET 3.1

По комплексным. Попробовал делать расчеты электрических цепей, отлично все, очень удобно. Единственное, было бы весьма приятно (хотя совсем не обязательно) увидеть достаточно часто встречающийся в расчетах модуль комплексного числа, доступный и как x.Magnitude, и как длинное и неочевидное для начинающих Complex.abs(x), в более привычном виде abs(x).

Конечно, пришлось писать процедуру для вывода комплексных чисел, потому что вывод вида (13.994972221248, -0.00590055678917983) гораздо удобнее и нагляднее, когда значения выглядят примерно так: 13.995-i0.006. И тут ностальгически вспомнился форматный вывод Фортрана или ПЛ/1…

Print() удобен тем, что он разделяет пробелом выводимые значения, но это хорошо лишь для целых величин и, возможно, символов. А для вещественных это зло… Вот если бы имелся какой-то PrintReal, выводящий вещественные (с автоприведением к ним целочисленных) значения, у которого первый параметр задавал бы число знаков в дробной части (в целой не надо, потому что Print’ом таблицы все равно не рисуют), это было бы превосходно.

Пусть имеется такая программа:

// PascalABC.NET 3.1, сборка 1167 от 12.02.2016
begin
  var s:=Seq(6,2,8,1,4,9,3,7,5);
  var hs:=HSet(s);
  ss.Println
end.

Тут все понятно, просто и работает. А как просто и понятно сформировать набор hs, взяв каждый второй элемент из s? Или, взяв из s элементы стоящие по порядку седьмым, третьим, вторым и пятым? Ведь для типа IEnumerable индексного свойства не предусмотрено… Преобразовать s в массив и написать примерно так:

// PascalABC.NET 3.1, сборка 1167 от 12.02.2016
begin
  var s:=Seq(6,2,8,1,4,9,3,7,5);
  var a:=s.ToArray;
  var hs:=HSet(a[8],a[4],a[3],a[6]);
  hs.Println;
end.

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

// PascalABC.NET 3.1, сборка 1167 от 12.02.2016
begin
  var s:=SeqGen(20,1,t->t+1); // 1,2,3, ... 20
  var a:=s.ToArray;
  var hs:=HSet(a[1]);
  var i:=3;
  while i<20 do begin
    hs:=HSet(hs.Concat(HSet(a[i]))); // несуразно как-то
    Inc(i,2);
    end;
  hs.Println
end.

Ну, пока у нас нет срезов, - надо использовать фильтрацию с индексом.

begin
  var s := Seq(6,2,8,1,4,9,3,7,5);
  var hs := HSet(s.Where((x,i)->i mod 2 = 0));
  hs.Println
end.

Спасибо за красивое решение! Использовать лямбду с двумя параметрами, а работать только с одним в голову не пришло. Только для “каждый второй” надо условие на <> поменять или просто взять Odd(i). Тут же счет с нуля идет, а не с единицы.

Попутно вопрос возник. Или я чего-то не понимаю - и тогда все эти SeqGen - обезьяна с гранатой, или я все понимаю правильно, и это ошибка.

begin
  var s:=SeqGen(7,1,t->t+1);
  s.Select((x,i)->Rec(x,i)).Println;
  s.Select((x,i)->Rec(x,i)).Println;
end.

Выдача: 
(1,0) (2,1) (3,2) (4,3) (5,4) (6,5) (7,6)
(8,0) (9,1) (10,2) (11,3) (12,4) (13,5) (14,6)

А теперь так:

begin
  var s:=Seq(1,2,3,4,5,6,7);
  s.Select((x,i)->Rec(x,i)).Println;
  s.Select((x,i)->Rec(x,i)).Println;
end.

И выдача: 
(1,0) (2,1) (3,2) (4,3) (5,4) (6,5) (7,6)
(1,0) (2,1) (3,2) (4,3) (5,4) (6,5) (7,6)

Я понимаю. что лямбда t->t+1 “толкает” к наращиванию генерируемых значений на единицу (она с этой целью и писалась), понимаю, что механизм вычисления членов последовательности “ленивый” (и это отлично), но почему при повторном обращении к последовательности игнорируется установка начального значения в единицу? Когда SeqRandom - там вопросов нет, но тут-то?

Ну, это ошибка в реализации. Неожиданная - на ровном месте. Ищем.

11 posts were split to a new topic: О статических и динамических массивах

Ошибку с последовательностями исправили

Ну, это ошибка в реализации. Неожиданная - на ровном месте. Ищем.

Еще один “сюрпризец”. Неожиданный, раньше работало нормально.

// PascalABC.NET 3.1, сборка 1171 от 15.02.2016
type
  tM=array[1..3,1..3] of integer;

begin
  var a:array[1..3,1..3] of integer:=
    ((1,2,3),(4,5,6),(7,8,9));
  Writeln('a:  ',a);
  var b:tM:=((1,2,3),(4,5,6),(7,8,9));
  Writeln('b:  ',b);
end.

Результат выполнения программы:

a:  [[1,2,3],[4,5,6],[7,8,9]]
b:  ([[1,2,3],[4,5,6],[7,8,9]],1,3)

В сборке 1172 ошибка устранена.

Известно, что для нахождения суммы членов последовательности можно использовать метод .Sum, для нахождения среднего арифметического - метод .Average. А вот с произведением все оказывается далеко не так красиво. То ли его решили изначально в LINQ не вводить из-за возможности неконтролируемого арифметического переполнения в операции умножения целых (обычно в целях эффективности контроль переполнения разрядной сетки не делается), то ли еще какая-то есть причина, - но так, или иначе, метода .Prod у нас нет. И приходится выкручиваться. Поскольку разработчикам лучше, чем кому бы то ни было, известна внутренняя “кухня” реализации, хотелось бы получить рекомендацию, как эффективнее (и красивее) находить произведение членов числовой последовательности. И необязательно даже по критерию отбора: ведь его при необходимости можно организовать через предшествующий .Where.

Product это, как и Sum, как и многое другое, это экземпляр свёртки (fold, в Линке это называется Aggregate). Примерно так.

a.Aggregate(1, (prod, x) -> prod * x);

(Надеюсь, с синтаксисом нигде не напутал, WDE не работает, чтобы проверить.)

Есть известная байка на схожую тему в мире функционального программирования.

3 лайка

fac n = product [1…n] - вот это как раз то, чего бы хотелось увидеть))) А байку оценил, “внушаить” (с)

И - да, спасибо, работает выражение.

Гхм, такого количества способов я не видел. Спасибо! :smile: Интересный материал.

Print() удобен тем, что он разделяет пробелом выводимые значения, но это хорошо лишь для целых величин и, возможно, символов. А для вещественных это зло… Вот если бы имелся какой-то PrintReal, выводящий вещественные (с автоприведением к ним целочисленных) значения, у которого первый параметр задавал бы число знаков в дробной части (в целой не надо, потому что Print’ом таблицы все равно не рисуют), это было бы превосходно.

В .Net это делается переопределением метода ToString или добавлением строки форматирования к тому же complex.ToString("{0:MyComplex}"). Не много замарочливо, но возможно каждому самому под себя делать любой вывод в зависимости от типа Возможно ли это реализовать тут?

Всё, что есть в библиотеке .NET, будет работать и тут

Обновился сегодня до последней версии и заметил одну странность - есть у меня один проект WinForms - компилируется он успешно, а при запуске падает по System.ArgumentNullException: Value cannot be null.

Внутренняя ошибка компилятора в модуле [pabcnetc.exe] :'System.Exception: System.ArgumentNullException: Value cannot be null.
Parameter name: key
   at System.Collections.Generic.Dictionary`2.FindEntry(TKey key)
   at System.Collections.Generic.Dictionary`2.ContainsKey(TKey key)
   at PascalABCCompiler.NETGenerator.ILConverter.ConvertFromTree(IProgramNode p, String TargetFileName, String SourceFileName, CompilerOptions options, String[] ResourceFiles)
   at PascalABCCompiler.CodeGenerators.Controller.Compile(IProgramNode ProgramTree, String TargetFileName, String SourceFileName, CompilerOptions options, Hashtable StandartDirectories, String[] ResourceFiles)
   at PascalABCCompiler.Compiler.Compile()'

и потом уже ничего не собирается. при этом собранный exe’шник запускается и работает нормально, проблема только при попытке запуска прямо из IDE. раньше это работало.

Это странно. У нас все проекты WinForms работают

А это пасхалочка от разработчиков такая? промахнулся и качай в 10 раз больше?) а я нашел) Случайно увидел что ссылка при наведении не целиком подсвечивается.

Тут вот у @Ret_ReT была проблема с запуском приложения с использованием CRT, я попробовал запустить свой проект winForms без связи с оболочкой, появилась консоль ProgramRunner.exe с единственной строкой - программа завершена, нажмите любую клавишу… - как будто запускается пустая программа типа begin end. То есть вроде бы ничего общего, но на мысли наталкивает.

В последних версиях появились операции, порождающие из обычной последовательности “последовательности последовательностей” или разбивающие её на несколько последовательностей. Возник вопрос: как эффективно “собрать назад” такие конструкции?

// PascalABC.NET 3.1, сборка 1200 от 13.03.2016
begin
  var a:=Range(0,11); // Sequence of integer (по Intellisence)
  Writeln(a); // [0,1,2,3,4,5,6,7,8,9,10,11]
  
  var b:=a.SplitAt(4); // System.Tuple<integer>
  Writeln(b); // ([0,1,2,3],[4,5,6,7,8,9,10,11])
  var b1:=b.Item1+b.Item2; // integer - ОШИБКА Intellisence?
  Writeln(b1); // [0,1,2,3,4,5,6,7,8,9,10,11]
   
  var c:=a.Batch(4); // Sequence of integer
  Writeln(c); // [[0,1,2,3],[4,5,6,7],[8,9,10,11]]
  // как все это собрать "назад" в исходную последовательность?
end.
2 лайка