-Поиск по дневнику

Поиск сообщений в blackspace

 -Подписка по e-mail

 

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 23.07.2009
Записей: 95
Комментариев: 8
Написано: 104





Без заголовка

Четверг, 10 Сентября 2009 г. 17:04 + в цитатник
Отладка программ

Если Вы пытались отлаживать какую-либо программу в Turbo Vision, Вы наверняка убедились, что трассировка (пошаговое прослеживание логики работы) таких программ весьма неэффективна. Вызвано это двумя обстоятельствами. Во-первых, значительная часть библиотеки Turbo Vision скрыта от Вас: библиотека поставляется в TPU-файлах, прослеживание работы которых невозможно. Во-вторых, в Turbo Vision используется принцип отделения логики создания видимых элементов от логики обработки связанных с ними событий: как только видимый элемент активизируется вызовом Execute, начинает работать его метод HandleEvent, который может породить целую цепочку непрослеживаемых трассировкой действий программы.

Ключом к решению проблемы отладки программ в Turbo Vision является расстановка точек контроля в наследуемых методах HandleEvent. Если программа не хочет открывать диалоговое окно или не реагирует на нажимаемую кнопку, следует прежде всего убедиться в том, что Ваши действия действительно порождают нужное событие.

Может случиться, что установленная контрольная точка не будет реагировать вообще или, наоборот, будет активизироваться слишком часто. Если точка не активизируется, это означает, что Ваш обработчик событий просто «не видит» событие. В этом случае необходимо убедиться в том, что поле EventMask видимого объекта содержит маску, позволяющую ему реагировать на событие нужного вида. Другой причиной «исчезновения» события может быть его перехват (и обработка) другим видимым элементом. Это может быть вызвано различными обстоятельствами. Например, Вы могли ошибочно связать две разные команды с одной константой или используете команду, которую использует также другой видимый элемент. Кроме того, обычно в наследуемых методах HandleEvent вызывается обработчик событий объекта-родителя, который может «украсть» событие у Вашего обработчика. В таких ситуациях бывает достаточно сделать вызов родительского метода после того, как событие будет обработано Вами.

Если контрольная точка активизируется слишком часто, значит Вы установили ее неправильно. Например, если Вы установили эту точку внутри метода TGroup.Execute, точка будет непрерывно активизироваться, т.к. значительная часть времени работы программы тратится на ожидание события. Если Вам все-таки требуется установить контрольную точку именно в этом месте, сделайте ее условной, чтобы она не реагировала на пустые или ненужные события.

Иногда запущенная программа «зависает», т.е. перестает реагировать на любые действия пользователя. Такие ошибки отлаживать труднее всего. Если программа «зависла», попытайтесь прежде всего локализовать то место, в котором это происходит. Для этого обычно используется расстановка контрольных точек в подозрительных местах программы. Следует помнить, что в Turbo Vision «зависания» связаны в основном с тремя видами ошибок:
освобождается динамический объект, который входил в состав ранее освобожденной динамической группы;
читаются данные из потока в ошибочно зарегистрированный объект (объект имеет неуникальный регистрационный номер);
элемент коллекции ошибочно трактуется как элемент другого типа. Ошибки первого вида встречаются наиболее часто. Например, прогон следующего невинного на первый взгляд варианта программы приводит к зависанию:

Uses Objects,Views;

var

G1, G2: PGroup;

R: TRect;

begin

R.Assign(10,5,70,20) ;

Gl := New(PGroup, Init(R));

R.Grow(-10, -3) ;

G2 := New(PGroup, Init(R));

G1.Insert(G2);

Dispose(G1, Done);

Dispose(G2, Done) {Здесь программа "зависнет"!}

end.

Заметим, что перестановка операторов Dispose местами приводит к корректному варианту, т.к. метод G1.Done умеет контролировать освобождение своего подэлемента G2 и не освобождает его вторично. Во всех случаях оператор Dispose (G2, Done) излишен: освобождение группы вызывает автоматическое освобождение всех ее подэ-лементов.

Поскольку динамическая память используется в Turbo Vision очень интенсивно, полезно предусмотреть в отладочном варианте программы визуализацию ее размера. Для этого можно использовать такой объект THeapView:

Unit HeapView;

Interface

Uses Dialogs,Objects;

type

PHeapView = THeapView;

THeapView = object(TStaticText)

Constructor Init(var R: TRect);

Procedure Update;

end;

Implementation

Constructor THeapView.Init;

var

S: String;

begin

Str(MemAvail,S);

