Инструменты пользователя

Инструменты сайта


bb:redbook:202

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
bb:redbook:202 [2016/09/08 21:12]
prospero78 [2.5 Общий вид программы]
bb:redbook:202 [2020/10/29 07:08] (текущий)
Строка 2: Строка 2:
  
 ==== 1. Задача отбора ==== ==== 1. Задача отбора ====
-Это одна из классических задач в программировании — это отбор данных. Задачи такие возникают с завидной регулярностью. Например на [[https://ru.wikipedia.org/wiki/Большой_адронный_коллайдер|Большом адронном коллайдере]] (**БАК**) производится столкновение двух бозонов. И операция эта повторяется //несколько миллиардов// раз. При этом в 85% случаев, бозоны не сталкиваются друг с другом, а пролетают мимо. Они ударяются в стенки детектора столкновений, нагревают его, но толку от таких "мимо-столкновений" нет. Но остаются ещё 15% бозонов, которые всё-таки сталкиваются. При попытке рассмотреть поближе, как они столкнулись, из этих оставшихся 15% столкновений — 85% столкновений оказывается не столкновение бозонов и бозонов, а скажем нуклонов и лептонов. И эти столкновения тоже надо отсеять и т. д. В конечном итоге, после всех отсевов столкновений //сотен миллиардов// частиц, на доказательство существования бозона [[https://ru.wikipedia.org/wiki/Бозон_Хиггса|Хиггса]] приходится //всего// 10 тыс. столкновений. Мало? Безусловно. Достаточно? Ну, видимо, да. Всё-таки 10 тыс. случаев рождения **бозона Хиггса**, хоть и по косвенным признакам — но зафиксировано было.+Это одна из классических задач в программировании — это отбор данных. Задачи такие возникают с завидной регулярностью. Например на [[https://ru.wikipedia.org/wiki/Большой_адронный_коллайдер|Большом адронном коллайдере]] (**БАК**) производится столкновение двух бозонов. И операция эта повторяется //несколько миллиардов// раз. При этом в 85% случаев, бозоны не сталкиваются друг с другом, а пролетают мимо. Они ударяются в стенки детектора столкновений, нагревают его, но толку от таких "мимо-столкновений" нет. Но остаются ещё 15% бозонов, которые всё-таки сталкиваются. При попытке рассмотреть поближе, как они столкнулись, из этих оставшихся 15% столкновений — 85% столкновений оказывается не столкновение бозонов и бозонов, а скажем нуклонов и лептонов. И эти столкновения тоже надо отсеять и т. д. В конечном итоге, после всех отсевов столкновений //сотен миллиардов// частиц, на доказательство существования бозона [[https://ru.wikipedia.org/wiki/Бозон_Хиггса|Хиггса]] приходится //всего// 10 тыс. столкновений. Мало? Безусловно. Достаточно? Ну, видимо, да. Всё-таки 10 тыс. случаев рождения **бозона Хиггса**, хоть и по косвенным признакам — но зафиксировано было. Да к тому же, 10 тыс. столкновений -- это "пять сигма". Физики оценят!))
 ==== 2. Пороговый отбор чисел ==== ==== 2. Пороговый отбор чисел ====
 Задача: на вход радиоприёмника поступает ослабленный радиосигнал, вместе с полезным сигналом в приёмник проникает шумовая помеха. Необходимо из массива входных сигналов выделить полезный сигнал. Сигнал поступает в форме [[https://ru.wikipedia.org/wiki/%D0%90%D0%B7%D0%B1%D1%83%D0%BA%D0%B0_%D0%9C%D0%BE%D1%80%D0%B7%D0%B5|азбуки Морзе]]. Дополнительные данные: Задача: на вход радиоприёмника поступает ослабленный радиосигнал, вместе с полезным сигналом в приёмник проникает шумовая помеха. Необходимо из массива входных сигналов выделить полезный сигнал. Сигнал поступает в форме [[https://ru.wikipedia.org/wiki/%D0%90%D0%B7%D0%B1%D1%83%D0%BA%D0%B0_%D0%9C%D0%BE%D1%80%D0%B7%D0%B5|азбуки Морзе]]. Дополнительные данные:
  
-  * символ "S" — "#.#.#" +  * литера "S" — "#.#.#" 
-  * символ "О" — "###"+  * литера "О" — "###"
   * уровень шумового сигнала — ниже 50 единиц.   * уровень шумового сигнала — ниже 50 единиц.
   * уровень помехи создаваемый грозой — выше 1000 единиц.   * уровень помехи создаваемый грозой — выше 1000 единиц.
Строка 23: Строка 23:
 <code oberon2> <code oberon2>
 CONST CONST
- _sig_max = 256; (* максимальное значение счётчика для массива *)+ _разм = 256; (* максимальное значение счётчика для массива *)
 VAR VAR
-p1: SHORTINT; (* нижний порог для шума *) +цШум_низ: SHORTINT; (* нижний порог для шума *) 
-p2: SHORTINT; (* верхний порог для шума *) +цШум_верх: SHORTINT; (* верхний порог для шума *) 
-sig: ARRAY _sig_max OF SHORTINT; (* массив полученных замеров сигнала *) +мкцСигнал: ARRAY _разм OF SHORTINT; (* массив полученных замеров сигнала *) 
-i: INTEGER; (* счётчик чтения входного потока, чтобы не выйти за пределы массива *) +цИтер: INTEGER; (* счётчик чтения входного потока, чтобы не выйти за пределы массива *) 
-tmp: INTEGER (* временная переменная для хранения числа, так как In.Int имеет свои особенности *)+цВрем: INTEGER (* временная переменная для хранения числа, так как In.Int имеет свои особенности *)
 </code> </code>
  
Строка 35: Строка 35:
 После задания входных структур давайте введём данные: После задания входных структур давайте введём данные:
 <code oberon2> <code oberon2>
-PROCEDURE GetSignal;+PROCEDURE Сигнал_Получ;
 BEGIN BEGIN
- FOR := 0 to(_sig_max - 1) DO (* цикл обнуления исходного массива сигналов *) + FOR цИтер := 0 TO (_разм - 1) DO (* цикл обнуления исходного массива сигналов *) 
- sig[i] := 0+ мкцСигнал[цИтер] := 0
  END;  END;
- := 0; (* предварительное обнуление счётчика *)+ цИтер := 0; (* предварительное обнуление счётчика *)
  In.Open; (* открываем входной поток на чтение *)  In.Open; (* открываем входной поток на чтение *)
- WHILE (In.Done) & (_sig_max) (* охрана цикла *) + WHILE (In.Done) & (цИтер _разм) (* охрана цикла *) 
- In.Int(tmp); (* чтение сигнала в цикле *) + In.Int(цВрем); (* чтение сигнала в цикле *) 
- sig[i] := SHORT(tmp); (* принудительное преобразование типа *) + мцСигнал[цИтер] := SHORT(цВрем); (* принудительное преобразование типа *) 
- INC(i) (* приращение счётчика цикла с условием по входу *)+ INC(цИтер) (* приращение счётчика цикла с условием по входу *)
  END;  END;
-END GetSignal;+END Сигнал_Получ;
 </code> </code>
  
-Для облегчения контроля ввода данных в тексте были определены две дополнительных переменных, о которых пока не было сказано ни слова. Это константа ''_sig_max'' и счётчик цикла ''i''. Константа нужна для того, что один раз её определив, не нужно было выискивать её по всему тексту. Если потребуется под массив выделить больше места — в следующий раз будет //достаточно переопределить константу//. Переменная счётчика цикла нам бы потребовалась в любом случае. Также в начале процедуры ввода нам //потребовалось обнулить весь массив//, при этом надо обратить внимание, что в целочисленном цикле константа ''_sig_max'' уменьшена на ''1''. Это связано только с тем, что диапазон массива сигналов //индексируется// ''от 0 до 255'' (т. е. 256 элементов). Если этого не сделать, то попытка обратиться к элементу массива с номером 256 //закончится крахом//. Это //несколько необычно для людей//, привыкших считать что автобусов, домов и квартир с номером ''0'' не существует. Чуть позже будет показано, как этот несколько странный момент обратить в преимущество.+Для облегчения контроля ввода данных в тексте были определены две дополнительных переменных, о которых пока не было сказано ни слова. Это константа ''разм'' и счётчик цикла ''цИтер''. Константа нужна для того, что один раз её определив, не нужно было выискивать её по всему тексту. Если потребуется под массив выделить больше места — в следующий раз будет //достаточно переопределить константу//. Переменная счётчика цикла нам бы потребовалась в любом случае. Также в начале процедуры ввода нам //потребовалось обнулить весь массив//, при этом надо обратить внимание, что в целочисленном цикле константа ''_разм'' уменьшена на ''1''. Это связано только с тем, что диапазон массива сигналов //индексируется// ''от 0 до 255'' (т. е. 256 элементов). Если этого не сделать, то попытка обратиться к элементу массива с номером 256 //закончится крахом//. Это //несколько необычно для людей//, привыкших считать что автобусов, домов и квартир с номером ''0'' не существует. Чуть позже будет показано, как этот несколько странный момент обратить в преимущество.
  
-После целочисленного цикла, переменная ''i'' опять получает присвоение, так как после целочисленного цикла она будет равна "255".+После целочисленного цикла, переменная ''цИтер'' опять получает присвоение, так как после целочисленного цикла она будет равна "255".
  
-Цикл с условием на входе имеет сложное условие. Цикл будет повторяться до тех пор, пока есть данные на входе (''In.Done:=TRUE''), и не закончится массив (''i:=255''). Т. е. вовсе не факт, что массив будет использован полностью. И если дело будет обстоять именно так, то такой способ организации ввода данных не является оптимальным ((Для хранения данных, число которых заранее неизвестно используется структура, получившая название "связанный список", или проще "цепочка". У него тоже есть недостатки, но в ряде случаев может оказаться более удобным.)). Любое условие, которое //ограничивает// (//направляет//) основную ветку выполнения программы называется //охраной//, что в стане **Паскаля** широко применяется (см. комментарий при объявлении цикла с условием на входе). Кроме того, впервые встречается ключевое слово ''SHORT''. Это встроенное средство **Компонентного Паскаля** позволяет привести тип ''INTEGER'' к типу ''SHORTINT'' (исключительно для уменьшения занимаемого объёма оперативной памяти компьютера). Порядок приведения чисел был рассмотрен ранее.+Цикл с условием на входе имеет сложное условие. Цикл будет повторяться до тех пор, пока есть данные на входе (''In.Done:=TRUE''), и не закончится массив (''цИтер := 255''). Т. е. вовсе не факт, что массив будет использован полностью. И если дело будет обстоять именно так, то такой способ организации ввода данных не является оптимальным ((Для хранения данных, число которых заранее неизвестно используется структура, получившая название "связанный список", или проще "цепочка". У него тоже есть недостатки, но в ряде случаев может оказаться более удобным.)). Любое условие, которое //ограничивает// (//направляет//) основную ветку выполнения программы называется //охраной//, что в стане **Паскаля** широко применяется (см. комментарий при объявлении цикла с условием на входе). Кроме того, впервые встречается ключевое слово ''SHORT''. Это встроенное средство **Компонентного Паскаля** позволяет привести тип ''INTEGER'' к типу ''SHORTINT'' (исключительно для уменьшения занимаемого объёма оперативной памяти компьютера). Порядок приведения чисел был рассмотрен ранее.
  
 По завершении процедуры ввода, выполнять закрытие входного потока //не требуется//. Итак, мы ввели данные с шумами, теперь их необходимо обработать. По завершении процедуры ввода, выполнять закрытие входного потока //не требуется//. Итак, мы ввели данные с шумами, теперь их необходимо обработать.
Строка 66: Строка 66:
 Вот пример того, как можно отсеять помехи: Вот пример того, как можно отсеять помехи:
 <code oberon2> <code oberon2>
-PROCEDURE LimitSig;+PROCEDURE Сигн_Ограничить;
 BEGIN BEGIN
- p1 := 50; + цШум_низ  := 50; 
- p2 := 1000; + цШум_Верх := 1000; 
- FOR := 0 TO _sig_max - 1 DO + FOR цИтер := 0 TO _разм - 1 DO 
- IF sig[i] < p1 THEN + IF sig[цИтер ] < цШум_низ THEN 
- sig[i] := 0 + sig[цИтер ] := 0 
- ELSIF sig[i] > p2 THEN + ELSIF sig[цИтер ] > цШум_Верх THEN 
- sig[i] := 600+ sig[цИтер ] := 600
  ELSE  ELSE
- sig[i] := 500+ sig[цИтер ] := 500
  END;  END;
  END;  END;
-END LimitSig;+END Сигн_Ограничить;
 </code> </code>
  
Строка 85: Строка 85:
  
 В целом представленная процедура имеет общепринятое название в радиотехнике "восстановление формы цифрового сигнала". В целом представленная процедура имеет общепринятое название в радиотехнике "восстановление формы цифрового сигнала".
 +
 +Также обратите внимание на то, что переменные ''цШум Низ'' и ''цШум верх'' на самом деле не изменяются и их можно было определить как константы. Это будет несколько лучше, так как константы нельзя изменять (по ошибке вы можете попытаться это сделать). Кроме того, устанавливаемые уровни сигналов -- по сути, тоже константы. И чтобы не искать их по всему коду -- можно тоже вынести в одно место. 
  
  
Строка 92: Строка 94:
 Часть символов ("#" и ".") уже представлено по условию задачи, и они обозначают "есть сигнал" и "нет сигнала" соответственно. Но у нас появился ещё один сигнал, значение которого равно "600". И его надо как-то тоже обозначать. Поскольку он превышает нормальный уровень нужно визуально указать на этот факт. Очень удобно будет использовать символ "^". Ниже примерный вид процедуры, который мог бы это сделать: Часть символов ("#" и ".") уже представлено по условию задачи, и они обозначают "есть сигнал" и "нет сигнала" соответственно. Но у нас появился ещё один сигнал, значение которого равно "600". И его надо как-то тоже обозначать. Поскольку он превышает нормальный уровень нужно визуально указать на этот факт. Очень удобно будет использовать символ "^". Ниже примерный вид процедуры, который мог бы это сделать:
 <code oberon2> <code oberon2>
-PROCEDURE OutSig;+PROCEDURE Сигнал_Печать;
  CONST  CONST
- _p = " "; (* пауза в передаче сигнала *)+ _п = " "; (* пауза в передаче сигнала *)
  _s = "#"; (* полезный сигнал *)  _s = "#"; (* полезный сигнал *)
- _m = "^"; (* молния? *)+ _м = "^"; (* молния? *)
 BEGIN BEGIN
- Log.String('[Начало приёма]'); Log.Ln; + мЛог.String('[Начало приёма]'); мЛог.Ln; 
- FOR := 0 TO _sig_max - 1 DO + FOR цИтер := 0 TO _разм - 1 DO 
- IF sig[i] = 0 THEN + IF мцСигнал[i] = 0 THEN 
- Log.String(_p+ мЛог.String(_п
- ELSIF sig[i] = 500 THEN + ELSIF мцСиг[i] = 500 THEN 
- Log.String(_s)+ мЛог.String(_s)
  ELSE  ELSE
- Log.String(_m)+ мЛог.String()
  END;  END;
  END;  END;
- Log.Ln; Log.String('[Конец приёма]'); Log.Ln + мЛог.Ln; мЛог.String('[Конец приёма]'); мЛог.Ln 
-END OutSig;+END Сигнал_Печать;
 </code> </code>
  
 ==== 2.5 Общий вид программы ==== ==== 2.5 Общий вид программы ====
 Для запуска всей программы нужно определить запускающую процедуру с признаком экспорта. Пусть она по традиции будет называться "Start". Также нельзя забывать про правило упреждающего объявления (вспоминаем содержание прошлых глав). Полный текст программы ниже. Для запуска всей программы нужно определить запускающую процедуру с признаком экспорта. Пусть она по традиции будет называться "Start". Также нельзя забывать про правило упреждающего объявления (вспоминаем содержание прошлых глав). Полный текст программы ниже.
 +
 +  Привет9.odc
 + 
 <code oberon2> <code oberon2>
-MODULE TestHello9;+MODULE КнигаПривет9;
  (* это программа на языке  (* это программа на языке
  Компонетный Паскаль. Она показывает  Компонетный Паскаль. Она показывает
  как можно вводить данные и обрабатывать их*)  как можно вводить данные и обрабатывать их*)
  
- IMPORT In, Log, Math;+ IMPORT мВв := In,  
 + мЛог := Log, 
 + Math;
  
  CONST  CONST
- _sig_max = 256;+ _разм = 256; 
 +
  VAR  VAR
- p1: SHORTINT; + цШум_низ: SHORTINT; 
- p2: SHORTINT; + цШум_верх: SHORTINT; 
- sig: ARRAY _sig_max OF SHORTINT; + мцСигнал: ARRAY _разм OF SHORTINT; 
- i: INTEGER; + цИтер: INTEGER; 
- tmp: INTEGER;+ цВрем: INTEGER;
  
- PROCEDURE GetSignal;+ PROCEDURE Сигнал_Получ;
  BEGIN  BEGIN
- FOR := 0 TO ( _sig_max - 1) DO + FOR цИтер := 0 TO(_разм - 1) DO 
- sig[i] := 0+ мцСигнал[цИтер] := 0
  END;  END;
- := 0; + цИтер := 0; 
- In.Open; + мВв.Open; 
- WHILE (In.Done) & ( _sig_max ) DO + WHILE (мВв.Done) & (цИтер _разм) DO 
- In.Int(tmp); + мВв.Int(цВрем); 
- sig[i] := SHORT(tmp); + мцСигнал[цИтер] := SHORT(цВрем); 
- INC(i)+ INC(цИтер)
  END;  END;
- END GetSignal;+ END Сигнал_Получ;
  
- PROCEDURE LimitSig;+ PROCEDURE Сигнал_Ограничить;
  BEGIN  BEGIN
- p1 := 50; + цШум_низ := 50; 
- p2 := 1000; + цШум_верх := 1000; 
- FOR := 0 TO _sig_max - 1 DO + FOR цИтер := 0 TO _разм - 1 DO 
- IF sig[i] < p1 THEN + IF мцСигнал[цИтер] < цШум_низ THEN 
- sig[i] := 0 + мцСигнал[цИтер] := 0 
- ELSIF sig[i] > p2 THEN + ELSIF мцСигнал[цИтер] > цШум_верх THEN 
- sig[i] := 600+ мцСигнал[цИтер] := 600
  ELSE  ELSE
- sig[i] := 500+ мцСигнал[цИтер] := 500
  END;  END;
  END;  END;
- END LimitSig;+ END Сигнал_Ограничить;
  
- PROCEDURE OutSig;+ PROCEDURE Сигнал_Печать;
  CONST  CONST
- _p = "."; (* пауза в передаче сигнала *)+ _п = "."; (* пауза в передаче сигнала *)
  _s = "#"; (* полезный сигнал *)  _s = "#"; (* полезный сигнал *)
- _m = "^"; (* молния? *)+ _м = "^"; (* молния? *)
  BEGIN  BEGIN
- Log.String('[Начало приёма]'); Log.Ln; + мЛог.String('[Начало приёма]'); мЛог.Ln; 
- FOR := 0 TO _sig_max - 1 DO + FOR цИтер := 0 TO _разм - 1 DO 
- IF sig[i] = 0 THEN + IF мцСигнал[цИтер] = 0 THEN 
- Log.String(_p+ мЛог.String(_п
- ELSIF sig[i] = 500 THEN + ELSIF мцСигнал[цИтер] = 500 THEN 
- Log.String(_s)+ мЛог.String(_s)
  ELSE  ELSE
- Log.String(_m)+ мЛог.String()
  END;  END;
  END;  END;
- Log.Ln; Log.String('[Конец приёма]'); Log.Ln + мЛог.Ln; мЛог.String('[Конец приёма]'); мЛог.Ln 
- END OutSig;+ END Сигнал_Печать;
  
- PROCEDURE Start*;+ PROCEDURE Старт*;
  VAR  VAR
  BEGIN  BEGIN
- GetSignal+ Сигнал_Получ
- LimitSig+ Сигнал_Ограничить
- OutSig + Сигнал_Печать 
- END Start;+ END Старт;
  
 BEGIN BEGIN
-END TestHello9.+END КнигаПривет9.
 </code> </code>
   
-В процедуре ''Start'' определены последовательные вызовы для обработки цифрового сигнала. Код разбит на довольно мелкие процедуры, что вполне позволяет оценить, что делает каждая из них даже без комментариев. +В процедуре ''Старт'' определены последовательные вызовы для обработки цифрового сигнала. Код разбит на довольно мелкие процедуры, что вполне позволяет оценить, что делает каждая из них даже без комментариев. 
 +Кроме того, обратите внимание, что литера "О" у нас нигде не используется, а значит она не нужна в константах, но это становится понятно, только получения рабочего кода. 
 +И обратите внимание, что все три вызова внутренних процедур внутри процедуры ''Старт'' есть ничто иное, как прямое указание-подсказка на создание типа ''тСигнал'', с привязкой этих процедур к этому типу.
  
 ==== 2.6 Исходные данные и результат ==== ==== 2.6 Исходные данные и результат ====
 Пример выделения данных для ввода в программу. Пример выделения данных для ввода в программу.
 В качестве исходных данных предлагаются следующие числа: В качестве исходных данных предлагаются следующие числа:
 +<code>
 +(*)TestHello9.Start
 +
 +5 8 78 40 123 32 465 1 322 567 401 0 234 32 658 23 61 23 14 18 22 34 2 2 18 32 44 41
 +49 51 48 67 2 1320 930 999 30 254 29 171 25 160 2 5 4 6 7 8 1350 4380 2356 2 2 2 2 2
 +</code>
  
 Чтобы программа смогла их получить на вход, необходимо выделить их, и нажать на КОММАНДЕР (как на врезке). Чтобы программа смогла их получить на вход, необходимо выделить их, и нажать на КОММАНДЕР (как на врезке).
Строка 202: Строка 217:
 В результате компиляции и выполнения программы будет выведена следующая информация: В результате компиляции и выполнения программы будет выведена следующая информация:
  
 +  компилируется "КнигаПривет9"   588   524
 +  старый модуль КнигаПривет9 выгружен
 +  [Начало приёма]
 +  ..#.#.#.###.#.#.#............#.#.^##.#.#.#......^^^............................................................
 +  ..............................................................................................................
 +  ...................................
 +  [Конец приёма]
  
-Обратите внимание на размер всей программы: 588 байт. 
- 
-Из выведенного сигнала видно, что была передана комбинация букв: "SOS SOS O". В первом случае сигнал был детектирован(выделен) точно. Во втором случае, в символ "О", видимо, вмешалась гроза, а в третьем случае сигнал трижды зашкаливал, и скорей всего, смысловой нагрузки не несёт. Вполне возможно, что в этот момент рядом работал мобильный телефон(( Сигнал SOS принят как международный, и буквально означает «спасите наши души». Существует целый стандарт, который описывает все параметры такого сигнала, и порядок действий при его приёме. Подробнее можно почитать в Википедии. Возможно, кто-то из читающих эту главу таким образом в будущем спасёт не одну человеческую жизнь. )). 
  
 +Обратите внимание на размер всей программы: **588 байт**.
  
-——————————————————+Из выведенного сигнала видно, что была передана комбинация букв: "SOS SOS O". В первом случае сигнал был детектирован(выделен) точно. Во втором случае, в символ "О", видимо, вмешалась гроза, а в третьем случае сигнал трижды зашкаливал, и скорей всего, смысловой нагрузки не несёт. Вполне возможно, что в этот момент рядом работал мобильный телефон(( Сигнал **SOS** принят как международный, и буквально означает «спасите наши души». Существует целый стандарт, который описывает все параметры такого сигнала, и порядок действий при его приёме. Подробнее можно почитать в [[https://ru.wikipedia.org/wiki/SOS|Википедии]]. Возможно, кто-то из читающих эту главу таким образом в будущем спасёт не одну человеческую жизнь. )).
  
 +==== Задание ====
 +   * Сделайте так, чтобы литера "О" не была бесполезным определением.
 +   * Доработайте так, чтобы вместо морзянки выводились литеры
 +   * Попробуйте сделать с помощью типа ''тСигнал'' с привязкой процедур.
bb/redbook/202.1473358376.txt.gz · Последнее изменение: 2020/10/29 07:08 (внешнее изменение)