Inherited lnit(R,#3+S)

end;

Procedure THeapView.Update;

var

S: String;

begin

Str(MemAvail,S);

DisposeStr(Text);

Text := NewStr(#3+S);

Draw

end;

end.

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

Uses Objects,Views,App, HeapView;

var

H: PHeapView;{Окно для MemAvail}

W: PWindow;

G: PGroup;

R: TRect;

P: TApplication;{Стандартная программа}

begin

P.Init;

R.Assign(70,0,80,1);{Верхний правый угол}

New(H, Init(R));{Создаем окно контроля}

P.Insert(H);{Помещаем его на экран}

ReadLn; {Пауза - показываем начальный размер кучи}

R.Assign(10,5,70,20);

W := New(PWindow,Init(R,'',0)); {Создаем окно}

R.Assign(5,3,55,12);

G := New(PGroup, Init(R));

W.Insert(G); {Вставляем в окно группу}

DeskTop.Insert(W); {Выводим на экран}

Н.Update; {Обновляем окно контроля}

ReadLn; {Пауза - размер кучи перед освобождением}

Dispose(W, Done); {Освобождаем окно и группу}

НА.Update; {Обновляем окно контроля}

ReadLn; {Пауза - размер после освобождения}

Р.Done

end.

Для получения текущего значения общего размера кучи используется вызов метода THeapView.Update в нужных местах программы. Вы можете автоматизировать обновление окна контроля, если включите вызов Update в перекрываемый метод TProgramIdle. В следующем варианте показан способ отображения MemAvail в фоновом режиме. Кроме того, в программе иллюстрируется возможное использование функции MessageBox.

{$Х+} {Используется расширенный синтаксис вызова функции MessageBox}

Uses Objects,Views,App,HeapView,MsgBox;

type

MyApp = object (TApplication)

Procedure Idle; Virtual;

end;

var

H: PHeapView;

Procedure MyApp.Idle;

begin

H^.Update

end;

var

W: PWindow;

G: PGroup;

R: TRect;

P: MyApp;

begin

P.Init;

R.Assign(70,0,80,1);

New(H,Init(R));

P.Insert(H);

MessageBox(#3'Размер кучи до размещения',NIL,0);

R.Assign(10,5,70,20) ;

W := New(PWindow, Init(R,'',0));

R.Assign(5,3,55,12) ;

G := New(PGroup, Init(R));

WA.lnsert(G);

DeskTop.Insert(W);

MessageBox(#3'Размер кучи после размещения', NIL,0);

Dispose(W, Done);

MessageBox(#3'Размер кучи после освобождения', NIL,0);

Р.Done

end.

Константа #3 вставляется в начало строки сообщения в том случае, когда требуется центрировать эту строку (расположить ее симметрично относительно границ окна сообщения).

Без заголовка

Четверг, 10 Сентября 2009 г. 17:04 + в цитатник
Обработка ошибок инициации и модальных состояний

Каждый видимый элемент наследует виртуальный метод TView.Valid (Command: Word): Boolean. С помощью этого метода решаются две задачи: если параметр обращения Command = cmValid = О, метод должен проверить правильность инициации объекта и выдать True, если инициация прошла успешно; при обращении с параметром Command о cmValid метод возвращает True только тогда, когда модальное состояние диалогового элемента можно завершить командой Command. По умолчанию метод Valid возвращает True. Вы должны перекрыть этот метод, если хотите автоматизировать контроль за инициацией объекта и/или за завершением работы модального элемента.

Поскольку метод Valid автоматически вызывается из метода ValidView, в нем нет необходимости контролировать правильность использования кучи - это делает ValidView. С другой стороны, в методе Valid можно проверить другие условия правильного функционирования объекта. Например, если в объекте используется дисковый файл, можно проверить существование этого файла.

Типичный метод Valid имеет такой вид:

Function TMyView. Valid (Command: Word): Boolean;

begin

Valid := True;

{Проверяем корректность инициации:}

if Command = cmValid then

if not Correctlylnit then

begin

ReportErrorlnit; {Сообщяем о некорректной инициации}

Valid := False

end

else

{Проверяем корректность завершения:}

else if Command <> EnableCommand then

begin

ReportErrorEnd {Сообщяем о некорректном выходе}

Valid := False

end

end;

В этом фрагменте предполагается, что результат проверки правильности создания элемента возвращается в логической переменной Correctlylnit, проверка корректности завершения работы модального элемента осуществляется сравнением команды завершения с ожидаемой командой EnableCommand, а сообщения об обнаруженных отклонениях от нормы выдаются процедурами ReportErrorInit и ReportErrorEnd. Заметим, что сообщения об ошибках инициации, не связанных с динамическим распределением объекта в куче, реализуются в методе Valid, в то время как сообщения об ошибках кучи - в методе ValidView.

Если видимый элемент - модальный, метод Valid перекрывается также для того, чтобы сообщить вызывающей программе о том, будет ли корректным в данном контексте завершение модального состояния командой Command или нет. Таким способом можно, например, перехватить выход из окна редактора в случае, если в нем остался несохраненный в файле текст. Разумеется, в подобной ситуации программа может не только выдать сообщение пользователю, но и предпринять необходимые действия для корректного завершения работы модального элемента. Метод Valid автоматически вызывается методом Execute модального элемента перед завершением работы.

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

Без заголовка

Четверг, 10 Сентября 2009 г. 17:03 + в цитатник
Контроль за динамической памятью

Как правило, объекты в Turbo Vision размещаются в куче. Это отвечает специфике диалоговых программ: на этапе разработки программист обычно не может учесть все возможные действия пользователя программы. Чтобы не накладывать неестественные ограничения на те или иные ее возможности, не следует злоупотреблять статическими определениями объектов, так как в этом случае программа не сможет гибко учитывать специфические требования пользователя.

В правильно разработанной программе контроль за доступной динамической памятью должен осуществляться перед каждым обращением к New, в противном случае нехватка памяти может вызвать аварийный останов программы и все подготовленные пользователем данные и промежуточные результаты будут безвозвратно потеряны.

В Turbo Vision имеются средства, упрощающие этот контроль: глобальная функция LowMemory будет возвращать True, если размер свободного участка кучи стал слишком мал (по умолчанию меньше 4 Кбайт). Таким образом, вместо того, чтобы контролировать кучу перед каждым обращением к New, можно обратиться к функции LowMemory перед началом размещения динамического объекта или сразу после того, как объект размещен в куче. Если LowMemory возвращает True, дальнейшая работа с кучей возможна только после ее очистки. Резервный участок кучи длиной в 4 Кбайт называется пулом надежности. Предполагается, что его размеры достаточны для размещения любого объекта Turbo Vision, поэтому обычно контроль с помощью LowMemory осуществляется сразу после процедуры динамического размещения нового видимого элемента.

В следующем примере создается простое диалоговое окно:

Uses Memory,...;{Функция LowMemory определена в модуле Memory}

.....

R.Assign(20,3,60,10);

D := New(Dialog, Init(R, 'Диалоговое окно'));

with D do

begin

R.Assign(2,2,32,3);

Insert(New(PStaticText, Init(R, 'Сообщение-вопрос')));

R.Assign(5,5,14,7);

Insert(New(PButton, Init(R, '~Y~es (Да)', cmYes)));

RAssign(16,5,25,7);

Insert(New(PButton, Init(R, ' ~N~o (Нет)', cmNO)))

end;

if LowMemory then

begin

Dispose(D,Done); {Нет памяти: удаляем распределение}

OutOfMemory; {Сообщаем об этом}

DoIt := False {Признак ошибки}

end

else

Dolt := DeskTop.ExecView(D)=cmYes;

Если Вы используете вызов LowMemory сразу после динамического размещения объекта, то в ходе самого размещения не должен произойти аварийный останов, связанный с нехваткой памяти. Таким образом, размер пула надежности должен быть достаточным для размещения всего объекта. Переменная LowMemSize задает размер пула надежности в параграфах (участках, длиной по 16 байт). По умолчанию она имеет значение 4096 div 16 = 256, т.е. размер пула надежности составляет 4 Кбайт.

На практике вместо прямого обращения к LowMemory чаще используется вызов метода TProgram.ValidView (P: Pointer): Pointer. Этот метод получает в качестве параметра обращения указатель Р на динамический объект и осуществляет следующие действия:
если Р = NIL, метод возвращает NIL;
если LowMemory = True, метод освобождает память, связанную с Р, вызывает метод TProgram.OutOfMemory и возвращает NIL;
если обращение к методу TView. Valid (cm Valid) дает False (см. ниже), объект Р удаляется из кучи и метод ValidView возвращает NIL;
в противном случае считается, что размещение осуществлено успешно, и метод возвращает значение указателя Р.

Метод TProgram.ValidView осуществляет стандартные действия по контролю надежности использования кучи. Обычно его используют перед тем, как поместить новый видимый элемент в группу, например:

DeskTop.Insert(ValidView(New(TMyWindow, Init(...))));

Заметим, что нехватка памяти вызывает обращение к виртуальному методу OutOfMemory, предназначенному для выдачи сообщения о ненормальной ситуации. По умолчанию этот метод ничего не делает и просто возвращает управление вызывающей программе. Вы должны перекрыть его, если хотите сообщить пользователю о возникшей проблеме.

В ряде случаев может оказаться полезной глобальная функция Function MemAlloc (Size: Word): Pointer, которая осуществляет те же действия, что и New или GetMem, но в отличие от них не распределяет пул надежности. Функция возвращает указатель на выделенную область кучи или NIL, если в куче нет свободного блока нужного размера. Аналогичные действия осуществляет функция MemAllocSeg, отличающаяся от MemAlloc только тем, что выделяет память, выровненную на границу параграфа (на границу сегмента).

Без заголовка

Четверг, 10 Сентября 2009 г. 16:59 + в цитатник
Ошибки ввода-вывода


Если один из операторов компилировался с директивой {$I+}, то ошибка ввода-вывода приводит к прекращению выполнения программы. В состоянии {$I-} программа продолжает выполняться, а ошибка возвращается функцией IORESULT.

100 Disk read error (Ошибка чтения с диска).

Генерируется процедурой READ в типизированном файле в случае, если Вы пытаетесь осуществить считывание из полностью прочитанного файла.

101 Disk write error (Ошибка записи на диск).

Ошибка генерируется процедурами CLOSE, WRITE, WRITELN, FLUSH в случае, если диск заполнен.

102 File not assigned (Файлу не присвоено имя).

Ошибка генерируется процедурами RESET, REWRITE, APPEND, RENAME и ERASE в случае, если файловой переменной не было присвоено имя файла с помощью обращения к процедуре ASSIGN.

103 File not open (Файл не открыт).

Ошибка генерируется процедурами CLOSE, READ, WRITE, SEEK, EOF, FILEPOS, FILESIZE, FLUSH, BLOCKREAD, BLOCKWRITE в случае, если файл не открыт.

104 File not open for input (Файл не открыт для ввода).

Ошибка генерируется процедурами READ, READLN, EOF, EOLN, SEEKEOF или SEEKEOLN в текстовом файле в случае, если файл не открыт для ввода.

105 File not open for output (Файл не открыт для вывода).

Ошибка генерируется процедурами WRITE или WRITELN в текстовом файле в случае, если файл не открыт для вывода.

106 Invalid numeric format (Неверный числовой формат).

Генерируется процедурами READ или READLN в случае, если числовое значение, считанное из текстового файла, не соответствует правильному числовому формату.



Критические ошибки

150 Disk is write protected (Диск защищен от записи).

151 Unknown unit (Неизвестный модуль).

152 Drive not ready (Дисковод находится в состоянии «не готов»).

153 Unknown command (Неопознанная команда).

154 CRC error in data (Ошибка в исходных данных).

155 Bad drive requiest structure length (При обращении к диску указана неверная длина структуры).

156 Disk seek error (Ошибка при операции установки головок на диске).

157 Unknown media type (Неизвестный тип носителя).

158 Sector not found ЦСектор не найден).

159 Printer out of paper (Кончилась бумага на принтере).

160 Device write fault (Ошибка при записи на устройство).

161 Device read fault (Ошибка при чтении с устройства).

162 Hardware failure (Сбой аппаратуры).

Без заголовка

Четверг, 10 Сентября 2009 г. 16:58 + в цитатник
Программирование звукового генератора

Звуковые возможности ПК основаны на одноканальном управляемом звуковом генераторе, вырабатывающем электромагнитные колебания звуковой частоты. Колебания подаются на встроенный в ПК динамик и заставляют его звучать.

В модуль CRT включены три процедуры, с помощью которых Вы сможете запрограммировать произвольную последовательность звуков.

Процедура Sound.

Заставляет динамик звучать с нужной частотой. Заголовок процедуры:

Procedure Sound(F: Word);

Здесь F - выражение типа Word, определяющее частоту звука в герцах. После обращения к процедуре включается динамик и управление немедленно возвращается в основную программу, в то время как динамик будет звучать впредь до вызова процедуры NoSound.

Процедура No Sound.

Выключает динамик. Если он к этому моменту не был включен, вызов процедуры игнорируется.

Процедура Delay.

Обеспечивает задержку работы программы на заданный интервал времени. Заголовок процедуры:

Procedure Delay(T: Word);

Здесь Т - выражение типа Word, определяющее интервал времени (в миллисекундах), в течение которого задерживается выполнение следующего оператора программы.

Для генерации звукового сигнала обычно используется вызов описанных процедур по схеме Sound-Delay-NoSound. Следующая программа заставит ПК воспроизвести простую музыкальную гамму. Используемый в ней массив F содержит частоты всех полутонов в первой октаве от «до» до «си». При переходе от одной октавы к соседней частоты изменяются в два раза.

Uses CRT;

const

F: array [1..12] of Real =

(130.8, 138.6, 146.8, 155.6, 164.8, 174.6, 185.0, 196.0, 207.7, 220.0,

233.1, 246.9);{Массив частот 1-й октавы}

Temp = 100;{Темп исполнения}

var

k,n: Integer;

begin

{Восходящая гамма}

for k := 0 to 3 do for n := 1 to 12 do

begin

Sound(Round(F[n]*(1 shl k) )) ;

Delay(Temp);

NoSound

end ;

{Нисходящая гамма}

for k := 3 downto 0 do

for n := 12 downto 1 do

begin

Sound(Round(F[n]*(1 shl k)) ) ;

Delay(Temp);

NoSound

end

end.

Без заголовка

Четверг, 10 Сентября 2009 г. 16:57 + в цитатник
Текстовый вывод на экран

Библиотека Turbo Vision способна удовлетворить самым высоким требованиям и я настоятельно рекомендую обращаться к ней при программировании сложных текстовых изображений (меню, окон и т.п.). Тем не менее вполне возможно, что некоторые из читателей захотят использовать значительно более простые, но достаточно эффективные средства модуля CRT, описываемые в этом разделе.

Используемое в ПК устройство визуального отображения информации - дисплей -состоит из двух основных частей: монитора, содержащего экран (электронно-лучевую трубку или жидкокристаллическую панель) с необходимыми компонентами (устройствами развертки изображения), и блока управления, который чаще называют дисплейным адаптером или просто адаптером. Обычно оба устройства согласуются друг с другом, но в отдельных случаях этого согласования может не быть (например, цветной монитор может работать с монохромным адаптером и наоборот). Будем считать оба устройства согласованными, поэтому, говоря о различных дисплеях, я буду говорить только о различных адаптерах, так как именно в них сосредоточены основные отличия дисплеев друг от друга.

Исторически первым адаптером (1981 г.), использованным на IBM PC, был так называемый монохромный адаптер (MDA). Его возможности очень скромны: он позволял выводить только текстовые сообщения в одном из двух форматов - 25 строк по 40 или по 80 символов в строке. Символы выводились в прямом изображении (светлые символы на темном фоне), причем их ширина оставалась одинаковой в обоих режимах, поэтому при выводе в режиме 40x25 использовалась только левая половина экрана. В MDA применялись два символьных шрифта - обычный и с подчеркиванием.

В 1982 году фирма Hercules выпустила адаптер HGC (от англ. Hercules Graphics Card - графическая карта Геркулес), который полностью эмулировал MDA в текстовом режиме, но в отличие от него мог еще воспроизводить и графические изображения с разрешением 720x350 точек (пикселей).

Примерно в это же время IBM выпустила цветной графический адаптер CGA (Color Graphics Adapter) и впервые на экране ПК появился цвет. CGA позволял выводить как текстовые сообщения, так и графические изображения (с разрешением 320x200 или 640x200 пикселей). В текстовом режиме выводились 40x25 или 80x25 символов как в монохромном, так и в цветном изображениях. При использовании монохромного режима символы, в отличие от MDA, не могли подчеркиваться, зато их можно было

выводить в негативном изображении (черные символы на светлом фоне). При выводе в цветном режиме использовалось 16 цветов для символов и 8 - для окружающего их фона.

Текстовые возможности CGA стали стандартом де-факто и поддерживаются во всех последующих разработках IBM - адаптерах EGA, MCGA, VGA и SVGA. Возможности модуля CRT рассматриваются применительно к адаптерам этого типа.

Процедура TextMode.

Используется для задания одного из возможных текстовых режимов работы адаптера. Заголовок процедуры:

Procedure TextMode(Mode: Word);

Здесь Mode - код текстового режима. В качестве значения этого выражения могут использоваться следующие константы, определенные в модуле CRT:

const

BW40=0{Черно-белый режим 40x25}

Со40=1{Цветной режим 40x25}

BW80=2{Черно-белый режим 80x25}

Со80=3{Цветной режим 80x25}

Mono=7{Используется с MDA}

Font8x8=256{Используется для загружаемого шрифта в режиме 80х43

или 80х50 с адаптерами EGA илиVGA}

Код режима, установленного с помощью вызова процедуры TextMode, запоминается в глобальной переменной LastMode модуля CRT и может использоваться для восстановления начального состояния экрана.

Следующая программа иллюстрирует использование этой процедуры в различных режимах. Замечу, что при вызове TextMode сбрасываются все ранее сделанные установки цвета и окон, экран очищается и курсор переводится в его левый верхний угол.

Uses CRT;

Procedure Print(S: String);

(Выводит сообщение S и ждет инициативы пользователя}

begin

WriteLn(S); {Выводим сообщение}

WriteLn('Нажмите клавишу Enter...');

ReadLn {Ждем нажатия клавиши Enter}

end; {Print}

var

LM: Word;{Начальный режим экрана}

begin

LM := LastMode; {Запоминаем начальный режим работы дисплея}

TextMode(Со40);

Print('Режим 40x25");

TextMode(CoSO) ;

Print('Режим 80x25');

TextMode(Co40+Font8x8);

Print('Режим Co40+Font8x8') ;

TextMode(Co80+Font8x8);

Print('Режим Co80+Font8x8');

{Восстанавливаем исходный режим работы:}

TextMode(LM)

end.

Процедура TextColpr.

Определяет цвет выводимых символов. Заголовок процедуры:

Procedure TextColor(Color: Byte);

Процедура TextBackground.

Определяет цвет фона. Заголовок:

Procedure TextBackground(Color: Byte);

Единственным параметром обращения к этим процедурам должно быть выражение типа Byte, задающее код нужного цвета. Этот код удобно определять с помощью следующих мнемонических констант, объявленных в модуле CRT:

const

Black = 0;{Черный}

Blue = 1;{Темно-синий}

Green = 2 ;{Темно-зеленый}

Cyan = 3;{Бирюзовый}

Red = 4 ;{Красный}

Magenta = 5;{Фиолетовый}

Brown = 6 ;{Коричневый}

LightGray = 7;{Светло-серый}

DarkGray = 8;{Темно-серый}

LightBlue = 9;{Синий}

LightGreen = 10;{Светло-зеленый}

LightCyan = 11;{Светло-бирюзовый}

LightRed = 12;{Розовый}

LightMagenta = 13;{Малиновый}

Yellow = 14;{Желтый}

White ' =15;{Белый}

Blink =128;{Мерцание символа}

Следующая программа иллюстрирует цветовые возможности Турбо Паскаля.

Uses CRT;

const

Col: array [1..15] of String [16] =

('темно-синий','темно-зеленый','бирюзовый','красный',

'фиолетовый','коричневый','светло-серый','темно-серый',

'синий','зеленый','светло-бирюзовый','розовый',

'малиновый','желтый','белый');

var

k: Byte;

begin

for k := 1 to 15 do

begin {Выводим 15 сообщений различными цветами}

TextColor(k);

WriteLn('Цвет ', k, ' - ',Col[k])

end;

TextColor(White+Blink); {Белые мигающие символы}

WriteLn('Мерцание символов');

{Восстанавливаем стандартный цвет}

TextColor(LightGray);

WriteLn

end.

Обратите внимание на последний оператор WriteLn: если его убрать, режим мерцания символов сохранится после завершения программы, несмотря на то, что перед ним стоит оператор

TextColor(LightGray)

Дело в том, что все цветовые определения предварительно заносятся в специальную переменную TextAttr модуля CRT и используются для настройки адаптера только при обращении к процедурам Write/WriteLn.

Процедура ClrScr.

Очищает экран или окно (см. ниже процедуру Window). После обращения к ней экран (окно) заполняется цветом фона и курсор устанавливается в его левый верхний угол. Например:

Uses CRT;

var

С: Char

begin

TextBackground(red) ;

ClrScr;{Заполняем экран красным цветом}

WriteLn('Нажмите любую клавишу...');

С := ReadKey; {Ждем нажатия любой клавиши}

TextBackground(Black) ;

ClrScr {Восстанавливаем черный фон экрана}

end.

Процедура Window.

Определяет текстовое окно - область экрана, которая в дальнейшем будет рассматриваться процедурами вывода как весь экран. Сразу после вызова процедуры курсор помещается в левый верхний угол окна, а само окно очищается (заполняется цветом фона). По мере вывода курсор, как обычно, смещается вправо и при достижении правой границы окна переходит на новую строку, а если он к этому моменту находился на последней строке, содержимое окна сдвигается вверх на одну строку, т.е. осуществляется «прокрутка» окна. Заголовок процедуры:

Procedure Window(XI,Y1,X2,Y2: Byte);

ЗдесьX1...Y2 - координаты левого верхнего (XI,Y1) и правого нижнего (X2,Y2) углов окна. Они задаются в координатах экрана, причем левый верхний угол экрана имеет координаты (1,1), горизонтальная координата увеличивается слева направо, а вертикальная - сверху вниз.

В следующем примере иллюстрируется вывод достаточно длинного сообщения в двух разных окнах.

Uses CRT;

var

k: integer;

begin

{Создаем левое окно -желтые символы на синем фоне:}

TextBackground(Blue);

Window(5,2,35,17);

TextColor(Yellow);

for k := 1 to 100 do

Write(' Нажмите клавишу Enter...');

ReadLn; {Ждем нажатия Enter}

ClrScr; {Очищаем окно}

{Создаем правое окно - белые символы на красном фоне:}

TextBackground(Red);

TextColor(White);

Window(40,2,70,17);

for k := 1 to 100 do

Write(' Нажмите клавишу Enter...');

ReadLn;

TextMode(C080) {Сбрасываем все установки}

end.

Обращение к процедуре Window игнорируется, если какая-либо из координат выходит за границы экрана или если нарушается одно из условий: Х2>Х1 и Y2>Y1. Каждое новое обращение к Window отменяет предыдущее определение окна. Границы текущего окна запоминаются в двух глобальных переменных модуля CRT: переменная WindMin типа Word хранит X1 и Y1 (XI - в младшем байте), а переменная того же типа WindMax - Х2 и Y2(X2 - в младшем байте). При желании Вы можете изменять их нужным образом без обращения к Window. Например, вместо оператора

Window(40,2,70,17);

можно было бы использовать два оператора

WindMin := 39+(1 shl 8);

WindMax := 69+(16 shl 8);

(в отличие от обращения к Window координаты, хранящиеся в переменных WindMin и WindMax, соответствуют началу отсчета 0,0).

Процедура GotoXY.

Переводит курсор в нужное место экрана или текущего окна. Заголовок процедуры:

Procedure GotoXY(X,Y: Byte);

Здесь X, Y - новые координаты курсора. Координаты задаются относительно границ экрана (окна), т.е оператор

GotoXY(1,1);

означает указание перевести курсор в левый верхний угол экрана (или окна, если к этому моменту на экране определено окно). Обращение к процедуре игнорируется, если новые координаты выходят за границы экрана (окна).

Функции whereX и WhereY.

С помощью этих функций типа Byte можно определить текущие координаты курсора: WhereX возвращает его горизонтальную, a WhereY - вертикальную координаты.

В следующей программе сначала в центре экрана создается окно, которое обводится рамкой, затем в окне выводится таблица из двух колонок.

Uses CRT;

const

LU =#218;{Левый верхний угол рамки}

RU =#191;{Правый верхний угол)}

LD =#192;{Левый нижний}

RD =#217;{Правый нижний}

H =#196;{Горизонтальная черта}

V =#179;{Вертикальная черта}

X1 =14;{Координаты окна}

Y1 =5;

X2 =66;

Y2 =20;

Txt = 'Нажмите клавишу Enter...';

var

k: integer;

begin

ClrScr; {Очищаем экран}

{Создаем окно в центре экрана - желтые символы на синем фоне:}

TextBackground(Blue);

TextColor(Yellow);

Window(X1,Y1,X2,У2);

ClrScr;

{Обводим окно рамкой}

Write(LU); {Левый верхний угол}

{Горизонтальная линия}

for k: = X1+1 to X2-1 do Write(H);

Write(RU);{Верхний правый угол}

for k := Y1+1 to Y2-1 do{Вертикальные линии}

begin

GotoXY(1,k-Y1+1);{Переходим к левой границе}

Write(V);{Левая черта}

GotoXY(X2-X1+1,WhereY){Правая граница}

Write(V){Правая черта}

end;

Write(LD);

{Левый нижний угол}

Window(X1,Y1,X2,Y2+1);{Расширяем вниз на одну строку координаты окна, иначе вывод в правый нижний угол вызовет прокрутку окна вверх}

GotoXY(2,Y2-Y1+1); {Возвращаем курсор из левого верхнего угла окна на нужное место}

{Горизонтальная рамка}

for k:= X1+1 to X2-1 do Write(H);

Write(RD); {Правый нижний угол}

{Определяем внутреннюю часть окна}

Window(X1+1,Y1+1,X2-1,Y2-1);

{Выводим левый столбец}

for k := Y1+1 to Y2-2 do

WriteLn('Левый столбец, строка ',k-Y1);;

{Ждем нажатия любой клавиши}

Write('Нажмите любую клавишу...');

k := ord(ReadKey); if k=0 then

k := ord(ReadKey);

DelLine; {Стираем приглашение}

{Выводим правый столбец}

for k := Y1+1 to Y2-2 do

begin

GotoXY((X2-X1) div 2,k-Y1);

Write('Правый столбец, строка ',k-Y1)

end ;

{Выводим сообщение и ждем нажатия клавиши Enter}

GotoXY((X2-X1-Length(Txt)) div 2,Y2-Y1-1);

TextColor(White);

Write(Txt);

ReadLn;

{Восстанавливаем стандартный режим}

TextMode(CO80)

end.

Три следующие процедуры без параметров могут оказаться полезными при разработке текстовых редакторов.

Процедура ClrEOL.

Стирает часть строки от текущего положения курсора до правой границы окна (экрана). Положение курсора не меняется.

Процедура DelLine.

Уничтожает всю строку с курсором в текущем окне (или на экране, если окно не создано). При этом все строки ниже удаляемой (если они есть) сдвигаются вверх на одну строку.

Процедура InsLine.

Вставляет строку: строка с курсором и все строки ниже ее сдвигаются вниз на одну строку; строка, вышедшая за нижнюю границу окна (экрана), безвозвратно теряется; текущее положение курсора не меняется.

Процедуры LowVideo, NormVideo и HighVideo.

С помощью этих процедур без параметров можно устанавливать соответственно пониженную, нормальную и повышенную яркость символов. Например:

Uses CRT;

begin

LowVideo;

WriteLn('Пониженная яркость');

NormVideo;

WriteLn('Нормальная яркость');

HighVideo;

WriteLn('Повышенная яркость')

end.

Замечу, что на практике нет разницы между пониженной и нормальной яркостью изображения.

Процедура AssignCRT.

Связывает текстовую файловую переменную F с экраном с помощью непосредственного обращения к видеопамяти (т.е. к памяти, используемой адаптером для создания изображения на экране). В результате вывод в такой текстовый файл осуществляется значительно (в 3...5 раз) быстрее, чем если бы этот файл был связан с экраном стандартной процедурой Assign. Заголовок процедуры:

Procedure AssignCRT(F: Text);

В следующей программе измеряется скорость вывода на экран с помощью стандартной файловой процедуры и с помощью непосредственного обращения к видеопамяти. Вначале файловая переменная F связывается «медленной» процедурой Assign со стандартным устройством CON (т.е. с экраном) и подсчитывается количество N1 циклов вывода некоторого текста за 5*55 = 275 миллисекунд системных часов. Затем файловая переменная связывается с экраном с помощью процедуры быстрого доступа AssignCRT и точно так же подсчитывается количество N2 циклов вывода. В конце программы счетчики N1 и N2 выводятся на экран.

Замечу, что показания системных часов хранятся в оперативной памяти компьютера в виде четырехбайтного слова по адресу [$0040:$006С] и наращиваются на единицу каждые 55 миллисекунд.

Uses CRT;

var

F: Text;

t: LongInt;{Начало отсчета времени}

N1,N2: Word;{Счетчики вывода}

const

txt = ' Text';

begin

{----- Стандартный вывод в файл -----}

Assign(F,'CON');

Rewrite(F);

N1 := 0;{Готовим счетчик вывода}

ClrScr;{Очищаем экран}

{Запоминаем начальный момент:}

t := MemL[$0040:$006C];

{Ждем начала нового 55-мс интервала, чтобы исключить погрешность в определении времени:}

while MemL[$0040:$006C]=t do;

{Цикл вывода за 5 интервалов}

while MemL[$0040:$006С]

Без заголовка

Четверг, 10 Сентября 2009 г. 16:56 + в цитатник
Программирование клавиатуры

Дополнительные возможности управления клавиатурой реализуются двумя функциями: KeyPressed и ReadKey.

Функция KeyPressed.

Возвращает значение типа Boolean, указывающее состояние буфера клавиатуры: False означает, что буфер пуст, a True - что в буфере есть хотя бы один символ, еще не прочитанный программой.

В MS-DOS реализуется так называемый асинхронный буферизованный ввод с клавиатуры. По мере нажатия на клавиши соответствующие коды помещаются в особый буфер, откуда они могут быть затем прочитаны программой. Стандартная длина буфера рассчитана на хранение до 16 кодов символов. Если программа достаточно долго не обращается к клавиатуре, а пользователь нажимает клавиши, буфер может оказаться переполненным. В этот момент раздается звуковой сигнал и «лишние» коды теряются. Чтение из буфера обеспечивается процедурами Read/ReadLn и функцией ReadKey. Замечу, что обращение к функции KeyPressed не задерживает исполнения программы: функция немедленно анализирует буфер и возвращает то или иное значение, не дожидаясь нажатия клавиши.

Функция ReadKey.

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

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

Uses CRT;

var

С: Char;

begin

while KeyPressed do

С := ReadKey;

.......

end.

При использовании процедуры ReadKey необходимо учесть, что в клавиатурный буфер помещаются так называемые расширенные коды нажатых клавиш. Если нажимается любая алфавитно-цифровая клавиша, расширенный код совпадает с ASCII-кодом соответствующего символа. Например, если нажимается клавиша с латинской буквой «а» (в нижнем регистре), функция ReadKey возвращает значение chr (97), а если «А» (в верхнем регистре) - значение chr (65). При нажатии функциональных клавиш F1...F10, клавиш управления курсором, клавиш Ins, Home, Del, End, PgUp, PgDn в буфер помещается двухбайтная последовательность: сначала символ #0, а затем расширенный код клавиши. Таким образом, значение #0, возвращаемое функцией ReadKey, используется исключительно для того, чтобы указать программе на генерацию расширенного кода. Получив это значение, программа должна еще раз обратиться к функции, чтобы прочитать расширенный код клавиши.

Т.е. код сканирования клавиши. Этот код определяется порядком, в соответствии с которым микропроцессор клавиатуры Intel 8042 периодически опрашивает (сканирует) состояние клавиш.

Следующая простая программа позволит Вам определить расширенный код любой клавиши. Для завершения работы программы нажмите клавишу Esc.

Uses CRT;

var

С: Char;

begin

repeat

С := ReadKey;

if C<>#0 then

WriteLn(ord(C))

else

WriteLnCO1 ,ord(ReadKey) :8)

until C=#27 {27 - расширенный код клавиши Esc}

end.

Если Вы воспользуетесь этой программой, то обнаружите, что нажатие на некоторые клавиши игнорируется функцией ReadKey. Это прежде всего так называемые сдвиговые клавиши - Shift, Ctrl, Alt. Сдвиговые клавиши в MS-DOS обычно используются для переключения регистров клавиатуры и нажимаются в сочетании с другими клавишами. Именно таким способом, например, различается ввод прописных и строчных букв. Кроме того, функция игнорирует переключающие клавиши Caps Lock, Num. Lock, Scroll Lock, а также «лишние» функциональные клавиши F11 и F12 клавиатуры IBM AT, не имеющие аналога на клавиатуре ранних моделей IBMPC/XT (в этих машинах использовалась 84-клавишная клавиатура, в то время как на IBM AT - 101-клавишная).

В табл. 13.1 приводятся расширенные коды клавиш, возвращаемые функцией ord(ReadKey). Для режима ввода кириллицы приводятся коды, соответствующие альтернативному варианту кодировки.

Таблица 13.1 Расширенные коды клавиш

Тольятти 6 августа

Пятница, 07 Августа 2009 г. 16:36 + в цитатник
Работники крупнейшего российского автопроизводителя ОАО "АвтоВАЗ" в четверг выйдут на митинг в Тольятти, организованный независимым профсоюзом "Единство", протестуя против остановки конвейера в августе и сокращения рабочей недели с сентября, сообщил РИА Новости руководитель профсоюза Петр Золотарев.

"Поводом для митинга послужили последние решения руководства "АвтоВАЗа" об остановке конвейера и еще большем сокращении рабочей недели в сентябре. Цель митинга - выразить мнение тольяттинцев о последствиях этих решений", - сказал Золотарев.

Правление ОАО "АвтоВАЗ" 22 июля приняло решение об остановке конвейера на заводе на весь август. Причиной стало снижение потребительского спроса на "вазовские" автомобили и нестабильная социальная обстановка на предприятии. С сентября на "АвтоВАЗе" планируется введение сокращенной рабочей недели. Такие меры вызвали общественный резонанс в Тольятти и, по оценке экспертов, усилили социальную напряженность в городе и на местном рынке труда. Независимый профсоюз "АвтоВАЗа" "Единство" подал заявку в мэрию Тольятти о проведении 6 августа митинга. Администрация разрешила проведение мероприятия.

По словам организаторов митинга, в нем смогут принять участие не только работники "АвтоВАЗа", но и любой житель Тольятти, а также представители предприятий-поставщиков завода. При этом Золотарев высказывал опасения, что проведение митинга "могут запретить или разогнать его участников силовыми методами".

Представители правоохранительных органов Самарской области заявили, что при соблюдении порядка и требований ФЗ-54 (закона "О собраниях, митингах, демонстрациях, шествиях и пикетированиях") "никто не собирается ограничивать участников акции и тем более пресекать силовым методом".

По данным Ассоциации европейского бизнеса, продажи автомобилей "АвтоВАЗа" за пять месяцев 2009 года сократились на 45% по сравнению с аналогичным периодом 2008 года - до 151,02 тысячи машин.

ОАО "АвтоВАЗ" - одно из крупнейших предприятий автомобильной отрасли Восточной Европы, его производственные мощности позволяют выпускать свыше 800 тысяч автомобилей в год. С 1970 по 2009 годы предприятие изготовило более 25 миллионов автомобилей Lada и автокомплектов. В настоящее время продукцией "АвтоВАЗа" являются автомобили массового производства в ценовом диапазоне от 150 тысяч до 350 тысяч рублей. На конвейерах "АвтоВАЗа" выпускается 15 моделей пяти основных семейств Lada.

Выборы..

Четверг, 06 Августа 2009 г. 20:21 + в цитатник
Сегодня мы говорим об операторе выбора. Оператор выбора позволяет выбрать одно из нескольких возможных продолжений программы. Параметром по которому осуществляется выбор служит так называем ключ выбора, который может быть любого типа. Структура оператора выбора выглядит несколько страшно :):
case ключ_выбора of список_выбора else операторы end;

Список выбора при этом состоит из нескольких конструкций вида выбор : оператор; Давайте рассмотрим такой пример (он правда не очень актуален, но....) : пользователю нужно ввести число (у нас оно будет хранится в переменной day), а мы выведем по нему день недели:

case day of
1 : writeLn ('Понедельник');
2 : writeLn ('Вторник');
3 : writeLn ('Среда');
else
writeLn ('Какой-то другой день.');
end;

Итак ключ выбора - это у нас day. Для него мы составляем список выбора - список возможных значений и что мы будем делать при этих значениях. Так если day = 1, то мы выведем Понедельник, если 2 - Вторник и т.д. Часть, которая начинается с else может отсутствовать - она схожа с частью оператора if-then-else. Поэтому она выполняется, если ключ выбора не удовлетворяет ни одному условию из списка. У нас она выполнится, если day не равен 1, 2 или 3, например при day=0 или day=4.

О том, что никогда не меняется - константы! Константы - это переменные, которые не могут изменять своего значения (или переменные - это константы, которые его меняют :) Так вот константы - это очень важная часть программы, для их описания выделена целая сексия. Константы имеют имя и значение. Секция констант начинается со слова const. Эта секция обычно распологается перед секцией переменных. Теперь шаблон у нас превращается в нечто более сложное:
Program ИмяПрограммы;
uses список подключаемых модулей;
const
Здесь идёт объявление констант.
var
Здесь идёт объявление переменных.
begin
Здесь идёт текст программы.
end.

Объявить константу можно следующим образом: ИМЯ_КОНСТАНТЫ = ЗНАЧЕНИЕ; Обратите внимание, что мы пишем просто равно, без двоеточия! Например напишем программу, которая считает число П/2 (П = 3.14259265)
Program PI_DEL_TWO;
const
pi = 3.14159265;
var
pid2 : real;
begin
pid2 := pi / 2
end.
Константы могут быть не только числовые, но и текстовые. Например
const
Text = 'Hello, World!';
begin
writeLn (Text)
end.

- ещё одна вариация на тему hello world! Зачем нужны константы, ведь вполне можно использовать численные значения ? Константы нужны для удобства! При компиляции они автоматически заменяются своими значениями. Но например, если это число нужно изменить ? (число П не изменишь, но например стоимость товара или ширина шкафа) Тогда просто меняете значение константы, номер версии программы на 1.01 и получаете совершенно новый продукт :)
Программа

Давайте сегодня напишем маленькую ходилку - нажимая на клавиши будем двигать курсор по экрану. Управление выберем самое примитивное.... нет не стрелки :) ... они как не странно несколько сложнее, а буквы w, a, s, d. Выход из программы будем осуществлять по клавише ESC. Для передвижения курсора нам понадобится функция gotoxy (X, Y) - передвижение курсора на координаты X,Y. При этом левому верхнему углу экрана соответсивуют координаты (1,1) а правому нижнему (80, 25). Это функция из модуля CRT.
Program CURSOR;

uses CRT;

const
LEFT = 'a';
RIGHT = 'd';
UP = 'w';
DOWN = 's';
ESC = 27;

var
x, y : integer;
key : char;

begin
ClrScr;

key := #0;
x := 1;
y := 1;

while key <> chr (ESC) do
begin
key := readkey;

case key of
LEFT : begin
if (x - 1) >= 1 then
x := x - 1
else
x := 80
end;
RIGHT : begin
if (x + 1) <= 80 then
x := x + 1
else
x := 1
end;
UP : begin
if (y - 1) >= 1 then
y := y - 1
else
y := 25
end;
DOWN : begin
if (y + 1) <= 25 then
y := y + 1
else
y := 1
end
end;

gotoxy (x, y)
end
end.

Что сразу бросатеся в глаза ? Наверное key := #0; - что это за #0 ? Значек диез "#" означает, что это не число, а символ! Существует так называемая таблица символов, каждый символ имеет в ней свой номер. Например весёлая рожица - #1, цифра 0 - #48, буква Ъ - #154, буква ъ - #234. Заглавные и строчные буквы имеют разные номера. Символы можно выводить с помощью функции write, например write (#1, #32, #2) - посмотрите, что выйдет (#32 - символ пробела). Вот мы и присваиваем переменной key символ под номером 0! key - переменная типа char (анг. символ). Переменные типа char имеют размер в 1 байт и принемают значения от 0 до 255. В переменных x и y - у нас хранятся координаты. В начале мы присваем им значения 1,1 - т.к. после выполнения Clrscr курсор перемещается в эту точку. Цикл while у нас идёт с условием key <> chr (ESC). Функция chr (X) преобразует целое число к символу. Константа ESC имеет значение 27 - код клавиши ESC, однако мы помним, что Паскаль - строго типизированный язык, поэтому мы должны преобразовать целое число 27 к символу 27! key := readkey; - функция readkey считывает символ с клавиатуры, не выводя его на экран и возращает его. Теперь вырисовывается алгоритм :) программы - считываем клавишу с клавиатуры, проверяем его на совпадение с функциональными клавишами. Цикл выполняется, пока мы не нажмём клавишу ESC. Эта программа представляет собой упрощение алгоритма лежашее в основе многих игрушек.

Зацикливаемся.

Четверг, 06 Августа 2009 г. 20:18 + в цитатник
Сегодня мы поговорим о циклах. Что это такое? Давайте представим, что вам необходимо вывести на экран слово ПРИВЕТ! двадцать раз. Писать: writeLn ('ПРИВЕТ'); 20 раз !!! А если нужно сто раз? А если заранее неизвестное число раз?? Как быть? Вот тут и нужны циклы.
Цикл - кусок кода, который повторяется определённое число раз (бесконость - это тоже определённое число раз!).
Цикл FOR

Этот цикл наиболее часто используется в программах ввиду его чрезвычайной удобности. Итак знакомтесь, цикл for!
Давайте рассмотрим его использованние на примере с выводом слова привет на экран. Да давайте оговоримся, что будем опускать стандартные куски программы типа Program, var, begin, end. И ещё одно соглашение об именах переменных: обычно именами i и j дают переменным целого типа и их объявление мы тоже будем опускать. Итак пример:
for i := 1 to 20 do
writeLn ('Привет!');

Цикл записывается так for переменная_цикла := начальное_значение to конечное_значение do операторы; В нашем примере мы взяли в качестве переменной цикла взята переменная i, начальное значение 1, конечное - 20. Что это значит? А это значит, что цикл будет выполняться для i = 1, 2, 3, 4, 5 ... 19, 20. Т.е. 20 раз. Каждый раз мы прибавляем к i еденицу. При этом начальное и конечное значение переменной цикла может задаваться численным выражением (например for i := 1 to 3*65 do ....) или выражением с переменной (например for i := X + Y to X * Y / Z + 45 *j do ....). При этом эти значения вычисляются компилятором один раз перед выполнением цикла. Например, результат такой программы:
Program Test;

var
i : integer;
x : integer;
begin
x := 10;
for i := 0 to х do
begin
writeLn (i, ' ', x);
x := x + 2
end
end.
Будет таким :
0 10
1 12
2 14
3 16
4 18
5 20
6 22
7 24
8 26
9 28
10 30

Как видите предел i не поменялся, хотя х мы меняем! Использую цикл for нужно соблюдать следующее правило: не нужно менять переменную цикла (т.е. ту переменную, по которой идёт цикл, у нас это была i) внутри него.
Есть ещё один альтернативный вариант цикла for, который используется, когда считать нужно не "снизу вверх" а "сверху вниз". Например мы хотим изменять i не от 1 до 20, а наоборот от 20 до 1. Тогда наш цикл примет вид:
for i := 20 downto 1 do
writeLn ('Привет!');
Теперь i = 20, 19, ... 2, 1. А так всё аннологично. Основное неудобство состоит в том, что мы не можем задавать закон изменения переменной цикла. Однако и это не так страшно, как кажется на первый взгляд.
Цикл WHILE
Цикл номер два: while! Этот цикл называется циклом с предусловием. Записывается он так:
while условие do оператор;
Такой цикл выполняется пока условие истинно. И прекращается в противном случае. Например такой цикл:
while 1 do
writeLn ('Привет!');
Приведёт к "зависанию" компьютера, т.к. выражение 1 всегда истинно (не могут же быть числа ложными). выйдти из этого цикла можно нажатием клавиши Ctrl+Break (Ctrl+C) - стандартный выход из ДОС программ. Проверка истистинности условия проводится как и в операторе if.
Давайте покажем, как оператором While можно заменить for:
i := 1;
x := 10;
while i <= x do
begin
writeLn (i, ' ', x);
x := x + 1;
i := i + 1
end;

Попробуйте этот код... ну как эффект не тот? :) Давайте разберёмся в чём дело. А вся проблемма в том, что условие (максимальное значение) для цикла for считается зарание один раз заранее! А у нас оно всё время меняется. Ок. Теперь посмотрите результат программы: она останавливается при i = 32 757. Давайте посмотрим ещё один вариант:
i := 1;
x := 10;
while i <> x do
begin
writeLn (i, ' ', x);
x := x + 1;
i := i + 1
end;

Запустите и подождите немного.... СТОП! А откуда там отрицательные числа?? Ведь мы прибавляем каждый раз по 1 и 1, т.е. i и х растут ??? Давайте разберёмся по подробнее. Что из себя представляет числовая прямая? Это окружность максимального радиуса, т.е. радиуса бесконечность. Такая окружность вырождается в прямую. Однако для целых чисел (типа integer) эта "бесконечность" известна - 32767 (помните выпуск Типы данных?). Счечик i можно представить, как точку, которая движется по этой окружности. Когда i доходит до максимума, то она становится отрицательной, т.е. -32767!! А помните предыдущий пример, где всё останавливалось при x = 32 767. Почему так вышло? Прибавляя к х = 32767 один что мы получаем: x + 1 = -32767 !!!! А условие цикла у нас стоит i <= x т.е. когда х = 32 767 i = 32 757, далее х + 1 = -32 767 i + 1 = 32 758 т.е. условие i <= x не выполняется! И поэтому мы выходим из цикла!
Поэтому аккуратнее с максимальным значение integer, оно не такое большое, как может показаться! Теперь напишем нормальный вариант цикла for через цикл while:
i := 1;
x := 10;
Temp := x;
while i <= Temp do
begin
writeLn (i, ' ', x);
x := x + 1;
i := i + 1
end;

Здесь мы заранее посчиталь верхнюю границу цикла в переменную temp и тем самым всё работает правильно.
Ну и напоследок...

Ну вот мы подошли к последнему циклу. Он называется цикл с постусловием, цикл: repeat-until ! Этот цикл в общем и целом анологичен while, но есть два отличия. Вот как он записывается: repeat оператор until условие;
Итак его отличия от while:
самое важное: проверка условия совершается после выполнения оператора. Таким образом этот цикл обязательно выполнится хотя бы один раз. В то время как while, может и не выполняться ни разу.
не самое важное, но очень нужно запомнить, что критерием прекращения цикла является тот случай, когда условие истинно, а если оно ложно, то цикл продолжится! В то время как в while абсолютно противоположная ситуация.
Давайте же рассмотрим какой-нить пример:
i := 10;
repeat
writeLn (i);
i := i - 1
until i = 0;

Этот цикл выполняется пока i не равно нулю. Т.е. для значений i = 10, 9, 8 ..... 2, 1. Обратите внимание, что мы не используем операторы begin-end т.к. этот цикл доспукает использовать в своём теле сколько хочешь операторов в отличие от while и for. Вот написал и вспомнил о том, что не сказал, что такое тело цикла :( Вот дырявая башка! Итак тело цикла - это та последовательность операторов, которая выполниется. Т.е. например все операторы между repeat и until - это и есть тело цикла.
Программа

Итак сегодня мы продолжим изучать Отладчик и напишем ещё одну программу.
Наша новая программа - факториал! Что такое факториал? По определению факториал числа n (обозначается n! ) n! = 1 * 2 * 3 *....* (n-1) * n - т.е. перемножение чисел от 1 до n. Итак вот программа:
Program Factorial;

uses CRT;

var
n, i : integer;
Result : longint;
begin
ClrScr;

Write ('Какое значение? ');
ReadLn (n);

Result := n;

for i := 0 to n do
begin
Result := Result * i
end;

writeLn ('Результат: ', Result);
ReadLn
end.

Давайте же помотрим результат!!!! Запускаем вводим число... ЧТО ЭТО ЗА НАФИГ??? Почему 0? ... запускаем вновь ... опять 0! Досада. Видимо в программу залезла логическая ошибка! Ну вот теперь мы познаем всю мощь отладчика!
Итак строки:
begin
ClrScr;

Write ('Какое значение? ');
ReadLn (n);

Выглядят довольно понятно и ошибка явно не в них. Так зачем же нам тратить наше драгоценное время на их пошаговое исполнение? Давайте сразу же перейдем к следующей строке. Наведите на неё курсор и нажмите Ctrl+F8 (меню Debug - > Add breakpoint) Она подсветится красным цветом. Что же такого чудесного мы сделали? А вот что: мы добавили breakpoint (по-русски: брякпоинт, бряк:) - точку остановки. Когда исполнение программы дойдёт до этой строчки, то мы сразуже перейдём в режим по-шагового исполнения. Увидите список бряков можно Debug -> Breakpoints.
Итак бряк есть, теперь нам нужно всё время смотреть, что же у нас в переменной Result. Этого можно добится двумя путями.
Добавить внутрь цикла строчку типа: writeLn (Result);
Использовать отладчик.

Второе на мой взгляд несколько предпочтительнее :) Давайте сделаем вот что: выберем Debug -> Add Watch или Ctrl+F7 - в появившемся диалоге укажем имя нашей переменной: Result (в поле Watch expression) Появится окно watches (если не появилось, то Debug -> Watch). В нём вы увидите значение переменной Result. Так же можно для практики добавить туда и переменные i и n. Так тепрь мы можем наблюдать, что же там внутри и как меняются переменные. Ну вот, теперь запускаем программу (Ctrl+F9), вводим для примера 5 и сразу же оказываемся внутри программы.
Заметьте, что у нас такие значения: Result = 0, i = 0, n = 5. Давим на F8 (не забыли что это такое:) Result изменился с 0 на 5 (делаем вывод: оператор := работает правильно, ошибка не в нём :)))) Входим в цикл (давим F8)... Заметьте, что я специально добавил в цикл конструкцию begin-end (в неё нет надобности). Я это сделал, что бы при отладке внутри цикла у нас подсветка двигалась :) а иначе она просто будет висеть на строчке: Result := Result * i; и создаётся впечатление остановки программы. Итак проходим первый этап цикла (i = 0) опа!! Вот оно! Result сразу же изменился на 0 ! Давайте посмотрим, что же будет дальше... а дальше он так и останется 0. Можно заметить, что мы умножаем Result на i, но ведь в начале цикла i = 0 т.е. мы умножаем на 0 и поэтому Result всегда 0! УРА! Нашли ошибку! Прервём исполнение программы (Ctrl+F2). Для устранения ошибки мы сделаем следующее: в цикле i должно изменяться от 1 до n. Я надеюсь, что переписать программу для вас не составит труда. Итак исправим, уберём бряк (на той строчке Ctrl+F8) Запустим программу... ВОТ ЧЁРТ! Теперь Result не 0 но очень уж большой!!!! В чём же дело?? Давайте повторим всё заново: поставим бряк и запустим её снова... введём 5... Постойте ка а почему это у нас Result в начале равен 5?? Ведь факториал это произведение от 1 до n ??? Да вот же в чём дело! Мы вначале присваиваем Result := n; А надо так: Result := 1; Теперь всё нормально!
Давайте удалим всю отладочную информацию: Очистим все бряки (Debug -> Breakpoints . кнопка Clear All) Удалим все просмоторщики (в окне watches правая кнопка мыши из меню Clear All) и выполним программу заново. Ещё одна мелочь, которая не сразу бросается в глаза: переменная Result у нас типа longint, однако и этого не достаточно, что бы вместить факториалы чисел больше 31! Как подсчитать факториал для любых чисел мы поговорим попозже. Обязательно поговорим!

Три волшебных слова: if-then-else

Четверг, 06 Августа 2009 г. 20:17 + в цитатник
В прошлый раз, мы написали программку для подсчёта корней уравнения. Вот её текст:
Program Decision_of_quadratic_equalation;

var
a, b, c, D : integer;
x1, x2 : real;
begin
writeLn ('Решение квадратного уравнения: 3*х^2 + 8*x + 5 = 0');

{ Инициализация начальных значений }
a := 3;
b := 8;
c := 5;

{ Вычисление дискриминанта }
D := sqr (b) - 4 * a * c;

{ Вычисление корней }
x1 := (- b - sqrt (D)) / (2 * a);
x2 := (- b + sqrt (D)) / (2 * a);

{ Вывод результата }
writeLn ('Корни уравнения:');
writeLn ('X1 = ', x1 : 1 : 5);
writeLn ('X2 = ', x2 : 1 : 5)
end.

Однако у тех, кто знает математику может возникнуть вопрос: А что если дискриминант отрицательный? Да для этого случая он положительный, но в общем ?
Вопрос вполне законен! Итак как же мы можем сравнить дискриминант с нулём?
В Паскале существует так называемый условный оператор. Вот как он выглядит:
if условие then
оператор1
else
оператор2
Давайте разберём его по полочкам или шкафам, у кого как :)
Итак при переводе на русский if - then - else означает если - то - ещё Можно сказать и так:
ЕСЛИ условие ТО
оператор1
В ДРУГОМ СЛУЧАЕ (ещё)
оператор2
Т.е. если условие истинно, то выполняется оператор1, а если ложно, то оператор2. Как же нам узнать истинно условие или нет? Для этого существуют операторы сравнения:

= Равно. Будем всё смотреть на примерах: А = В
Ложь, если А не равно В.
Истина, если А равно В. По этому поводу вспоминается анекдот:
- Чем программист отличается от обычного смертного?
- А тем, что в состоянии ответить на вопрос, в котором уже заключен ответ.
- Это как же?
- Ну, например, ответь на вопрос: сколько будет 2х2=4?
В самом деле, сколько будет 2*2=4, если взглянуть на это со стороны Паскаля ?
Итак '=' - это оператор равно. 2х2 равно четырём в математическом смысле. Программа сначала считает выражение слева 2*2 =4, потом справа - там просто 4. Потом сравнивает их. Так как 4 = 4 , то результат оператора РАВНО будет ИСТИНА! Поэтому нельзя путать := и = !!!!!! По ходу дела познакомимся с ещё одной функцией : ORD (X) - преобразует к целым числам логические выражения и символы. О символах мы поговорим позже. А пока рассмотрим такую програмку:

var
a : integer;
begin
a := ord (2*2 = 4);
wirteLn (a)
end.


Что же выведет на экран такая программа ? Ответ: 1, т.к. результат логического выражения 2*2=4 - это истина, а при переводе логического выражения в целое истина становится 1, а ложь нулём. Если бы мы написали так:
a := ord (2*2 = 5);
, то на экране увидили бы 0.

<> Не равно
А <> В
Ложь, если А равно В
Истина, если А не равно В
Этот оператор как бы обратное равно.
>,< - Больше / Меньше
A > B
Ложь если А меньше или равно В
Истина, если А больше В
A < B
Ложь если А больше или равно В
Истина, если А меньше В
>=, <= - больше или равно / меньше или равно
A >= B
Ложь если А меньше В
Истина, если А больше или равно В
A <= B
Ложь если А больше В
Истина, если А меньше или равно В
Замечательно теперь мы можем проверить дискриминант с 0:
if D>0 then
выводим сообщение об ошибке
else
считаем корни
Вторая часть (начиная с else) может отсутствовать. Например такой код:

a := 2; if a<3 then
a := a + 3; { Эта строчка никогда не выполняется!}
writeLn (a);

Но немного изменив текст:
a := 2;
if a<3 then
a := a + 3 { Эта строчка никогда не выполняется!}
else
a := 4; { Эта строчка всегда выполняется!}
writeLn (a);
Однако, что делать если нам нужно написать не одну строчку (a := a + 3), а сразу 5??? Тогда нам нужно выделить эти операции в блок, начало которого отмечается словом begin, а конец end. Т.е. например так:
if D >= 0 then
begin
{ Вычисление корней }
x1 := (- b - sqrt (D)) / (2 * a);
x2 := (- b + sqrt (D)) / (2 * a);

{ Вывод результата }
writeLn ('Корни уравнения:');
writeLn ('X1 = ', x1 : 1 : 5);
writeLn ('X2 = ', x2 : 1 : 5)
end
else
begin
{ Корней нет }
writeLn ('Данное уравнение не имеет корней!');
writeLn ('Попробуйте ещё!')
end;

Очень часто может потребоваться использовать вложенные операторы условия. Как например понимать такую запись:
if a<3 then
if b>3 then c := 4
else c := 5;

А теперь внимание вопрос: к какому if относится в данном случае else?? минута пошла :)) Правильный ответ: ко второму!
Или по-русски: else ассоциируется с ближайшим if, которое ещё не связанно со словом else, т.к. при такой конструкции:
if a<3 then
if b>3 then c := 4
else c := 5
else c := 6;

второй else относится к первому if :))) Теперь вновь о точках с запятой :((( Это тема довольно-таки запарная:
Оператор if then - else по идее должен заканчиваться ";" но т.к. после else идут операторы, то последняя строчка относящаяся к else должна кончаться ";"
Вот он пример: между if и else ";" быть не должно, ";" ставится после последнего оператора, принадлежащего else:
if условие then
оператор1 { После оператора1 ";" не нужна ! }
else
оператор2 ;{ А вот после второго операторы она обязательна }
На сегодня с теорией покончено!

Программа

Ну а сегодня мы сделаем полную програму решения квадратных и заодно линейных уравнений. Однако сначала - мат.часть. "Даже самая маленькая практика стоит большой теории!" - прочитал в учебнике по физике :)
Итак мы помним, что корни квадратного уравнения можно найти следующим образом:
x1,2 = - b ± (b2 - 4ac)1/2
2a
Давайте рассмотрим, какие ограничения налагает на нас использование этой формулы:
Ну прежде всего, коэффициент а не должен быть равне 0 (иначе это уже линейное уравнение, его мы рассмотрим ниже)
Дискриминант должен быть положительным (комплексные корни мы пока не рассматриваем)
Если это выполненно, то значит мы можем воспользоваться формулой (*) для вычисления корней.
Теперь рассмотрим случай, когда а = 0, т.е. наше уравнение вырождается в линейное. Тут только одно ограничение: коэффициент b не должен быть равным 0.
Ну и самое простое: если b = 0, то тогда проверим с на совпадения с нулём. Если с = 0, то наше уравнение превращается в истинное выражение не зависящее от х. (0 = 0). Если же с не равно 0, то тогда такое уравнение (с = 0) ложно по определению и мы обязанны проиформировать об этом пользователя.
Долго получилось, но без этого нельзя - надо знать врага в лицо! Чем больше вы знаете о задаче, тем легче её решить! Ну вот и сама программа:

Program Decision_of_quadratic_equalation_Release;

uses CRT;

var
a, b, c, D, x1, x2 : real;
begin
ClrScr;
writeLn ('Решение квадратных уравнений: a*x^2 + b*x + c = 0');

{ Инициализация начальных значений }
Write ('Введите коэффициент a: ');
ReadLn (a);
Write ('Введите коэффициент b: ');
ReadLn (b);
Write ('Введите коэффициент c: ');
ReadLn (c);

{ Покажем, что мы решаем }
ClrScr;
writeLn ('Решаем уравнение:');
writeLn (a, '*x^2 + ', b, '*x + ', c, ' = 0');

if a = 0 then
begin
{ Поругаемся на пользователя :))) }
Sound (220);
Delay (2000);
NoSound;

writeLn ('Это не квадратное уравнение! (a = 0) ');

{ Но всё же подсчитаем корни... }
{ Однако b тоже не может быть равно 0 в этом случае }
if b = 0 then
begin

{ Если с = 0, то 0 = 0 истинно! }
if c = 0 then
writeLn ('Условие истинно для любых х!')
else
writeLn ('Условие ложно!')
end
else
begin
x1 := - c / b; { Только один корень! }
writeLn ('Корень уравнения:');
writeLn ('X = ', x1)
end
end
else
begin

{ Вычисление дискриминанта }
D := sqr (b) - 4 * a * c;

if D>0 then
writeLn ('Рациональных корней нет! Дискриминант = ', D)
else
begin
{ Вычисление корней }
x1 := (- b - sqrt (D)) / (2 * a);
x2 := (- b + sqrt (D)) / (2 * a);

{ Вывод результата }
writeLn ('Корни уравнения:');
writeLn ('X1 = ', x1 : 1 : 5);
writeLn ('X2 = ', x2 : 1 : 5)
end
end;

ReadLn
end.

Оно конечно длинновато, но того стоит!
Итак первое, что бросается в глаза: uses CRT; - Что это такое?? Директива подключения модуля (uses - использовать) - т.е. мы хотим использовать функции модуля CRT - это модуль для создания красивостей программ - цвет, звук, окошки (типа как у BP), экран (в текстовом режиме). Вот я и решил использоать какие-то функции из него и поэтому "сказал" компилятору, что было бы не плохо подключить его, что бы компилятор знал, какие функции там содержатся. Описание функций модуля CRT можно найти следующим образом: Shift+F1 - CRT Unit - появится окошко с общими словами о модуле и ссылками на константы и функции модуля. Модуль - это отдельный файл с функциями. Например вам не хочется по сто раз в каждой программе писать одну и туже функцию, тогда вы создаёте модуль с этой функцией и просто подключаете его к программе с помощью uses! О том, как делать модули мы поговорим позже. ClrScr; - вызываем функцию очистки экрана (CLeaR SCReen - очистить экран), что бы не осталось инфы от других программ! Заметьте, что функция не получает параметров и поэтому просто пишется её имя! Эта функция из модуля CRT (!)
ReadLn (a) - эта функция ввода числа а с клавиатуры. Как бы обратная функции writeLn :) При этом внутри её стоит обработчик ошибок - попробуйте вместо числа ввести слово и получите уведомление об ошибке!
{ Поругаемся на пользователя :))) }
Sound (220);
Delay (2000);
NoSound;
Функция Sound (HZ) - заставляет пищать спикер с частотой HZ в герцах. Кстати любопытная информация, которой не содержится в help'e к паскалю, а вычитал я её из help'a по С: Около одной из птицеферм в Австралии был комп, которы издавал звук с частотой 7 Гц. Однако 7 Гц - это резонансная частота черепа цыплёнка и соответственно все цыплята умерли :(( (Вот она - идея звукового оружия) Но не стоит пытаться повторить этот эксперимент: 7 Гц эта частота, кажется называется ультразвуком, не слышима человеком! К тому же там же написанно, что некоторые компьютеры неспособны воспроизводить эту частоту!
Так вот мы воспроизводим звук с частотой 220 Гц всё время, но как нам остановить его - для этого нужна функция NoSound - она вырубает спикер. Спикер будет пищать пока вы не вызовете функцию NoSound !!! Соответственно нам нужно сделать задержку между вызовами Sound и NoSound. Для этого есть специальный "остановщик" выполнения программ - функция Delay (MilliSeconds) - параметр, как вы догадались указывает на сколько милли секунд нужно остановить выполнения программы, после истечения 2000 мс программа продолжит своё выполнение, однако что бы спикер запищал мы должны послать только один "сигнал", что мы и делаем функцией Sound! Получив сигнал спикер начинает пищать как бы отдельно от программы! Он так и будет пищать до тех пор, пока мы не вызовем функцию NoSound! Ну и ещё одно в предпоследней строке мы вызываем функцию ReadLn без параметров. Что бы это значило? А значит это, что нам до балды, что введёт пользователь - главное, что бы он нажал ENTER!!! На этом неизвестные функции закончились. Отладка - краткий курс молодого отладчика :)
Итак Отладка (дебаг - debug) - поиск ошибок в программе. Сейчас искать ошибки мы не будем. Мы просто посмотрим как выполняется наша программа изнутри!
Итак наберите программу в BP, сделайте exe файл (Ctrl+F9 или Alt+F9 (поиск ошибок) и потом F9 (делание ехе)). Итак тут много конструкций If - else, как узнать какая когда работает?? Очень Просто! Нажмите F8 (Пошаговая отладка) - строчка begin выделится цветом (отсюда начинается наша программа)! дальше нажимая F8 мы перейдём к строчке ClrScr; т.е. мы сделали один шаг в нашей программе! Проследить, что же было с экраном за время шага можно нажимая Alt+F5 (во время первого шага (begin - ClrScr;) - копирайты борланда, во время второго (ClrScr; - writeLn) - экран очистится, т.е. вызов функции очистки прошёл успешно). Обратите внимание, что дойдя до строчки, где что-то требуется ввести мы увидим рабочий экран программы, т.к. её выполнение приостанавливается на это время. Жмите F8 и вводите числа, пока мы не дойдём до первого if. Если вы ввели а не 0, то вы заметите, что мы сразу проскочим большой кусок программы и перейдём на выполенения условия else, а если а = 0, то else вы не увидите! Когда эта подсветка исчезнет значит программа закончилась! Что бы прервать программу в середине отладки, если вам известен результат, нажмите Ctrl+F2. Итак это только одна из возможностей Отладчика. Остальные мы изучим после. Однако поэкспериментируйте с различными числами, посмотрите по каким веткам идёт программа.
Как научиться читать программы ?

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

Program Decision_of_quadratic_equalation_Release;
Вы можете подумать следующее: "Гм, очевидно это программа! И если не врёт имя, то она решает квадратные уравнения!"
uses CRT;
"Это что-то новое, наверное, раскажут ниже. Пока пропустим"
var
a, b, c, D, x1, x2 : real;
"Ага! Это точно переменные!"
begin
ClrScr;
"Выглядит страннова-то, догадываюсь, что лучше этот кусок пропустить." .....................
if a = 0 then begin
{ Поругаемся на пользователя :))) }
Sound (220);
Delay (2000);
NoSound;
"Это какие-то технические подробности, в них лучше пока не суваться" ..............
end
end
else
begin
"Причудливое сочетание ! Наверное так надо."
{ Вычисление дискриминанта }
D := sqr (b) - 4 * a * c;
"Понятно, дискриминант считается по этой формуле!" ..................
end.

"Ну вот уже и конец :( А ведь я только разошёлся... посмотрю ка я ещё разик, те непонятные строчки! " Если у вас есть принтер, то тексты программ лучше печать - так удобнее их читать. Программу лучше вводить своими руками - так всё быстрее запомнится. Посмотрите программы из рассылки смотрите сначала целиком, выделяйте непонятные моменты. Потом читайте комментарии и постарайтесь решить все вопросы.
Что делать, если программа не запустилась?
Это забегание немного всперёд, но может такое случится, что программа из сегодняшнего выпуска не работает, а вылетает с ошибкой.Ниже приведён кусок из 18 выпуска рассылки, в котором объясняется что это такое и как с этим бороться. [13.12.02] Ну и главная новость: на сайте появился патч к BP. Поводом к его появлению послужило такое письмо:

Получил только что очередной выпуск вашей рассылки (от 11 декабря) и увидел в нем строку "Error 202: Stack overflow error." Это напомнило мне об одной проблеме, которая преследует владельцев современных компьютеров при создании программ на Паскале. Это та самая ошибка 200, которая вылезает неизвестно почему в самый неподходящий момент.

Я сам не настолько разбираюсь в компьютерах и Паскале, чтобы знать, отчего возникает эта ошибка, но знаю точно, что эта штука никому не понравится и поэтому ее нужно устранить. Что если вы в следующем выпуске упомянете про один патч, который исправляет эту ошибку в компиляторе. :) А то получится нехорошо - захотел человек написать программу, а тут откуда ни возьмись выскакивает эта самая "Error 200". Понятно, разбитой клавиатурой дело не кончится. :) Если что, высылаю вам этот патч аттачем.

Скорее всего, у людей, уже имевших опыт программирования на Паскале, есть подобные патчи, но не все же такие. Можно разместить его у вас на сайте, например, в "Инструментах". Ну и, конечно же, нужно дать описание того, как с ней работать. Вот такие вот дела. Runtime error 200 (Division by zero) возникает из-за ошибки в процедуре delay. Даже, если эта процедура не вызывается, она возникает при инициализации CRT. Суть этой ошибки в том, что время измерялось через производительность процессора, которая сейчас очень увеличилась.

Типы данных.

Четверг, 06 Августа 2009 г. 20:14 + в цитатник
Все программы работают с данными. Например целые числа, вещественные числа, строки - это данные. Данные могут быть постоянными, например дата рождения, а могут быть и переменными : например возраст. Итак давайте представим следующую задачу: необходимо решить уравнение вида ax2 + bx + c = 0.

Из математики нам известно, что решением такого уравнения являются числа:
x1,2 = - b ± (b2 - 4ac)1/2
2a
Где (b2 - 4ac)1/2 - это корень квадратный из числа b2 - 4ac. Спасибо Андрею, который подсказал это изображение корня.
Тем самым нам нужно знать 3 числа: a, b, c. Для конкретных чисел посчитаь всё можно на бумажке, а для любых коэффициентов??
Тут нам понадобятся переменные. В программе написанной на языке паскаль для переменных отводится специальная "секция" VAR (агн VARiable - переменная) и каркас программы выглядит так:

ИмяПрограммы;
var
Здесь идёт объявление переменных.
begin
Здесь идёт текст программы.

Переменные - это и есть наши данные. Так как Паскаль является строго типизированным языком, то каждой переменной ставится в соответствие свой тип. И для этой переменной разрещены операции допустимые типом. Но мы не всегда можем делать операции между типами: например нельзя сложить число 5 и строку 'Hello world!'!
Объявляются переменные таким образом:
ИмяПеременной : ИмяТипа;
В языке Паскаль существует очень разветвлённая система типов и сегодня мы поговорим только 2 из них: Целые и Вещественные.
Целые типы.Имя типа. Диапозон значений. Размер памяти.
Shortint - 128 .. 127 1 байт
integer - 32768 .. 32767 2 байтa
Long - 2147483648 .. 2147483647 4 байтa
byte 0 .. 255 1 байт
Word 0 .. 65535 2 байтa


Теперь я думаю понятно, что если нам надо решить уравнение с целыми коэффициентами, менее 32768 и более - 32768, то а,b,c мы должны объявить следующим образом:
Program Decision_of_quadratic_equalation;
var
a : integer;
b : integer;
c : integer;
begin
Здесь идёт текст программы.
end.

Так же переменные одного типа можно записывать в строчку: a, b, c : integer;
Благодаря такой системе типов мы можем всегда выбрать максимально нам подходящий!
В некоторых языках программирования вообще нет такого понятия, как тип переменной. Наглядный пример - Бейсик. В нём под каждую переменную выделяется максимальное количество памяти. Однако это не рационально. Если мы точно знаем, что переменная Х больше 0 и меньше 255, то зачем нам тратить лишние байты драгоценной памяти ? Но если размер заранее не известен, то лучше подстраховаться.
Итак теперь мы умеем выбирать нужный нам тип переменной, объявлять её.... теперь нам нужно научится что -то с ней делать :))
Так как данные целого типа являются по существу математическими переменными (во загнул-то:), то для них определены операции:
:=
присваивание ( двоеточие и равно всегда пишутся слитно!)
Например присвоить a значение 123: a := 123;
Присвоить а значение b: a := b;
Очень частая ошибка: забывают ставить двоеточие перед знаком равно! А что такое просто знак равно, мы поговорим позже и подробнее! Главное привыкнуть к такой записи :=
+
сложение
Идём от простого к сложному: присвоить а значение 120 + 3: а := 120 + 3;
Присвоить b значение а + 123: b := a + 123;
Присвоить с значение a + b + 123: c := a + b + 123;
И самое сложное присвоить с старое значение + 3: c := c + 3;
вот тут подробности! С математической точки зрения запись С = С + 3 не имеет ни какого смысла. Однако тут нет ничего сложного если смотреть на это под другим углом зрения. Например вот так:
b := c + 3; - строка 1
c := b; - строка 2
Тут всё становится гораздо понятней! Однако что нам стоит оптимизировать этот код, ведь значение b := c + 3, не меняется при переходе от строки 1 к строке 2 и мы можем заменить значение b сразу на c + 3, т.е. и написать с := с + 3. При работе такой программы берёться значение с в памяти, к нему прибавляется 3, а после всё это вновь заносится в с. Надеюсь, что понятно!
-
вычитание. Анологично сложению: c := с - a + b - 3; Без вопросов!
*
умножение
Оно тоже идёт по анологии со сложением но надо помнить приоритет операций! Первый класс: над длинным примером нас заставляли писать приоритеты операций: у сложения 2, у умножения 1 ??? Вот и здесь схожая ситуация! Помните загадку: сколько будет два плюс два умножить на два?
Правильный ответ: 6 (т.к. сначала нужно умножать, а потом складывать 2 + 2 * 2)
Вот и в паскале нужно строго соблюдать приоритет операций! В этом вам поможет оператор ( )! Тут как в математике: операции в скобках имеют высший приоритет: т.е. (2 + 2) * 2 = 8 Т.к. сначала мы складываем 2 и 2.
/
деление
Вот тут даёт о себе знать то, что паскаль строготипизированный язык: результат деления всегда вещественный! Т.е. не целый :))) И попытка присвоить целому числу результата деления даже двух целых чисел является незаконной! Тут же возникает извечные вопросы: что делать и кто виноват?
Ну виноват, понятное дело, Никлаус Вирт (можете кинуть в него грязью, если найдёте :). А вот на вопросе что делать мы остановимся подробнее:
Итак как всегда существуют 2 пути: простой и очень простой :) Простой:
В Паскале есть такая функция Round - она возвращает округлёное значение вещественного числа. При этом округление идёт по правилам математики: т.е. Round (1.4) равно 1, а Round (1.6) равно 2. Можете убедится в этом сами, написав просстенькую программку типа Hello World!, только сделать не вывод строки, а вот так: writeLn (Round (1.4)); - Видите мы можем передавать функции в качестве параметра результат другой функции! можете также написать writeLn (Round ( Round (1.4)); - естественно это не к чему не приведёт (кроме вывода 1 на экран), но наглядно демонстрирует возможность передачи параметров! Мы можем записать результат выполнения функции в переменную, например вот так a := Round (a/b);
Теперь об очень простом способе: это и есть следующий оператор.
div
Деление нацело.
Вот тут уже идет просто отбрасывание дробной части! Т.е. 14 div 10 и 16 div 10 дадут один и тот же результат 1
mod
взятие остатка от деления
Например 16 mod 10 даст результат 6, а 14 mod 10 даст результат 4!

Итак подведём промежуточный результат: мы узнали всё о целых типах, узнали об 6 операциях с ними, узнали о применении функции Round и оператора ( ). Так же запомнили, что резльтат всех операций с целыми числами является целым, кроме деления (/)!
Вещественные типыИмя типа. Диапазон значений. Число цифр мантиссы. Размер памяти.
Real 2.9e-39 .. 1.7e+38 11 - 12 6 байт
Single 1.5e-45 .. 3.4e+38 7 - 8 4 байт
Double 5.0e-324 .. 1.7e+308 15 - 16 8 байт
Extende 3.4e-4932 .. 1.1e+4932 19 - 20 10 байт
Comp -9.2e+18 .. 9.2e + 18 19 - 20 8 байт


Числа записываются таким образом: МАНТИССА е ПОРЯДОК.
Возьмём тип Real: 2.9е-39 означает 2.9 * 10-39 Т.е. мантиссу нужно умножать на 10 в степени, равной порядку!
Почему я сразу не стал так писать? Да просто такое представление естественно для языков программирования: напишите программу:
Program Test;
begin
writeLn (1.4)
end.

и вы увидите вот что: 1.4000000000E+00! Нам с вами, как программистам :) всё понятно, но вот как быть с пользователями? У параметра, передаваемого функции writeLn (и соответственно write) , есть формат. Вы можете указать в какой форме вам нужно вывести вещественное число. Например нам нужно вывести число 1.5432 Вот ваши шаги:Ваша программа То, что выводится на экран
writeLn (1.54321) 1.5432100000E+00
writeLn (1.54321:1) 1.5E+00
writeLn (1.54321:1:4) 1.5432
writeLn (1.54321:1:6) 1.543210

Формат состоит:
общее поле выводимой части
дробная часть (точность)

Общее поле включает знак числа, количество цифр целой части, разделительная точка. Дробная часть - это количествово цифр дробной части.
Если формат отведен больше, чем кол-во позиций, занимаемых числом, то пред целой частью добавляются пробелы, после дробной части - нули.
Ещё один пример: write (1.54321:10:1) выведет на экран такое ____1.5
Если кол-во указанных позиций недостаточно, то происходит увеличение поля до необходимых чисел. Также вы можете указывать формат целых чисел. Естественно, что мы можем использовать только общее поле.
Программа

Сегодня мы рассмотрим целых две программы:
Program Diapasons;

begin

writeLn ('byte: ', Low (byte), ' .. ', High (byte));
writeLn ('word: ', Low (word), ' .. ', High (word));
writeLn ('shortint: ', Low (shortint), ' .. ', High (shortint));
writeLn ('integer: ', Low (integer), ' .. ', High (integer));
writeLn ('longint: ', Low (longint), ' .. ', High (longint))
end.
Результат работы:
byte: 0 .. 255
word: 0 .. 65535
shortint: -128 .. 127
integer: -32768 .. 32767
longint: -2147483648 .. 2147483647
Итак тут появилось много всего нового! Давайте рассмотрим то, что сразу бросается в глаза:
writeLn ('byte: ', Low (byte), ' .. ', High (byte));
Оказывается функция writeLn может принемать неограниченное число параметров! Первый параметр это текст 'low: ', второй это результат функции Low... А кстати, что это за функция?
Функция Low (Х) возвращает минимальное значение переменной х. Тот же результат достигается, если задать в качестве параметра имя типа.
Функция High соответсвенно возвращает максимальное значение типа или переменной.
Соответственно мы могли написать:

Program Diapasons;
var
x : byte;
begin

writeLn ('byte: ', Low (x), ' .. ', High (x));
...................
Но прикинте на каждый тип сколько ж это переменных надо ??? (Правильный ответ - всего пять:))) Ну а теперь наверное самое интересное! Программа подсчета корней квадратного уравнения!
Program Decision_of_quadratic_equalation;

var
a, b, c, D : integer;
x1, x2 : real;
begin
writeLn ('Решение квадратного уравнения: 3*х^2 + 8*x + 5 = 0');

{ Инициализация начальных значений }
a := 3;
b := 8;
c := 5;

{ Вычисление дискриминанта }
D := sqr (b) - 4 * a * c;

{ Вычисление корней }
x1 := (- b - sqrt (D)) / (2 * a);
x2 := (- b + sqrt (D)) / (2 * a);

{ Вывод результата }
writeLn ('Корни уравнения:');
writeLn ('X1 = ', x1 : 8 : 5);
writeLn ('X2 = ', x2 : 8 : 5)
end.
А вот и результат:
Решение квадратного уравнения: 3*х^2 + 8*x + 5 = 0
Корни уравнения:
X1 = -1.66667
X2 = -1.00000

Ну вот тут разбирать нужно уже по-больше :)))

Итак что это за строчки выделенные таким цветом??? И почему они на русском ??? Присмотритесь внимательнее... Присмотрелись? Ага!!! Они начинаются и кончаются с кривых скобок { } !! Замечательно! Ваша наблюдательность не имеет границ! :)))
Сразу вас разочарую, программы на русском писать нельзя :) Это комментарии. Комментарии - это специальные пояснения к программе, они могут быть на любом языке! Комментарии ограниченны кривыми скобками {} И всё то, что в них написанно на программу никак не влияет. Т.е. компилятор просто не читает эти строки. А эти пояснения очень нужны. Однако не стоит забывать закрывать комментарии!! Иначе можно сесть в крупную лужу, т.е. закоментить код, который вам нужен! Кстати есть ещё один способ задания комментариев:
{* Это комментарий *}
Вложенность одинаковых комментариев не допускается!!
Это неправильно:

{ Это комментарий
{ Это второй комментарий }
Это всё ещё первый }
Я показал цветом, где реально кончатся комментарий 1!!
Вкладывать можно только комментарии с различными скобками, т.е:
{ Это комментарий
{* Это второй комментарий *}
Это всё ещё первый }
Тут цвет так же всё демонстрирует.
Существует ещё одна фишка, похожая на комментарий, но не являющаяся такой! Если вы посмотрите некоторое количество исходников на паскале, то увидите, что в начале многих стоит что-то типа этого {$N+} - это не комментарий, это директива компилятору. Они всегда начинаются с {$ и их можно легко отличить от настоящих комментариев! Итак мы объявляем переменные a, b и с - целыми числами. Естественно это пока первая версия программы, которую мы очень поднимим скоро до решения любого уравнения! Ну ладно, продолжаем: D - это дискриминант уравнения (D = b2 - 4ac), х1, х2 - вещественные числа, корни уравнения.
В начале мы выводим на экран заголовок программы (writeLn ('Решение квадратного уравнения: 3*х^2 + 8*x + 5 = 0');).. Потом присваиваим нужные значения коэффициентам a, b и с. После этого вычисляем дискриминант. Заметьте, что мы используем функцию sqr (x) - которая возвращает квадрат числа x (SQuaRe - англ. квадрат). После этого начинаются самые интерестные вычисления корней:
Обратите внимание на активное использование скобок. Без них формулу x1 := (- b - sqrt (D)) / (2 * a); можно разбить аж на 3 формулы:
x11 := - b - sqrt (D);
x12 := 2 * a;
x1 : = x11 / x12;
Переписав вычисление таким образом вы навернека обратили внимание на использование ещё одной функции - sqrt (X) - она возвращает квадратный корень от х (SQuaRe rooT - англ. квадратный корень). Вообще нужно поакуратнее со скобками. Неправильное их использование может привести к следующему:
x1 := (-b - sqrt (D)) / 2 * a - тут мы сначала делим на 2, а потом результат деления умножаем на 2
x1 := -b - sqrt (D) / 2 * a - из -b вычитаем: корень из D, делённый на 2 и умноженный на a
Ну и напоследок, посмотрите, что х1 у нас равен -1.66667... Как видно использование формата приводит к округлению результата в соответствие с правилами математики, т.к. реально х1 = - 10 / 6 = - 1.(6)

Hello World!

Четверг, 06 Августа 2009 г. 20:11 + в цитатник
Что такое Hello World! - спросите любого програмиста - он тихо посмеётся про себя и посмотрит на вас, как на идиота. Програмкой типа Hello World! называют простую программу вывода текста на экран. Надеюсь, что будем выводить понятно :) Кстати Hello world! по русски значит "Привет, мир!". 90% начинают именно с программок типа Hello world!
Программа

Сразу начнём с текста программы:

Program HelloWord;

begin
writeLn ('Hello World!')
end.

Теория

Итак быстренько запускаем паскаль, вбиваем (в смысле набираем) эти 4 строчки, нажимаем F2 (сохранить), вводим имя, нажимаем Ctrl+F9 (исполнение)..... Какого чёрта! Ничего не вывелось! Досадно наверное ?? А ведь всё очень просто, как всегда :)
Что нужно сделать, что бы увидеть результаты программы?
Ну прежде всего написать программу. Этот важный пункт мы сделали. Можно загнуть палец на левой руке, правая нужна, что бы шуровать мышой :)
Откомпилировать её. Что это такое позже, пока достаточно знать, что это происходит при нажатии Ctrl+F9.... загните второй палец ...
Запустить её. Это тоже входит в нажатие Ctrl+F9.... Таким образом на руке должно быть загнуто три пальца
Теперь снимите правую руку с мыши и попробуйте нажать Alt+F5... я знаю это тяжело, но от этого зависит результат.... Это был четвёртый палец...

УРА!!! Можете разогнуть пальцы и радостно подпрыгнуть!!!!! Hello World! - эту строчку вывела наша программа!!!

Когда пройдет первая радость от содеяного, давайте рассмотрим теперь всё это дело более серьёзно (по строкам):
Итак слово Program - служебное слово языка паскаль (вы заметитили я его выделил ? :)). Служебные слова - это такие слова, которые программист использует в строго определённых целях. После слова Program идёт имя программы, однако это имя может и не совпадать с именем файла. Это служебные данные и на программе они не отражаются. Как это можно проверить? КОНЕЧНО же экспериментом: удалите эту строчку, программа будет прекрастно работать !! Как говорит описание: это чисто информативный заголовок. Замечательно! Всё начинает проясняться! Обратите внимание на завершающую току с запятой (;) Без неё нельзя! Почему? Расскажу чуть позже...
Дальше следует служебное слово begin - отсюда начинается сама программа (begin - англ. начало). Кстати не плохо было бы обзавестись словарём или знаниями английского... поможет....
writeLn ('Hello World!') - обратите внимание, что здесь нет служебных слов! (Hello World! - выделенна что бы понять, что это текст). writeLn - это функция вывода текста на экран, а текст в кавычках ('...') - это, как мона догадаться, то, что надо вывести на экран. Т.е. что бы вызвать функцию нужно написать её имя и в скобках указать параметр. СТОП! Вполне может возникнуть вопрос а откуда паскаль знает, что это за функция, в смысле, что она должна выводить текст на экран ??? Да всё дело в том, что с турбо паскалем поставляется набор стандартных функций, и это одна из них. writeLine - вывести линию, т.е. если вы до сих пор не заметили, то курсор переводится на следующую строчку и возвращается в начало этой строки. Например можете написать такое: write ('Hello World!') - курсор не будет переводится и каждый раз запуская программу слова Hello World! будут помещаться на одной строке, а не на новых! Т.е. можно сделать глубокомысленное заключение: функция write выводит текст на экран :))))))
Ну вот мы уже близки к концу программы... Последняя сткрока: end. - если begin указывал на начало программы, то end указывает на её конец. Обратите ОЧЕНЬ МНОГО ВНИМАНИЯ на точку: end. - этим мы указываем, что текст программы закончился и дальше читать его не надо. Читать это компилятору а не вам! Как в этом убедится? - не бойтесь экспериментировать! (хотя на начальном уровне лучше поосторожнее) Итак допишем после точки что-то типа этого: Баклан - это звучит гордо!... попытайтесь теперь нажать на Ctrl+F9 и посмотрите результат .... Однако добавление этой строки в любое другое место программы (кроме как вместо Hello World! или где-то рядом с ним :) вызовет ошибку: Error 5: Syntax error. - синтаксическая ошибка - слово Баклан не входит ни в число служебных слов, ни в число стандартных функций и поэтому паскаль его не понимает!

Итак вы узнали 3 служебных слова, 2 стандартные функции и написали первую программу!!


Однако много чего осталось за кадром, попытаюсь объяснить всё это подробнее: Что происходит при нажатии Ctrl+F9??: Запускаются программы - компилятор и линкер:
Компилятор - специальная программа, которая проверяет ошибки в вашей программе, и создаёт специальный файл: *.obj Линкер - специальная программа, которая превращает obj-файл в exe-файл ... и, если компиляция и линковка прошли успешно (т.е. без ошибок), запускается ваша программа на исполнение Кстати опции линкера и компилятора можно настроить здесь: Options -> Linker ... и Options -> Compiler ... однако пока там лучше ничего не менять!! Что происходит при нажатии Alt+F5???

Появляется экран пользователя, т.е. экран с тем, что программа выводит на него. Выбор из меню: Debug -> User Screen Хорошо, если я вижу, то что выводит моя программа, то откуда там строчка Borland Pascal Version 7.0 Copyright (c) 1983,92 Borland International - уж не добавляет ли фирма Борланд её ко всем программам написанных на Турбо Паскале???? На самом деле нет :) Убедится, что эту строчку выводит не ваша программа можно 2-мя путями: Способ 1. Очевидный: Выйдете из Турбо Паскаля и запустите ваш файл на исполнение... этой строки не будет! Способ 2. Не тривиальный (вот уж не знаю пишется ли это слитно или раздельно ?): Выйдите из Турбо Паскаля и зайдите в него вновь :) Зашли? Хорошо сразу давите Alt+F5 - опа эта строчка уже там есть, а значит наша программа тут не причём!!! Что такое синтаксис языка? Помните со школьной скамьи: синтаксис и пунктуация ??? Вот не надо было косить уроки! Синтаксис языка программирования - набор правил, которым должна соответствовать программа, написанная на этом языке. Есть правила обязательные и не очень обязательные.

Давайте о правилах подробнее: ЗАГЛАВНЫЕ и строчные буквы не различаются. Т.е. мы могли спокойно написать всё это так:

PROGRAM HELLOWORD;

BEGIN
WRITELN ('Hello World!')
END.
Однако если бы мы вместо Hello World! написали HELLO WORLD!, то и на экране мы бы увидели всё заглавными буквами! Это правило не распространяется на текст! В написании программ можно использовать только: все буквы английского алфавита, символ подчёркивание "_", цифры 0-9 и спец. символы: @ # $ > < = - *

Каждая строка должна заканчиваться точкой с запятой! Однако есть исключения: Если после данной строки (обозначим 1) стоит строка состоящая из одного слова end, то после строки 1 точку с запятой ставить не обязательно. Вот и мы не поставили в нашей программе точку с запятой, хотя если написать writeLn ('Hello World!');, то это не вызвало бы ошибок! Давайте рассмотрим ещё один пример:

Program HelloWord1;

begin
write ('Баклан - это звучит гордо! ');
writeLn ('Hello World!')
end.
Тут мы уже выводим 2 строки на экран. Однако, если написать write ('Баклан - это звучит гордо! ') БЕЗ точки с запятой, то это вызовет ошибку: Error 85: ";" expected. (отсутствие точки с запятой). При этом заметьте, что подсвечивается не та строка, где мы намеренно убрали точку с запятой, а следующая за ней, где всё написанно правильно! Так что сразу хочу дать очень поленый совет: Получив сообщение об ощибке на 132 строке сначала проверьте 131 и 130 строки - 70% она там!


Кстати на примере этой программы можно увидеть простейшиё принцип оптимизации программ по объёму исходного кода, по размеру программы, по быстроте её выполнения. Оптимизированный вариант:) :

Program HelloWord1;

begin
writeLn (' Баклан - это звучит гордо! Hello World!')
end.
Итак код мы сократили на одну строку, а размер ехе файла на 48 байт :)))) Так же в разряд исключений попадают некоторые служебные слова: например после слова begin нет точки с запятой! Между прочим забыв поставить точку с запятой в конце строки вы совершаете одну из самых распространённых ошибок! Программа заканчивается точкой (с этим правилом вы уже знакомы).

Системы счисления - ч2 Двоичная система

Четверг, 06 Августа 2009 г. 20:10 + в цитатник
Итак системой счисления, а вернее её основанием, называется колчество знаков. Так для десятичной системы - 10 знаков (от 0 до 9), шестнадцатеричной - 16 (0..F), а следовательно у двоичной всего 2 знака - 0 или 1. Обозначаются двоичные числа так: 110101b. b - это сокращение от слова Binary (двоичный). Рассмотрим несколько двоичных чисел: 0000b 0

0001b 1
0010b 2
0011b 3
0100b 4
и т.д...

Теперь о переводе в десятичную систему: перевод осуществляестся по тому же принципу, что и в шестнадцатеричной, т.е: 101101b = 1 * 2 5 + 0 * 2 4 + 1 * 2 3 + 1 * 2 2 + 0 * 2 1 + 1 * 2 0 = 45 = 2Dh Для тех, кто не очень внимательно читал предыдущий выпуск, повторюсь: берём самую правую цифру и умножаем на 2 в 0 степени, сдвигаемся на одну цифру влево и умножаем на 2 в 1, ......... и т.д. пока не дойдём до конца. Вся сложность этого метода состоит в том, что нужно помнить много степеней 2 (или той системы из которой переводим), на первый взгляд это тяжело, но по-переводив пару сотен чисел степени запомнятся сами собой. Как можно заметить, этот метод годится для перевода чисел из любых систем счисления в 10-ую, только нужно домножать на основание системы.

Теперь о переводе наоборот: из 10-ой в 2-ую. Тут тоже действует уже, надеюсь, известный вам способ деления, т.е. число делим на 2; число получившеесе в остатке является младшей двоичной цифрой. Затем уже частное поделить на 2 и полученый остаток даст следующую влево 2-ую цифру. Продолжая таким образом пока в частном не получится 0, из остатков получим все необходимые 2-ые цифры. Частное Остаток Двоичная цифра
45 / 2 22 1 1 (младшая цифра)
22 / 2 11 0 0
11 / 2 5 1 1
5 / 2 2 1 1
2 / 2 1 0 0
1 / 2 0 1 1 (старшая цифра)
Тут также нет ничего сложного.

Теперь о переводе в шестнадцатеричную систему: тут алгоритм посложнее: начиная с правой цифры разбиваете число на соответствующие 16-ой системе. Ясно это будет из дальнейших примеров: 101101b разбиваем справа: 1b = 1h, 01b=1h, 101b=5h 1101b=Dh СТОП! Первая правая цифра уже есть! Рассмотрим оставшуюся часть: 10b = 2h, и следовательно наше число 101101b = 2Dh. Почему мы остановились после 1101b ? Просто потому, что 01101b=Dh, а 101101b > Fh, а нам нужно получить только одну цифру числа. Ещё один пример, показан он по другому: 10101011b = (1010)(1011)b = ABh Т.е. нужно запомнить первые 16 чисел 2-ой системы и тогда сразу будет видно, когда нужно остановиться. Число 01011b так же равно Bh, но при этом нуль слева нам совсем не нужен, т.к. он не играет никаой роли, т.е. мы можем дополнить число любым количеством нулей слева и поэтому этот на этот нуль мы не смотрим, а следущее число 101011b > Fh = 1111b и значит мы производим разбивку по 4-ой цифре, т.е. (1010)b и (1011)b. Это и даёт нам конечный результат.

Двойчная арифметика. Сейчас мы заново научимся складывать числа столбиком :) 1011101 +1111001 11010110 Правила всё те же, что и для десятичной системы, но нужно помнить, что 1b + 1b = 10b. Вычитание - это всё наоборот, 10b - 1b = 1b, а правила - знакомые со школы!

А теперь поговорим об отрицательных числах. Начнём с простого числа (-1). Как же можно представить его в двоичном виде ?? Ответ кроется в следуещем соображении: (-а) = 0 - а :))) Тут вроде бы всё ясно, НО какой глубокий смысл! Рассмотрим число (-1): (-1) = 0 - 1, а теперь в двоичном виде: 000000000 -000000001 111111111 Каково ??? Удивительно, но это логично: попробуйте к 111111111111b прибавить 000001b и получится 0 !!!! Это очень интересное свойство двоичных чисел.

Ну а перевод отрицательных двоичных в 10-ую систему происходит так: переворачиваем все цифры на противоположные, т.е. вместо 0 ставим 1 и наоборот. 11111011b -> 00000100b переводим полученное в Dec 00000100b = 4 добавляем 1 4 + 1 = 5 ставим знак минус 5 -> -5 Ладно, а теперь всё проверим..... Запускаем виндовский калькулятор, ставим галочку Bin, вводим 11111011, ставим галочку Dec, и ...... видим на экране 251 ??? Что-то тут не так! В душу вкладывается сомнение: а не гон ли всё это? Устроим ещё одну проверку: берём (-5), ставим галочку Bin, и видим число : 1111111111111111111111111111011 ? Похоже, но не то! (Кстати попробуйте перевести его обратно в Dec :)). Вся фишка заключается в том, что виндовский калькулятор: не умеет преобразовывать отрицательные Bin в Dec. Об числе 1111111111111111111111111111011b : всё дело втом, что когда мы вычитали из 000b 001b, то мы не учли одной очень нужной вещи: к числу можно добавить любое количество нулей слева!! Т.е. 0 у калькулятора выглядит так: 00000000000000000000000000000000b :)) Вот и весь прикол! В (-1) на самом деле бесконечное множество 1.

А теперь ещё одно маленькое соглашение: что бы не уподобляться виндовскому калькулятору и не путать отрицательные числа с положительными (в Bin разумеется), мы будем писать положительные числа, добавляя слева нуль (например: 1 = 01b, 2 = 010b и т.д.), а отрицательные без него (-1 = 1111b)! Тем самым мы предотвратим возможную путаницу!
А нафига они нужны - эти системы?

Да уж волнующая тема! Теперь появилась ещё одна система, а зачем оно ? Ок. Начну отдалённо. Наименьшей единицей хранения информации является бит (ну это, как секунда в СИ). Соответственно бит может принемать два состояния, которые условно называют правда и ложь. Для обозначения этого можно использовать 1 (правда) и 0 (ложь). Чуствуете ? Пахнет двоичной системой счисления! Из бит складываются байты. 1 байт = 8 битам. Т.е. что бы закодировать 1 байт нам нужно написать последовательность из 8 битов: 10110110 Сколько же может быть комбинаций еденичек и нулей? Оказывается всего 256. Этих 256 комбинаций хватает, что бы закодировать в них символы алфавита, поэтому с помощью 1 байта мы можем представить символ подчти каждого алфавита. Естественно, что мы таким образом кодируем номер символа, а выводом нужного знака на экран по этому номеру занимается видеокарта. Хорошо, отношение двоичной системы к битам вроде бы понятно, но шеснадцатеричная-то тут при чём??? Да вообщем-то она и не при делах :) Просто её удобнее использовать. В самом деле hex-число, состоящее из 2-х знаков полнотью описывает все 256 возможных комбинаций. FFh = 255 (256 комбинацию составляет число 00h). Получается, что 1 шеснадцатеричная цифра может закодировать пол-байта (это так называемый огрызок, или нибл). Согласитесь чем для каждого байта писать восемь цифр удобнее написать две, а после окажется, что рабтотать с ними удобнее, чем с десятичными.
Послесловие

Думаю, если вы вникли во всё выше сказанное, то смысл фразы будет вам понятен: в мире существует 10 категорий людей: те, которые понимают двоичную систему счисления и те, которые её не понимают :))

Ну вот теперь вы изучили мат. часть :) Это самое главное! Со следующего выпуска мы начнём писать программы на Паскале. Если вы ещё им не обзавелись, то самое время это сделать. На сайте в разделе Инструменты лежит пара ссылок, на работо способность они к сожалению не проверены. Лучшим же выходом является попрежнему покупка CD диска с Паскалем. Напомню, что нам нужен Borland Pascal 7 (или Turbo Pascal 7). На этом всё.

Теория

Четверг, 06 Августа 2009 г. 20:06 + в цитатник
Для начала разоберёмся с шестнадцатеричной системой счисления. Ничего сложного в ней нет. Мы используем в жизни десятичную систему. Поэтому объяснения начну с аналогий: В десятеричной системе мы используем десять цифр - от 0 до 9 => в шестнадцатеричной цифр должно быть 16. С первой десяткой вроде ясно (те же арабские цифры от 0..9), а как быть с остальными?? Этот вопрос решили просто - взяли первые шесь букв латинского алфавита. Таким образом получается такой набор цифр:

0 1 2 3 4 5 6 7 8 9 A B C D E F

В дальнейшем, для предотвращения путаницы шестнадцатеричные числа я буду писать, ставя на конце букву h или H (например 12A4Dh ) H - это сокращение от англ. hexadecimal (шестнадцатеричное). Для краткости его иногда называют просто Hex. Вообщем-то h пришло из языка Ассемблера. Важно сразу же понять, что десятичные и шестнадцатеричные числа равны только в промежутке от 0..9, т.е. 10 = Аh, 11 = Bh .... 15 = Fh, а 11 не равно 11h.

Преобразование из шеснадцатеричной (HEX) в десятичную (DEC).

Для первода числа в Dec необходимо последовательно начиная с самой левой цифры умножать на 16 и складывать со следующей цифрой. Так как операции выполняются в 10-ом формате, то необходимо цифры A..F преобразовать в 11..15 :) Пример преобразования числа A7B8h:

Первая цифра А(10)
Умножаем на 16

Прибавляем следующую цифру, 7

Умноить на 16

Прибавить следующую цифру, В(11)

Умножить на 16

Прибавить следующую цифру, 8
Десятичное значение 10

Есть ещё один способ перевода из Hex в Dec: A7B8h = 10 * 16 3 + 7 * 16 2 + 11 * 16 1 + 8 * 16 0 = 42936 Этот способ по-моему несколько проще: берём самую правую цифру и умножаем на 16 в 0 степени, сдвигаемся на одну цифру влево и умножаем на 16 в 1, ......... и т.д. пока не дойдём до конца. Вспомните из математики: любое число в 0 степени равно 1 (кроме 0 есстественно)! Вся сложность этого метода состоит в том, что нужно помнить много степеней 16, на первый взгляд это тяжело, но по-переводив пару сотен чисел :) степени запомнятся сами собой. Теперь поговорим об обратном преобразовании из Hex в Dec. Для преобразования необходимо сначала исходное число разделить на 16; число получившеесе в остатке является младшей шестнадатеричной цифрой. Затем уже частное поделить на 16 и полученый остаток даст следующую влево 16-ую цифру. Продолжая таким образом пока в частном не получится 0, из остатков получим все необходимые 16-ые цифры. Тут нужно незабывать делать обратные преобразования, т.е. 10 преобразовывать в А, 11 в B и т.д. Пример переведём число 42936 в Hex: Частное Остаток Шестнадцатиричное значение

42936 / 16 2683 8 8 (младшая цифра)
2683 / 16 167 11 B
167 / 16 10 7 7
10 / 16 0 10 A (cтаршая цифра)


Тем самым ответ: 42936 = A7B8h. Не забудьте, что результат пишется, как бы наоборот, т.е. первый остаток является последней цифрой искомого числа!

Дома не забудьте попрактиковаться - переводите числа на листочке из одной системы в другую, благо есть чем проверять!
А нафига она нужна - эта система?

Да уж! Такой вопрос сразу же возникнет у многих. И в самом деле - всю жизнь обходились десятичной и жалоб не было, а тут понимаешь ли подают какую-то непонятную полубуквеную систему, нафига она нужна ?

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

Главу ассамблеи азербайджанцев Грузии посадили на четыре с половиной года

Четверг, 06 Августа 2009 г. 19:58 + в цитатник
Руководитель Национальной ассамблеи азербайджанцев Грузии (НААГ) Дашгын Гюльмамедов приговорен к 4,5 года лишения свободы по обвинению в мошенничестве и присвоении полномочий должностного лица, сообщает 6 августа информагентство Trend.

Как передает Day.Az, уголовное дело против Гюльмамедова было возбуждено в декабре 2008 года. В феврале он был объявлен в розыск, а в марте задержан в Баку. Подробности уголовного дела неизвестны.

Общественно-политическая организация НААГ была создана в 2001 году. Участники этой организации борются за права азербайджанцев, живущих в Грузии, в том числе выступают за признание азербайджанского одним из официальных языков Грузии, а также за создание азербайджанского телеканала.

Как сообщалось ранее, в НААГ арест Гюльмамедова считают частью "тайного плана правительства Азербайджана подавить движение азербайджанцев в Грузии".

Время собирать фишки

Четверг, 06 Августа 2009 г. 19:57 + в цитатник
Российские казино приглашают в СНГ и Европу

Со времени запрета на организацию и проведение азартных игр в России прошло больше месяца. Пока возобновлять деятельность казино и игровых клубов никто не собирается, поэтому российский игорный бизнес активно ищет новое "место прописки". Предложений из-за рубежа крупным казино поступило уже немало.


Пресс-конференция посла Киргизии в России Раимкула Аттакурова, состоявшаяся 6 августа, оказалась яркой на целый ряд неожиданных заявлений. Аттакуров, в частности, отдал "Газпрому" контрольный пакет акций "Кыргызгаза", а также заявил о планах по проведению футбольного матча между киргизскими гастарбайтерами и московскими скинхедами.

Но для игорного бизнеса гораздо важнее оказались другие слова Аттакурова, почти не растиражированные СМИ. На конференции посол Киргизии предложил российским казино переехать… на Иссык-Куль – самое большое озеро в Киргизии и одну из главных достопримечательностей страны.

По словам Аттакурова, власти Киргизии планируют построить на берегу озера игорный комплекс под незамысловатым названием "Казино". Когда будет возведено "Казино" – неизвестно, так что по степени готовности киргизский проект пока напоминает долгострой российских игорных зон, куда, по задумке чиновников, и должны были отправиться все рулетки и любители азартных игр. Пока ни одна из зон не работает – и неизвестно, когда будет работать.

Заявление Аттакурова, несмотря на всю неопределенность планов Киргизии, тем не менее, весьма показательно. Оно лишний раз доказывает, что на экономических просчетах России не прочь заработать ее соседи.
От Киргизии до Латвии

Оборот казино и залов игровых автоматов в России оценивался в 3,6 миллиарда долларов ежегодно. Значительная часть из этих денег шла в федеральный и региональные бюджеты, но недополучение огромных
Берег Иссык-Куля. Фото пользователя Headscarf с сайта wikipedia.org

средств не смутило чиновников, активно взявшихся за борьбу с игроманией.
Берег Иссык-Куля. Фото пользователя Headscarf с сайта wikipedia.org


Зато многие другие страны тут же объявили о готовности приютить у себя пострадавший бизнес. Одними из первых на запрет казино и залов игровых автоматов отреагировали в Белоруссии. По данным портала Slon.Ru, в Белоруссии сейчас располагается около восьми тысяч казино и залов игровых автоматов, но ни одно из этих заведений не может сравниться по объемам с их вымершими московскими конкурентами. Да и доходы бюджетов от местных казино весьма невелики: всего 13 миллионов долларов в год.

Поэтому неудивительно, что экспансия российских казино за рубеж началась именно с Белоруссии. В середине июля местные СМИ сообщали, что в Минске вот-вот откроется "Шангри Ла" с 12 игровыми столами и 70 игровыми автоматами.

В компании Storm International, которой принадлежит "Шангри Ла", утверждают, что белорусским рынком не ограничатся. Во всяком случае, еще одно казино – X.O. – планируется открыть в Бишкеке. Кроме того, в середине июля портал BFM.Ru сообщал и об интересе компании к таджикскому рынку: Storm International начала поиск специалиста по подбору персонала в этой стране.

Проект привлечения туристов из России с помощью казино разработали и в Латвии. Недавно выбранный мэром Риги Нил Ушаков заявил, что в столице Латвии необходимо создать "маленький Лас-Вегас". Для этого, по мнению Ушакова, надо собрать игорные заведения города под одну крышу многофункционального центра. Этот центр и будет, по замыслу мэра, привлекать азартных россиян.
Запрет на азартный бизнес может обернуться для России потерей не только миллиардов долларов налогов и инвестиций, но и "культурных ценностей". Во всяком случае, Алла Пугачева уже заявила, что намерена переехать в Киев или Минск, потому что там есть, где поиграть.


Любопытно, что в Латвии в 2005 году также пытались почти полностью запретить игорную деятельность, но бизнесмены сумели добиться отмены этого решения. В итоге только государственный бюджет получает от "игровиков" два миллиона латов (4,09 миллиона долларов) налоговых поступлений, а в Риге располагается около 12 тысяч игровых автоматов.
За пределами СНГ

На российские казино летом 2009 года стали претендовать не только страны из числа бывших советских республик. В конце июля, например, стало известно, что в столице Болгарии Софии будет возведено казино стоимостью в 100-120 миллионов евро, которое построят три российские компании и одна болгарская. Кто именно из россиян заинтересовался инвестициями в Болгарию, неизвестно, но, по данным болгарской стороны, среди них есть компании, владевшие крупными казино в Москве.

Не осталась в стороне и Черногория, которая летом становится едва ли не сплошь российской из-за обилия отечественных туристов. Во всяком случае, группа компаний "Корстон", (владелец Korston Hotel & Casino Moscow) готовится развивать игорный бизнес в отеле The Queen of Montenegro – он принадлежит "Корстон" на 75 процентов.

Закрытое московское казино. Фото Мити Алешковского для "Ленты.Ру"

Другие российские бизнесмены забрались еще дальше. Бывший владелец казино Premier, Goodwin и "Слава", группа СЭТ, будет развивать проекты в Аргентине, а также Эстонии и той же Черногории, сообщал в середине июля порта BFM. А Ritzio Entertainment, известная по игровым залам "Вулкан" и "Миллионъ", уже открыла свои отделения в Германии и Италии. Кроме того, компания планирует развиваться за счет Южной Европы – Хорватии, Сербии и, опять-таки, Черногории.

Иными словами, российские игровые компании в связи с запретом на казино и игровые клубы не пропадут, а азартные россияне, особенно из числа богатых, найдут места, где потратить свои средства и вне России. Вот только налоги "игровики" теперь будут платить в казну других стран.

Что касается амбициозных проектов по возведению больших игорных комплексов в СНГ, то они имеют один очевидный минус: большинство из них находится в стадии планирования. Следовательно, их возведение займет по крайней мере несколько лет. За это время могут ожить игорные зоны внутри России. А, может, и сам запрет на игорный бизнес отменят…

Россия и Турция подписали соглашение о строительстве "Южного потока"

Четверг, 06 Августа 2009 г. 19:56 + в цитатник
Премьер-министры России и Турции Владимир Путин и Реджеп Эрдоган подписали протокол о сотрудничестве в газовой сфере, предусматривающий предварительное согласие турецкой стороны на строительство газопровода "Южный поток" (South Stream) в своих территориальных водах. Об этом сообщает "Интерфакс".

Согласно документу, Турция также даст России разрешение на проведение в турецких территориальных водах изысканий по "Южному потоку".

Предполагается, что "Южный поток" обеспечит поставки газа в Европу в обход Украины. Маршрут газопровода пока точно не определен, однако планируется, что сначала он будет идти из России в Болгарию по дну Черного моря, а затем разделится на две ветки. Одна из них будет транспортировать газ в Грецию и на юг Италии, а вторая - в Сербию, Венгрию и Австрию.

О том, что турецкая сторона согласилась пустить "Южный поток" через свои воды, стало известно 5 августа, когда об этом сообщали РИА Новости со ссылкой на замглавы аппарата правительства России Юрия Ушакова. Тогда же сообщалось, что согласие Турция дала за месяц до визита российского премьера. Источники газеты "Коммерсант" упоминали, что в случае если турецкая сторона даст России допуск в территориальные воды, то "6 августа можно будет считать днем рождения South Stream".

В российско-турецком газовом соглашении также упомянуты планы сотрудничества сторон по проекту "Голубой поток - 2". Эта ветка газопровода пройдет параллельно "Голубому потоку - 1" из РФ в Турцию, который уже построен, а затем через ближневосточные государства будет направлен в Израиль. В ближайшее время "Газпром" намерен провести переговоры с Турцией и Израилем относительно реализации данного проекта.

Стороны также договорились о возведении в Турции крупных подземных хранилищ газа (ПХГ), передает РИА Новости.

Кроме того, представители России и Турции подписали 6 августа протокол о сотрудничестве в сфере атомной энергетики. Согласно документу, в Турции примерно в 200 км от Антальи будет построена первая в стране АЭС. Пока единственным претендентом на проект является консорциум российских "Атомстройэкспорта" и "Интер РАО ЕЭС", а также турецкой Park Teknik.

При этом стороны смогли согласовать стоимость электроэнергии, которую будет производить будущая АЭС. Первоначальное предложение консорциума составляло 21,13 цента за киловатт-час, однако теперь цена снижена до 15,33 цента за киловатт-час.

Лечение интернет-зависимости закончилось смертью китайского подростка

Четверг, 06 Августа 2009 г. 00:36 + в цитатник
Китайский подросток, лечившийся от интернет-зависимости, скончался в реабилитационном центре, сообщает The Times. Родители ребенка обратились к региональным властям с просьбой провести справедливое расследование причин инцидента.

15-летний Дэн Сэньшань (Deng Senshan) был помещен в реабилитационный центр в Гуанси-Чжуанском автономном районе Китая 1 августа. Родители подростка хотели таким образом помочь ему избавиться от интернет-зависимости.

По словам отца мальчика, сотрудники медицинского учреждения поместили ребенка в одиночную камеру через несколько часов после его прибытия в центр. Около трех часов 2 августа Дэн Сэньшань скончался в больнице города Наньнин.

О смерти сына отцу сообщили лишь через сутки. Он позвонил в реабилитационный центр, однако руководство учреждения отрицало смерть ребенка. Сообщается, что прибыв на опознание, отец заметил кровь на лице мальчика, на теле погибшего были многочисленные синяки, на руках – следы от наручников.

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

Как заявил один из хирургов больницы, в реанимационном отделении которой скончался Дэн Сэньшань, местная полиция изъяла все медицинские записи подростка в интересах следствия. По словам сотрудников правоохранительных органов, четверо подозреваемых задержаны, расследование этого дела продолжается.

В ноябре 2008 года органы здравоохранения Китая официально признали интернет-зависимость болезнью. Были разработаны диагностические критерии и рекомендации по лечению данного расстройства. Психиатрическим клиникам предписано оказывать помощь пациентам с этим заболеванием.

В июне 2009 года появились сообщения о том, что в одной из клиник для лечения интернет-зависимости используется электросудорожная терапия. 14 июля китайский Минздрав признал такое лечение небезопасным и рекомендовал медицинским учреждениям отказаться от его использования.

В России начались продажи Wii Sports Resort

Четверг, 06 Августа 2009 г. 00:32 + в цитатник
В России начались официальные продажи игры Wii Sports Resort для консоли Wii, сообщается на официальном сайте российского подразделения Nintendo. Игра появилась на прилавках магазинов в среду, 5 августа. Жители остальных европейских государств получили возможность поиграть в Wii Sports Resort еще 24 июля текущего года. Японский релиз состоялся 25 июня.

Проект Wii Sports Resort представляет собой сборник из 12 мини-игр. Основной упор разработчики сделали на летних видах спорта - геймеры могут побросать фрисби, покататься на каноэ, водном мотоцикле или водных лыжах, а также объехать на велосипеде тропический остров Wuhu.

Новая игра продается в комплекте с устройством под названием Wii MotionPlus. Этот аксессуар присоединяется к контроллеру Wii Remote, повышая его точность. По словам разработчиков, Wii MotionPlus позволяет консоли Wii отслеживать практически все движения игрока.

Сборник Wii Sports Resort пользуется хорошим спросом в Японии. К 26 июля геймеры купили свыше 750 тысяч копий этой игры. Первая часть Wii Sports, в который было представлено всего пять мини-игр, вышла в конце 2006 года. Сборник продается в комплекте с приставкой Wii во всех регионах кроме Японии и Южной Кореи. На днях стало известно, что во всем мире продано уже 47,62 миллиона копий Wii Sports.


Поиск сообщений в blackspace
Страницы: 5 4 3 [2] 1 Календарь