Scilab: различия между версиями

Содержимое удалено Содержимое добавлено
Нет описания правки
разбросано по страницам
Строка 25:
Несомненно основным преимуществом данного продукта является его открытость. По функциональности среда ничуть не уступает таким коммерческим собратьям, как Matlab, идеями которого вдохновлялись разработчики Scilab, и Mathcad. Привыкание к командной строке происходит достаточно быстро, особенно, если постоянно использовать среду по поводу и без повода.
 
== Установка окружения ==
Данный программный продукт распространяется под лицензией CeCILL, что даёт право:
* свободного запуска программы с любой целью;
* свободного изучения исходного кода программы;
* свободного распространения копий исходного и исполняемого кода;
* свободного улучшения программы.
 
Окружение Вы можете скачать с официального сайта разработчиков [http://www.scilab.org/download/ www.scilab.org]. Пройдя по ссылке, Вам необходимо будет выбрать установочный файл, в зависимости от операционной системы, установленной на Вашем персональном компьютере, и разрядности Вашего процессора. Если Вы не знаете разрядность вашего процессора, то смело устанавливайте 32-х разрядную версию программы. При написании учебника, автор пользовался версией программы 5.4.1 для 64-х разрядного процессора.
 
Scilab — это кроссплатформенное окружение, которое поддерживает следующие операционные системы: Windows, начиная с версии XP, от компании Microsoft; Mac OS X от компании Apple; Unix-подобные операционные системы, собранные на основе Linux-ядра. Отметим, что для Unix-подобных операционных систем данная среда изначально и разрабатывалась.
 
Установка для рядового пользователя не должна составить каких-либо особых трудностей: единственное, что попросит сделать установочная программа, это выбрать каталог на жёстком диске и указать набор пакетов, которые следует установить (рекомендуется установить все пакеты, которые идут в стандартной комплектации). Помимо этого, для платформы Intel может быть предложена установка дополнительных расширений, позволяющих ускорить расчеты за счёт оптимизации потока процессов ЦП компьютера.
 
Более опытные пользователи могут собственоручно скомпилировать исходный код, воспользовавшись доступным компилятором.
 
== Знакомство с пользовательским интерфейсом ==
В этом разделе мы познакомимся с интерфейсом пользователя. Несмотря на то, что для всех платформ работают одни и те же программные коды, пользовательские интерфейсы в разных операционных системах немного отличаются друг от друга. Эти отличия заключаются главным образом в отображении строки меню.
 
Пользовательский интерфейс мы рассмотрим из-под Windows (пусть это вас не пугает, так как принципы едины во всех операционных системах). На рисунке 1 показан интерфейс программы. Немного оговорюсь на счет Unix-подобных систем. При первом запуске вы можете не увидеть такой вид, который показан на рисунке 1 (скорее всего загрузится только '''Командное окно'''). В этом случае прочитайте сначала [[Scilab#Интерфейс в Unix-подобных системах на примере Ubuntu 12.04 LTS|этот раздел]], а потом возвращайтесь сюда.
[[Файл:Scilab window.PNG|right|thumb|600px|Рисунок 1 Пользовательский интерфейс в Windows 7]]
На рисунке 1 вы можете наблюдать, что внутри большого окна располагается ещё 4 более мелких:
* '''Обозреватель файлов''';
* '''Командное окно''';
* '''Обозреватель переменных''';
* '''Журнал команд'''.
 
В каждый момент времени активным может быть только одно из видимых окон и признаком этого служит подсвеченный заголовок. На рисунке 1 активным является окно '''Командное окно'''. Отметим, что все окна не привязаны жёстко друг к другу и могут быть исключены из основного окна или заново перегруппированы.
 
Условно назовём вид, представленный на рисунке 1, группой окон. В любой момент каждое окно может быть исключено из группы путём нажатия на командную кнопку ''Исключить'' ({{lang-en|Undock}}), которая представлена в виде кнопки со стрелочкой, стоящей между кнопками ''Справка'' ({{lang-en|Help on component}}) и ''Закрыть'' ({{lang-en|Close}}) на заголовке окна (см. рисунок 1). После исключения, окно может быть перемещено в любую точку рабочего стола.
 
Чтобы перегруппировать окна, необходимо ухватить заголовок окна, зажимая ''левую кнопку мышки'', и перетащить курсор в желаемую позицию. «Фантом» в виде серой рамки будет подсказывать как встанет окно, если вы отпустите левую кнопку мыши, и здесь возможны следующие варианты:
* если вы попали курсором в какое-то окно группы, то перемещаемое окно поделит область по горизонтали пополам и займет свою позицию;
* то же, что и в предыдущем пункте, но по вертикали;
* окно не будет ничего разбивать, а просто вложится. В этом случае внизу появятся вкладки.
Исключённое окно может быть включено в любую группу. Для этого нужно захватить её заголовок и выполнить те же действия. '''Очень важно''' то, что хватать нужно не внешний заголовок окна, который генерируется операционной системой, а внутренний заголовок, на котором есть элементы управления ''Справка'', ''Исключить'' и ''Закрыть''.
 
Перегруппировка требует практики, так как тот или иной вариант будет предложен в определенной позиции курсора. Попрактикуйтесь немного и выполните следующее упражнение.
<!-- Отделить -->
{|
|style="background-color:Orange"|<big>'''Упражнение'''</big>
|-
|style="background-color:WhiteSmoke"|
Выполните следующее:
# Сделайте активным '''Командное окно''';
# Введите команду <source lang=scilab>--> scinotes();</source>и нажмите клавишу <Enter> (не уделяйте её смыслу пока особого внимания). Перед вами должно появится окно встроенного текстового редактора ''SciNotes'';
# Нажмите клавишу <F1> и перед вами появится окно со справкой;
# Имея текущий набор окон, перегруппируйте их так, как показано на рисунке ниже. а затем верните все в прежний вид (как показано на рисунке 1).
 
[[Файл:Task1.png|center|thumb|900 px]]
|}
<!-- конец отделения -->
 
Вы могли убедиться, когда переключались между окнами, что среда обладает незамысловатым интерфейсом и содержит минимум элементов, что идёт только в плюс. Переключаясь на определенное окно вы можете заметить, что изменяется панель с инструментами группы и строка меню под это окно. В целом нет надобности расписывать каждую кнопку, так как всё интуитивно просто и понятно. Рекомендую читателю посмотреть все настройки, которые предоставляются пользователю в графическом режиме. Для этого:
# Сделайте активным '''Командное окно''';
# Затем вверху выберите ''Правка'' ({{lang-en|Edit}});
# В раскрывшемся меню нажмите на ''Настройки''.
 
Коротко рассмотрим назначение каждого окна.
 
=== Командное окно ===
Командное окно — самое главное окно, посредством которого происходит общение со средой. В данное окно пользователь вводит команды и получает результаты.
 
На рисунке 1 в командном окне можно наблюдать техническую информацию о загрузке окружения, после которой система приглашает пользователя ввести команду. Начало строчки сопровождается стрелкой, указывающей направо (-->), которая и называется приглашением. Попробуйте ввести следующий код
<source lang=scilab>
--> 2*2+69/25
</source>
В ответ от интерпретатора вы получите следующее
<source lang=scilab>
--> 2*2+69/25
ans =
6.76
</source>
Другими словами, вы передали среде алгебраическое выражение, которое было ей рассчитано, а результат помещён в автоматически создаваемую переменную ''ans'', с которой мы познакомимся позднее. Введя эту команду, вы внесли переполох в оставшихся окнах.
 
Перед тем как мы перейдём на следующее окно, введите вторую команду.
<source lang=scilab>
--> myVariable=26;
</source>
Этой командой вы попросили среду выделить память под новую переменную с именем ''myVariable'' и присвоить ей значение 26. Обратите внимание на точку с запятой в конце команды. Введя этот символ, вы попросили интерпретатор не выводить информацию о результате, получаемом после команды, к которой приставляется точка с запятой.
 
Например, попробуйте ввести
<source lang=scilab>
--> anotherVariable=31
</source>
и вы получите ответ, что присваивание прошло
<source lang=scilab>
--> anotherVariable=31
anotherVariable=
31.
</source>
Блокирование вывода результата бывает полезным в случаях, когда результат оказывается очень большим, тривиальным или неудобным для изучения.
 
=== Обозреватель переменных ===
[[Файл:VViewer.PNG|right|300px|thumb|Рисунок 2 Окно обозревателя переменных]]
Это окно появилось относительно недавно и призвано облегчить работу с объектами, которые создал пользователь. Если вы попробовали ввести предыдущие команды, то можете наблюдать результат, показанный на рисунке 2.
 
В этом окне отображается вся необходимая информация о созданных переменных в частности:
* ''имя переменной'';
* ''размер переменной'';
* ''тип переменной'' или другими словами тип данных, которая эта переменная в настоящий момент хранит;
* ''видимость переменной''.
Нажав по переменной дважды откроется окно ''редактора переменных'', которое показано на рисунке 3.
[[Файл:Editor.PNG|left|thumb|300px|Рисунок 3 Окно редактора переменных]]
''Редактор переменных'' — это ещё одно новшество. Вероятно вы спросите, почему в редакторе переменная представлена таблицей, на что вам будет дан вполне внятный ответ:
<blockquote>
Все объекты в среде Scilab являются двухмерными массивами.
</blockquote>
Переменные, которые были нами созданы ранее, являются просто-напросто вырожденным случаем — массивом с одним элементом. Мы ещё не раз вернемся к этому вопросу, а пока внимательно рассмотрите редактор переменных.
 
На рисунке 3 показана переменная ''myVariable'', которой было присвоено значение 26. Поменяйте значение переменной дважды щёлкнув по значению 26 и введя, к примеру, 51, а затем нажмите клавишу <Enter> или щёлкните в любом другом месте окна.
 
О том, что значение переменной изменилось, вы уже можете узнать из командной строки. Сделайте активным окно командной строки и введите имя нашей переменной, т.е.
<source lang=scilab>
--> myVariable
myVariable =
51.
</source>
Конечно показанный способ редактирования переменной является не самым рациональным, так как редактировать массив с одним полем проще всего из той же командной строки. Редактор же используется в случаях, когда необходимо редактировать большие массивы.
 
Не бойтесь, если вы пока ничего не понимаете. Мы ещё не раз вернемся ко всем этим вопросам.
 
Всё, что вы сейчас видите в этом окне — вершина айсберга. За этой вершиной скрывается ещё целая куча системных переменных, которые регулируют работу окружения и часть которых пользователь может контролировать. Чтобы их увидеть в окне, сделайте следующее:
# Сделайте активным окно '''Обозреватель переменных''';
# На панели меню вверху выберите пункт ''Фильтр'' ({{lang-en|Filter}});
# В раскрывшемся меню снимите галочку с пункта ''Скрывать системные переменные''.
Рассмотрите эти переменные, но ни в коем случае не пробуйте их редактировать.
 
=== Журнал команд ===
[[Файл:Journal.PNG|left|300px|thumb|Рисунок 4 Окно журнала команд]]
Окно журнала команд отражает все команды, которые вводил пользователь в командную строку в течении текущей сессии. На рисунке 4 показано окно журнала команд. Содержимое окна рисунка 4 может отличаться от вашего, так как автор при написании книги то и делал, что отвлекался.
 
Вы можете видеть записи последней сессии, которые отражают все введенные нами команды. Все журналы бережно сохраняются средой, чтобы вы могли вспомнить и восстановить команды, которые вводили ранее. Это может быть полезным, если вы забыли сохранить коды и завершили сессию или, другой пример, если вы ввели очень длинную команду ранее, а теперь вам нужно ввести похожую, но лишь с небольшой разницей, или если сессия была прервана из-за плохо отлаженного модуля, а команды вам ещё нужны.
 
Тем не менее, если вам не нужны журналы, вы всегда их можете удалить или очистить, воспользовавшись командами меню.
 
=== Интерфейс в Unix-подобных системах на примере Ubuntu 12.04 LTS ===
[[Файл:Scilab1.png|right|thumb|400px|Первый запуск Scilab 5.4.1]]
При первом запуске программы скорее всего вы увидите картину, показанную на рисунке 5. Как вы можете видеть, минимализм на лицо.
 
Чтобы привести все к виду, показанному на рисунке 1, вам нужно открыть окна '''Обозреватель переменных''' ({{lang-en|Variable Browser}}) и '''Журнал команд''' (({{lang-en|Command History}})). В отличие от версий для Windows и для Mac OS, здесь нет окна '''Обозревателя файлов''', что связано с разницей в организации хранения файлов (т.е. в Unix-подобных системах в обозревателе нет смысла, так как для каждого пользователя выделяется отдельная директория).
 
Чтобы открыть эти окна выполните простые действия:
# В строке меню вверху окна нажмите на ''Приложения'' ({{lang-en|Applications}});
# В раскрывшемся меню вам требуется нажать по соответствующим пукнктам.
В отличие от версии для Windows, вам сразу видны служебные переменные, но только те, которые вы можете редактировать. '''Настоятельно''' рекомендую вам не редактировать их, не узнав о их назначении. Обратите внимание, что каждое окно как и в Windows имеет внутренний заголовок, который предназначен для образования групп из окон.
 
В отличие от Windows и Mac OS, настройки интерфейса сократились до трёх окон: ''Настройка шрифта'' ({{lang-en|Font Chooser}}), ''Настройка цвета фона'' ({{lang-en|Console Background}}) и ''Настройка цвета шрифта'' ({{lang-en|Console Font}}). Вызвать эти окна вы сможете из раскрывающего меню ''Предпочтения'' ({{lang-en|Preferences}}) или, нажав на соответствующую иконку на панели инструментов.
 
На этом разница между интерфейсами заканчивается.
 
== Работа с сессией ==
Мы начнём наше изучение с самого простого — управления сессией. Сессией называется отрезок времени, начинающийся с ввода первой команды после запуска программы, и заканчивающийся закрытием программы. Во время сессии среда ведёт историю, в которой отражаются введённые команды и результаты. Многие моменты сессии скрыты от глаз пользователя, например, такой момент, как инициализация среды, выделение памяти под массивы, проверка на ошибки, но это нас пока не волнует.
 
Большую часть времени в сессии пользователь проводит в командной строке, которая работает в режиме интерпретатора, т.е. результат виден сразу после ввода команды. Если вы изучаете этот учебник последовательно, то уже пробовали вводить некоторые команды.
 
В дальнейшем вы убедитесь, что пользовательский интерфейс создан только для упрощения работы со средой и вообще говоря не нужен, потому что любое действие в среде можно осуществить вводом соответствующей команды. Вообще говоря, нажимая на какую-либо иконку, вы заставляете ввести эту команду с определенными аргументами за вас.
 
В дальнейшем, для ускорения работы со средой, я рекомендую вам заучивать наиболее часто используемые команды и их параметры. Это позволит вам работать со средой из командной строки операционной системы (т.е. без каких-либо графических штучек), да и вообще вы сразу почувствуете себя профессионалом.
 
Для начала запомните и попробуйте следующие горячие клавиши:
# Сначала нажмите <Ctrl>+<C>;
# Затем нажмите <Ctrl>+<X>.
Вы увидите такой результат
<source lang=scilab>
-->
 
Введите «resume» или «abort» для возврата на стандартный уровень командной строки.
-1->
-2->
</source>
 
Вы нажали комбинации, которые выполнили одно и то же действие — создали подуровень, т.е. как бы в одной сессии вы открыли одновременно три. На каждом подуровне своя область памяти для хранения переменных. Данная система работает по принципу стека «первым вошёл, последним вышел». Это означает, что выход из подуровня очищает безвозвратно область памяти, выделенную на него.
 
Выполните следующее:
# Введите на втором подуровне выражение<source lang=scilab>-2-> 2+2;</source>
# Нажмите еще раз любую комбинацию, чтобы создать подуровень;
# Введите еще раз<source lang=scilab>-3-> 2+2;</source>
 
Теперь посмотрите в окно '''Обозреватель переменных''' и вы увидите, что «в мире» сосуществуют две переменные с одинаковым именем. Это происходит потому, что они не подозревают о существовании друг друга.
 
Чтобы подняться на уровень выше, необходимо ввести команду
<source lang=scilab>
resume
</source>
 
Если вы уверены, что подуровни вам больше не нужны, то удалить их можно все сразу командой
<source lang=scilab>
abort
</source>
после которой вы окажетесь на главном уровне с единственной областью памяти для переменных.
 
Данные подуровни созданы для упрощения работы со средой, в частности, чтобы не захламлять память неиспользуемыми переменными.
 
Вот вам пример использования многоуровневой работы. Допустим Основная задача содержит подзадачу, после решения которой вам нужен только результат. Решив подзадачу, вам требуется удалить всё, что от неё осталось. Считайте вам повезло, если для решения подзадачи вам понадобилась всего одна переменная, но если вы писали временные функции, использовали матрицы, векторы и прочее, вам потребуется время на очистку памяти.
 
Как же можно поступить? Решив подзадачу, вы всегда можете перенести нужные вам результаты на уровень выше, воспользовавшись командой ''resume''. При этом за одну операцию вы не только переносите нужную вам информацию, но и очищаете память от переменных подзадачи.
 
{|
|style="background-color:Orange"|<big>'''Упражнение'''</big>
|-
|style="background-color:WhiteSmoke"|
Для начала удалите все подуровни, оставив только основной, командой ''abort''. Положим, что нам нужно решить полиномиальное уравнение второго порядка, корни которого будут использованы для каких-либо решений. Отметим, что нам важен лишь результат и ничего больше.
 
Так как читающий пока ничего не знает о возможностях данной среды, будем действовать в лоб и решим уравнение так, как учили в школе на математике. Уравнение, которое необходимо решить, представлено ниже.</br>
<center><math>2\cdot x^2+4\cdot x-10=0.</math></center></br>
# Для начала создадим два подуровня, с помощью одной из двух комбинаций клавиш.
# На втором подуровне вычислим [[дискриминант]], введя<source lang=scilab>-2-> D=4^2-4*2*-10;</source>
# Теперь мы заберем результат на первый подуровень, а второй удалим. Для этого введите следующее<source lang=scilab>-2-> D=resume(D)</source> Отметим, что Вы попросили среду переместить значение D второго уровня в переменную D уровня выше, а всё остальное удалить. Так как пространство первого уровня пусто, то переменная D будет создана системой, но если бы это имя было занято, то переносимый результат был бы записан в уже имеющуюся переменную.
# На первом уровне рассчитаем корни, для чего введите<source lang=scilab>-1-> x1=(-4+sqrt(D))/4, x2=(-4-sqrt(D)/4)</source> Обратите внимание на то, что мы ввели две команды за раз, разделив их запятой. Таким образом, мы нашли два вещественных корня, записав их соответственно в переменные x1 и x2.
# Дискриминант нам уже не нужен, а корни необходимо перенести на главный уровень. Чтобы перенести за раз больше одной переменной, необходимо переносимые переменные объединить в вектор. Введите следующую команду<source lang=scilab>-1-> [x1, x2]=resume(x1, x2)</source>. Обратите внимание на то, как объявляется вектор: в квадратные скобки помещаются переменные, разделяемые запятыми. В дальнейшем мы научимся их создавать и для математических целей.
# Мы решили нашу подзадачу, но правильно ли? Проведем проверку и заодно научимся ещё одному приёму. Введите следующую команду<source lang=scilab>--> 2*x1^2+4*x1-10,..</source> и нажмите клавишу <Enter>. Вы увидите, что командная строка создаст новую строку, но результат расчёта не покажет. Дело в том, что ввод команды ещё не завершен: введя две точки в конце команды вы даёте указание создать новую строчку и продолжить ввод команды. После того, как вы завершите ввод, интерпретатор проигнорирует эти точки и слепит всё в единую команду. Этот приём используется, когда вам за один раз необходимо ввести много длинных и несвязанных между собой команд. После создания строчки введите вторую команду<source lang=scilab>--> 2*x2^2+4*x2-10</source> и нажмите клавишу <Enter>
 
Вы увидите следующее<source lang=scilab>--> 2*x1^2+4*x1-10,..
--> 2*x2^2+4*x2-10
ans =
-1.776D-15
ans =
-3.553D-15</source>Очевидно, что мы правильно рассчитали корни с двойной точностью. Отметим, что команды выполнились последовательно и результат последней команды записался в переменную ans.
|}
Теперь углубимся. Нажимая сочетания клавиш <Ctrl>+<X> или <Ctrl>+<C> вы на самом деле вызывали функцию
<source lang=scilab>pause</source>. Новый подуровень не запрещает вам пользоваться уже созданными переменными. Например, вы можете воспользоваться полученными корнями на новом уровне при этом не меняя имя переменной. Создавая подуровень вы защищаете уже полученные результаты.
 
Например, попробуйте ввести
<source lang=scilab>--> pause
-1-> x1=x1+3;</source>Вы увидите, что в области памяти подуровня будет создана переменная x1, в которую будет занесен результат прибавления тройки к найденному нами корню квадратного уравнения. При этом мы не потеряли корень, так как его значение было только скопировано. Это еще одно удобство подуровней, которым необходимо пользоваться, т.е. переменные верхних подуровней всегда защищены от изменений, но при этом к ним всегда есть доступ с нижних уровней.
 
Не менее полезными будут следующие приёмы работы с текущей строкой:
* Нажимая кнопки со стрелками «вверх» и «вниз», вы перемещаетесь по истории введенных вами команд;
* После нажатия кнопки <End>, курсор мгновенно переносится в конец строки, кнопка <Home> перемещает курсор в начало строки;
* Нажимая комбинацию <Ctrl>+<Стрелка вправо> или <Стрелка влево>, вы мгновенно можете перемещать курсор между законченными частями выражения в строке: например, в выражении 235 + 458, если курсор находится слева, комбинация <Ctrl>+<Стрелка вправо> сначала переместит курсор за цифру 5, потом за знак '+' и, наконец, за цифру 8;
* Нажимая комбинацию <Ctrl>+<Shift>+<Стрела вправо> или <Стрелка влево>, вы можете быстро выделять законченные части выражения в строке;
* Если в строке выделен фрагмент введенного выражения, то комбинация <Ctrl>+<C> работает как команда «Скопировать», комбинация <Ctrl>+<V> — «Вставить».
 
Иногда нагромождение команд введенных ранее в командное окно мешает работе. В этом случае вы можете очистить командное окно, воспользовавшись одной из двух функций:
* tohome — поднимает курсор так, чтобы скрыть все введенные команды вместе с результатами, при этом не удаляя их из командного окна. Можно воспользоваться ползунком окна, чтобы снова их увидеть;
* clc — удаляет все содержимое в командном окне. После очистки вернуть результаты не возможно. Если вы передадите в качестве аргумента число, например clc(5), то команда удалит это число строчек выше курсора.
 
Мы познакомились с основными приёмами работы с клмандной строкой. Теперь рассмотрим наиболее важные функции по конфигурированию среды.
 
=== Конфигурация среды ===
Под конфигурированием среды мы будем понимать доступные пользователю настройки.
 
=== Правила записи выражений ===
Данный раздел написан для начинающих пользователей, которые сталкиваются с проблемами ввода математических выражений в строчку. Этот раздел можно пропустить опытным пользователям математических пакетов, так как следующая информация тривиальна и не несёт в себе ничего нового.
 
Для начала запомните следующие правила, которыми руководствуется интерпретатор:
* Любое выражение читается интерпретатором слева на право;
* В выражении можно выделить ''операнды'' (объекты над которыми производятся действия, или которые участвуют в действии над другими операндами) и ''операторы'' (инструкции, которыми руководствуется интерпретатор, когда выполняет действия).
 
Операторы бывают '''унарными''', когда инструкция направлена на один ''операнд'', и '''бинарными''', когда инструкция направлена на два ''операнда''.
 
Основные операторы, которые используются для записи математических выражений, вы уже можете знать:
;Бинарные
:: <nowiki>' * '</nowiki> — оператор умножения;
:: ' / ' — оператор правого деления, т.е. когда левый операнд делится на правый;
:: ' \ ' — оператор левого деления, т.е. когда правый операнд делится на левый;
:: ' + ' — оператор сложения;
:: ' — ' — оператор вычитания;
:: ' = ' — оператор присваивания;
:: ' ^ ' — оператор возведения в степень
:: ' & ' — конъюнкция (логическое И);
:: ' | ' — дизъюнкция (логическое ИЛИ);
;Унарные
:: ' ~ ' — инверсия (логическое НЕ);
:: " ' " — транспонирование матрицы
 
'''Примечание''': заметим, что у некоторых операторов могут быть ''псевдонимы'', например, логические операции можно выполнить через вызовы функций or(), and() и not().
 
У читателя не должно возникнуть трудностей с операторами арифметических действий. Скажем несколько слов про оператор присваивания. Оператор присваивания служит для присваивания некоторого значения (которое может быть получено из математического выражения) для некоторой переменной или для копирования значения некоторой переменной в другую переменную.
 
В любом случае при выполнении операции присваивания:
* адресат должен стоять по левую часть от оператора.
 
Каждый оператор имеет собственный приоритет и выполняется в соответствии с ним. Внизу представлена иерархия операторов, которые были представлены выше.
{|class="standard"
!Уровень приоритета
!Оператор
|-
|1
|(), [ ], ' ^ '
|-
|3
|' * ', ' / '
|-
|4
|' + ', ' — '
|-
|14
|' = '
|}
Вы наверное спросите, почему в таблице приведены не все уровни. Данная таблица вырвана из контекста и в ней нарочно приведены не все уровни, чтобы не перегружать читателя лишней информацией.
 
Легко видеть, что самым большим приоритетом обладают выражения, заключенные в скобки. Именно скобки используются для смены приоритетов в математических выражениях.
 
Приведем поучительные примеры. Введите в комадной строке
<source lang="scilab">
--> 2+2*3
ans =
8.
--> 6/2*4
ans =
12.
--> 2+2*3+3
ans =
11.
--> 2+3^2*2
ans =
20.
</source>
Разберем все примеры по очереди. В первом случае интерпретатор проходя слева на право, согласно таблице приоритетов, выполняет операцию умножения (результат 6), к которому прибавляет двойку (в результате 8). Во втором случае, так как операторы умножения и деления на одном уровне, интерпретатор сначала выполнит операцию деления, потому что он стоит левее, а затем умножения.
 
В третьем случае интерпретатор выполнит сначала умножение, затем снова начнет с левого края и прибавит двойку к результату. В конце он прибавит тройку.
 
В четвертом случае интерпретатор сначала возведет тройку в квадрат, так как возведение в степень имеет самый высокий приоритет, затем результат помножит на два и в конце прибавит двойку.
 
Теперь во втором примере изменим приоритет вычислений, выполнив сначала умножение, а затем деление
<source lang="Scilab">
--> 6/(2*4)
ans=
0.75
</source>
 
Более сложные действия, которые невозможно выполнить за один ход, группируются в функции, о которых мы поговорим чуть позже. В концепции, которую мы здесь ввели, функции тоже можно считать своего рода операторами, потому что в большинстве случаев нам не важно знать как функция работает и какие инструкции она несет в себе. Она лишь принимает аргументы (своего рода операнды) и возвращает нам результат.
 
Вещественные числа могут быть введены в командную строку двумя способами: десятичная дробь и экспоненциальный формат. В десятичной дроби целая и дробная части всегда отделяются друг от друга точкой.
 
В экспоненциальном формате число имеет вид
<center><math>N = M \cdot E^p .</math></center>
В этой записи M — это мантисса числа; E (также можно использовать символ 'D') кодирует запись «умножить на десять в»; p — порядок числа. Таким образом, следующие записи для одного числа эквивалентны
<center><math>-6.3E-3 = -6.3D-3 = -0.0063 =-.0063</math></center>
Если в выражении встречаются функции, то они выполняются в первую очередь. Пока вам нужно знать, что в общем случае вызов функции осуществляется через её имя, после которого в круглых скобках через запятую перечисляются аргументы. В среду внедрено большое количество функций, выполняющих всевозможные процедуры. Кроме того, пользователь сам может создавать библиотеки своих собственных функций.
 
На данном этапе вам достаточно знать элементарные математические функции, которые используются для записи математических выражений.
 
* sin(x) — синус числа x
* cos(x) — косинус числа x
* tan(x) — тангенс числа x
* cotg(x) — котангенс числа x
* asin(x) — арксинус числа x
* acos(x) — арккосинус числа x
* atan(x) — арктангенс числа х
* sqrt(x) — квадратный корень числа x
* exp(x) — экспонента числа х
*
 
Отметим также, что в среде существует несколько синтаксических конструкций, которые могут применяться при вызове одной и той же функции. Использование той или иной конструкции регламентируется внутри функции и обычно указывается в справочной информации.
* В первом варианте достаточно обратиться к функции по имени. Если функция не требует обязательных аргументов, то скобки можно опускать.
<center>function или function()</center>
* Заметим, что в среде Scilab может быть реализована, так называемая ''перегрузка'', когда для одной функции могут быть предопределены различные варианты поведения в зависимости от передаваемых параметров или аргументов. Во втором варианте функция имеет хотя бы один обязательный аргумент.
<center>function(arguments)</center>
* Третий вариант является по сути вариацией второго, но аргументы имеют специальные пометки (''параметры'' или ''флаги''), указывающие функции по какому сценарию обрабатывать аргументы
<center>function -param_1 [arguments] -param_2 [arguments]</center>
 
=== Комментарии ===
В системе Scilab возможно комментирование отдельных строк. Комментарии — это записи, которые оставляет пользователь для облегчения понимания кода. Комментарии разумно оставлять в сценариях, так как со временем можно забыть некоторые фрагменты кода. Кроме того, комментарии облегчают понимание кода для пользователей, которые сталкиваются с вашим сценарием впервые.
 
Для того, чтобы поставить комментарий, необходимо ввести два правых слэша, например,
<source lang="Scilab">
// это мой комментарий
</source>
Комментарии можно оставлять и в командной строке, хотя это вообще говоря, бессмысленно. К сожалению, в Scilab отсутствуют многострочные комментарии.
 
=== Быстрый ввод функций ===
В заключении данного раздела познакомим читателя с еще одним приемом, позволяющим быстро вводить функции. В большинстве случаев приходится иметь дело с ограниченным набором часто используемых функций. Постоянный ввод одних и тех же команд быстро утомляет и по этой причине в командную строку введен механизм быстрого ввода функций.
 
Для начала следует начать печатать имя функции, при этом достаточно даже одного первого символа. После этого следует нажать клавишу <Tab>. Рядом с курсором появится раскрывающийся список, в котором будут представлены функции с совпадающими символами. Вы можете продолжить ввод желаемой функции, при этом из списка автоматически будут выпадать несовпадающие пункты. Если вы заметили искому функцию, то выберите ее из списка с помощью стрелок и нажмите <Enter>.
 
== Объекты ==
В этом разделе мы изучим объекты среды, которые пользователь может применять для решения своих задач.
 
Все объекты (с точки зрения математика) можно разделить на:
* Переменные;
* Матрицы:
* Векторы;
* Списки.
С точки зрения программиста те же объекты можно классифицировать на:
* Переменные
* Массивы
* Структуры
 
Мы не будем придерживаться строгой терминологии и где нужно будем говорить ''«матрица»'', вместо ''«двумерный массив»'', и наоборот. Как вы в дальнейшем убедитесь, все эти объекты просто различные формы представления двумерного массива данных, и каждый из этих объектов имеет свою область применения.
 
=== Переменная ===
'''Переменная в Scilab''' ({{lang-en|Variable}}) — это именованный массив всего с одним полем, которое хранит данные некоторого типа. С другой точки зрения, переменной можно считать любой зарезервированной участок памяти, на начало которого есть ссылка, но мы будем придерживаться первого толкования.
 
Среди типов данных можно выделить:
* Числа
** Целые числа
** Вещественные числа
** Комплексные числа
* Строки
* Логические переменные
 
Создать переменную в среде не составляет труда. Для этого, как вы уже знаете, достаточно ввести ее имя и присвоить ей какое-либо начальное значение. Для переменной будет автоматически выделено место в памяти, а ее область видимости по умолчанию становится локальной.
 
Для того, чтобы посмотреть текущее значение переменной, достаточно просто обратиться к ней по имени, либо воспользоваться редактором переменных. В дальнейшем вы убедитесь, что редактор крайне удобен для матриц.
 
Запомните следующие правила, которым должны удовлетворять имена переменных и вообще любых объектов среды:
* Имя переменной может состоять из букв латинского алфавита (верхнего и нижнего регистра) и цифр;
* Имя переменной не может начинаться с цифры, но может начинаться с символов '%', '_', '#', '!', '$', '?';
* Регистр в имени играет роль, т.е. переменные с именами var,VAR ,Var и т.п. разные;
* Запрещено совпадение имени переменной с зарезервированными словами, такими как имена объявленных функций, констант и др.;
 
{|
|style="background-color:Orange"|<big>'''Упражнение'''</big>
|-
|style="background-color:WhiteSmoke"|
Для начала попробуем создать несколько переменных
<source lang=scilab>
--> n1=25, n2=65.33, n3=-36.4e-6, n4=9+%i*4
</source>
В результате мы получили 4 переменных, 3 из которых хранят вещественные числа и одна — комплексное число. Обратите внимание, как вводится мнимая единица. В среде Scilab мнимая единица является предопределенной константой с именем ' i '. Знак процента указывает на то, что вы обращаетесь к ''константе''.
 
Несмотря на то, что в переменной n1 нет дробной части, с точки зрения хранения этого числа в памяти оно вещественно и имеет тип ''double''. Убедимся, что переменные хранят числа, для чего вызовем внутреннюю функцию type(). Чтобы не вызывать функцию четыре раза, мы объединим наши переменные в вектор. Для объединения объектов в вектор необходимо перечислить их через запятую внутри квадратных скобок
<source lang=scilab>
--> type([n1,n2,n3,n4])
ans =
1.
</source>
В ответ функция возвращает число 1. Данным числом функция закодировала информацию о том, что в качестве аргумента была передана матрица, содержащая вещественные или комплексные числа удвоенной точности.
 
Создадим текстовую переменную следующей командой
<source lang=scilab>
--> n5='Scilab'
</source>
Вызовем функцию type() для переменной n5
<source lang=scilab>
--> type(n5)
ans =
10.
</source>
Снова отметим, что число 10 кодирует информацию о том, что в массиве n5 хранятся текстовые строки. Не стоит заучивать наизусть что означает то или иное число, возвращаемое функцией type(), так как вы всегда можете воспользоваться справочной информацией.
 
Введите команду, которая откроет окно справки и перейдет к разделу, описывающему функцию type()
<source lang=scilab>
--> help type
</source>
Запомните команду help и всегда применяйте её в подобных случаях.
 
Логические переменные могут хранить в себе одну из двух предопределенных констант: %T (от {{lang-en|True}} — ''Истина'') и %F (от {{lang-en|False}} — ''Ложь''). Для логических типов данных применяются особые (логические) операции, тем не менее, этот тип данных совместим с числовым типом данных: любое ненулевое значение является эквивалентом %T, а соответственно нулевое значение — %F.
 
Убедимся в последнем на следующем поучительном примере.
<source lang=scilab>
--> n6=%T; n7=%F;
--> n4 & n6, n2 | n7
ans =
T
ans =
T
</source>
Обратите внимание, что логическая операция успешно прошла даже с комплексной переменной. Запомните это свойство, так как им пользуются при написании сценариев, чтобы лишний раз не создавать логические переменные.
 
Наконец, обратим ваше внимание на то, что интерпретатор динамически реагирует на присваивание. Это означает, что любая объявленная переменная может хранить в любой момент времени любой тип данных.
 
Запишите следующий сценарий
<source lang=scilab>
--> type(n4), n4='text'; type(n4), n4=[n1,n2,n3]; type(n4)
ans =
1.
ans =
10.
ans =
1.
</source>
Переменной n4, хранящей комплексное число, мы последовательно присвоили сначала текстовую строку, а затем вектор из числовых значений. Обратите внимание, что такие действия не приводят к ошибке интерпретатора. Если заглянуть вглубь этого процесса переприсваивания, то можно увидеть, что это многошаговый процесс: сначала необходимо освободить память от предыдущих данных, затем выделить столько памяти, сколько нужно для хранения другого типа данных и, наконец, заполнить память данными. Разумеется, что все эти действия умело скрыты от глаз пользователя.
 
Также вы легко можете видеть, как стирается граница между переменными и массивами в рамках одного имени, так как в любом случае среда работает с памятью. В некоторых ситуациях данное свойство может быть губительно для данных, так как вы спокойно можете сослаться на имя, которое например ссылается на имеющийся в памяти массив и присвоить ему переменную (по сути тот же массив, но с одним полем и другими данными). При этом вернуть назад данные вы не сможете, если не приняли страховочные меры, например, защита от изменений, которую мы рассмотрим ниже.
|}
 
Вы уже умеете создавать переменные, однако этого не достаточно для работы. Рано или поздно вы наталкнетесь на вполне естественные вопросы: "Сколько переменных сейчас в памяти?", "Какие имена свободны, а какие заняты?", "Как очистить память от ненужных мне объектов?" и другие.
 
Вообще говоря, для работы с любыми объектами в среде существуют предопределенные функции, которые всегда загружаются вместе со средой. Мы рассмотрим все вопросы в этом разделе, и далее будет полагаться, что данная здесь информация переносится на все последующие объекты среды.
{| class="standard"
!Имя функции
!Ключевые слова для параметров
!Аргументы
!Назначение
|-
|'''whos'''
|'''Необязательные''':<br />'''-type''' typ<br />
'''-name''' nam
|typ — текстовая строка, кодирующая тип данных<br />
nam — имена искомых переменных, либо их начальные фрагменты
|Выводит список переменных в длинной форме (с указанием типа и размера), если вызывается без аргументов. Выводит список переменных, хранящих определенный тип данных (если указан параметр -type) или/и обладающих определенным именем или фрагментом этого имени (если указан параметр -name).
|-
|'''who()'''
|аргументы перечисляются в скобках
|'''Необязательные''':<br />
'local' или 'get' — список локальных переменных и констант в коротком виде<br />
'global' — список глобальных переменных в коротком виде<br />
'sorted' — возвращает сортированный список объявленных переменных (локальных и глобальных) с текущими значениями параметров памяти.
|Без аргументов возвращает <u>несортированный</u> список объявленных переменных (локальных и глобальных) с текущими значениями параметров памяти.
|-
|'''who_user'''
|нет
|нет
|Работает почти как who('local'), но выводит только переменные, созданные пользователем во время текущей сессии.
|-
|'''typeof()'''
|нет
|'''Обязательный''':<br />
object — имя объекта среды
|Возвращает в виде строки тип объекта, чье имя передается в качестве аргумента. В отличие от функции type(), более гибко работает с типами данных. О возвращаемых значениях смотрите в справке по данной функции.
|-
|'''clear'''
|нет
|'''Необязательные''':<br />Аргументами являются имена объектов, перечисляемых через пробел.
|Удаляет из памяти объекты и освобождает имена. Если вызывается без аргуметов, то удаляются все незащищенные объекты текущей сессии.
|-
|'''predef()'''
|нет
|'a' или 'all' — защищает все переменные из списка who('get')<br />
'c' или 'clear' — снимает защиту со всех переменных списка who('get'), кроме последних 7 (по умолчанию), некоторых предопределенных системных переменных и констант<br />
n (n>7) — устанавливает n последних переменных в качестве защищенных<br />
'names' — возвращает список защищенных переменных
|Функция предназначена для защиты переменных. Вызов без аргументов возвращает количество защищенных переменных. Остальные вариации перечислены в колонке с аргументами.
|-
|
'''exists()'''
|нет
|'''Обязательный''':<br />name — имя переменной (передается строкой, т.е. в кавычках)<br />
'''Необязательный''':<br />where — возможны варианты: 'l' — локальный, 'n' — нелокальный, 'a' — все
|Функция проверяет существование объекта с указанным именем. Если объект существует, то функция возвращает 1, в противном случае 0. С помощью флага, можно задавать область поиска. По умолчанию используется вариант 'a'.
|}
 
Функции, которые приведены, следует запомнить со всеми возможными аргументами, так как они используются при работе со средой повсеместно.
 
{|
|style="background-color:Orange"|<big>'''Упражнение'''</big>
|-
|style="background-color:WhiteSmoke"|
Надеюсь вы не удалили последствия предыдущего упражнения. Вызовите команду whos. В ответ вы увидите следующее
<source lang=Scilab>
-->whos
Name Type Size Bytes
$ polynomial 1 by 1 56
%driverName string* 1 by 1 40
%e constant 1 by 1 24
%eps constant 1 by 1 24
%exportFileName constant* 0 by 0 16
%F boolean 1 by 1 24
%f boolean 1 by 1 24
%fftw boolean 1 by 1 24
%gui boolean 1 by 1 24
%helps constant* 0 by 0 16
%i constant 1 by 1 32
%inf constant 1 by 1 24
%io constant 1 by 2 32
%modalWarning boolean* 1 by 1 24
%nan constant 1 by 1 24
%pi constant 1 by 1 24
%pvm boolean 1 by 1 32
%s polynomial 1 by 1 56
%T boolean 1 by 1 24
%t boolean 1 by 1 24
%tk boolean 1 by 1 16
%toolboxes string* 1 by 1 40
%toolboxes_dir string* 1 by 1 136
%z polynomial 1 by 1 56
atomsguilib library 320
atomslib library 856
cacsdlib library 4000
compatibility_functilib library 4216
corelib library 688
data_structureslib library 464
datatipslib library 760
demo_toolslib library 544
demolist string* 15 by 2 4648
development_toolslib library 496
differential_equationlib library 448
dynamic_linklib library 744
elementary_functionslib library 2984
fft fptr 40
fileiolib library 624
functionslib library 752
genetic_algorithmslib library 648
graphic_exportlib library 392
graphicslib library 3968
guilib library 488
help function 5368
helptoolslib library 752
home string 1 by 1 96
integerlib library 1416
interpolationlib library 336
iolib library 392
jvmlib library 296
linear_algebralib library 1448
m2scilib library 352
maple2scilablib library 288
matiolib library 328
modules_managerlib library 704
MSDOS boolean 1 by 1 16
n1 constant 1 by 1 24
n2 constant 1 by 1 24
n3 constant 1 by 1 24
n4 constant 1 by 3 40
n5 string 1 by 1 48
n6 boolean 1 by 1 24
n7 boolean 1 by 1 24
neldermeadlib library 1168
optimbaselib library 1024
optimizationlib library 696
optimsimplexlib library 1248
output_streamlib library 360
overloadinglib library 15712
parameterslib library 424
polynomialslib library 904
pvmlib library 248
PWD string 1 by 1 96
SCI string 1 by 1 96
scicos_autolib library 408
scicos_utilslib library 576
SCIHOME string 1 by 1 184
scinoteslib library 272
signal_processinglib library 1888
simulated_annealinglib library 600
soundlib library 544
sparselib library 456
special_functionslib library 304
spreadsheetlib library 328
statisticslib library 1360
stringlib library 648
tclscilib library 384
texmacslib library 312
timelib library 520
TMPDIR string 1 by 1 128
uitreelib library 512
umfpacklib library 456
whos function 15416
xcoslib library 928
</source>
В данном списке перечислены объекты, которые были объявлены средой во время инициализации и во время сессии. Из данного списка пользователь получает информацию о типе объекта, его размере в полях (если это массив) и размере в байтах. Именно поэтому данный список называется ''длинным''. Попытаемся во всем этом многообразии отыскать только те переменные, которые мы объявили в предыдущем упражнении. Для этого введем команду
<source lang=Scilab>
--> whos -name n
Name Type Size Bytes
n1 constant 1 by 1 24
n2 constant 1 by 1 24
n3 constant 1 by 1 24
n4 constant 1 by 3 40
n5 string 1 by 1 48
n6 boolean 1 by 1 24
n7 boolean 1 by 1 24
neldermeadlib library 1168
</source>
Обратите внимание, что функция вернула список из объектов, начинающихся на символ 'n'. Среди таких объектов оказалась также библиотека функций neldermeadlib.
 
К сожалению функция whos не поддерживает одновременное использование своих параметров, поэтому в каждый отлельный вызов вы можете искать объект либо по его имени, либо по типу данных, которые он хранит. Попытаемся найти все объекты, хранящие строки, для чего введем
<source lang=Scilab>
->whos -type string
Name Type Size Bytes
%_opt string 1 by 1 48
%_sel string 1 by 1 48
%driverName string* 1 by 1 40
%toolboxes string* 1 by 1 40
%toolboxes_dir string* 1 by 1 136
demolist string* 15 by 2 4648
home string 1 by 1 96
n5 string 1 by 1 48
PWD string 1 by 1 96
SCI string 1 by 1 96
SCIHOME string 1 by 1 184
TMPDIR string 1 by 1 128
</source>
Обратите внимание на символ звездочки у некоторых переменных в колонке их типа. Данный символ означает, что переменная глобальная, т.е. зона ее видимости распространяется на все функции, загруженные в данной сессии. Мы вернемся к этому вопросу, когда будем изучать программирование в среде, а пока просто запомните смысл этого символа.
 
Отметим, что аргументы функции также можно передавать в скобках, несмотря на то, что об этом не было упомянуто в таблице выше. Делается это так
<source lang=Scilab>
->whos('-type','string')
Name Type Size Bytes
%_opt string 1 by 1 48
%_sel string 1 by 1 48
%driverName string* 1 by 1 40
...
</source>
Данный способ является уже устаревшим и мы все же рекомендуем вам им не пользоваться, но и не запрещаем.
 
Мы научились искать объекты, однако, еще не научились искать только те, которые были объявлены в данной сессии. Для этого следует использовать команду who_user
<source lang=Scilab>
-->who_user
User variables are:
whos n7 n6 n5 n4 n3 n2 n1 help
home
Using 2636 elements ouf of 4990727
</source>
Обратите внимание, что функция вернула список объектов текущей сессии. Несмотря на то, что мы не создавали объекты help, whos и home, среда все равно отнесла их к пользовательским. Так как никакой информации об объектах мы теперь не наблюдаем, то данная запись называется ''короткой''. Обратите внимание, что внизу отображается информация о заполненности стека. Отметим также, что функция в версии для Windows записывает этот массив в ans (или другой адресат). В версии для Unix-подобных систем этого замечено не было.
 
Обратите внимание на достоинства и недостатки функций whos и who_user: первая выводит исчерпывающую информацию о стеке и позволяет искать объекты в стеке, однако, вся информация об объектах иногда бывает не нужна; вторая функция возвращает только пользовательские переменные в коротком виде, что бывает полезно для проверки свободных имен.
 
Функция who сочетает в себе особенности whos() и who_user. Мы предлагаем читателю утолить свое любопытство и поэкспериментировать с вызовом функции who() с разными наборами аргументов, которые, в отличие от whos, можно комбинировать.
 
Теперь выясним тип объекта help.
<source lang=Scilab>
-->typeof(help)
ans =
function
</source>
О том, что это функция, вы могли догадаться ранее, когда вызывали, например, help type, где строка type являлась аргументом. Обратите внимание, что, в отличие от функции type, функция typeof возвращает не число, а строку, что намного понятнее человеку. Коды функции type очевидно намного полезнее в программировании сценариев.
 
Защитим наши переменные
<source lang=Scilab>
-->predef('a')
ans =
79. 90.
</source>
В ответ функция возвратила два значения: первое — сколько переменных было защищено до вызова и второе — сколько защищенных переменных стало.
 
Если вы попытаетесь теперь удалить, например, переменную n1, то получите в ответ сообщение об ошибке
<source lang=Scilab>
-->clear n1
!--error 13
Переопределение неизменной переменной.
</source>
С этого момента мы натыкаемся на одно неудобство функции predef(), а именно то, что она не позволяет защищать переменные и снимать защиту с переменных по отдельности. В результате чего необходимо быть очень внимательным, вызывая функцию clear и очень тщательно обдумывать какие переменные стоит защищать, а какие не стоит.
 
Давайте преднамеренно совершим очень неприятную ошибку, а именно освободим стек от библиотек с системными функциями. Не следует бояться, что мы разрушим среду, так как данная проблема решается простым перезапуском программы. Выполните команду
<source lang=Scilab>
-->predef('c')
ans =
90. 13.
</source>
Обратите внимание, что осталось защищенными только 13 объектов. Теперь вызовите функцию очистки
<source lang=Scilab>
clear
</source>
Как вы знаете, без аргументов функция удаляет все незащищенные объекты. Теперь попытаемся воспользоваться функцией whos
<source lang=Scilab>
-->whos
!--error 4
Неизвестная переменная: whos
</source>
Очевидно, что функция перестала работать. Такой же результат вы можете наблюдать и с функцией help. Это произошло потому, что неосторожным вводом команды clear мы выгрузили все библиотеки с функциями, которые прописаны в главном сценарии среды. Так как вы не исправляли сам сценарий, то при следующем его запуске все возвратится на круги своя, а пока вы остались наедине со средой с минимальным набором компонент. Тем не менее, функция who должна работать, потому что она защищена от такой ситуации, и вы можете понаблюдать, что осталось в памяти.
 
Закройте среду и запустите ее заново.
|}
В последнем упражнении последний пример показывает как важно аккуратно обращаться с памятью. Давайте разберем ситуацию «а как удалить все переменные с n1 по n7?». Вспомним правило, по которому работает стек: первым зашел — последним вышел. Это означает, что объекты как бы наслаиваются друг на друга при каждом объявлении, слдовательно наши переменные в стеке были одними из последних.
 
Можно было запомнить сколько объектов было защищено до вызова функции predef('a') и вернуть защиту именно этому числу объектов вызовом predef(n) (если вы обратили внимание, в упражнении это число было равно 79, т.е. введя predef(79)). Соответственно предыдущее число защищенных объектов мы можем получить вызвав predef() без аргументов. Если на верхушке стека оказывались бы только наши переменные, то с чистой совестью мы можем вызвать команду clear, так как библиотеки мы уже защитили. Если в верхушке стека вместе с нашими переменными есть еще какие-то объекты, то clear вызывать уже нельзя и следует перечислить удаляемые объекты через пробел в качестве аргументов.
{|
|style="background-color:#4169e1"|<big>'''Самостоятельно'''</big>
|-
|style="background-color:WhiteSmoke"|
С этого момента в учебнике будут появляться блоки, в которых читателю предлагается закрепить полученные знания. В этом блоке предлагается решить следующую задачу.
 
# Создайте десять переменных, хранящих нули, с именами v#, где символ '#' означает число от 1 до 10. Переменные следует создавать строго в прямой последовательности;
# В переменные v3, v5 и v9 запишите значения системных переменных, хранящих строковые значения. Выведите список предопределенных констант (т.е. начинающихся с символа '%') и отыщите среди них математическую константу Пи. Значение Пи запишите в переменную v1;
# Очитстие память от переменных v2 и v10;
# Защитите все переменные;
# Очистите память от всех созданных вами переменных, кроме тех, что хранят строки, любым кажущимся для вас наиболее рациональным способом, но только так, чтобы в среде оставались все объекты проинициализированные перед началом сессии, и так, чтобы впоследствии они оставались защищенными;
# Если оставшиеся пользовательские переменные остались защищенными, то снимите с них защиту;
# Ответье на вопрос «Какой тип данных хранит константа %fftw?».
 
|}
==== Целые числа ====
Вы могли обратить внимание, что научились создавать вещественные числа, но так и не научились создавать целые числа. В Scilab целые числа возможно создавать только через специальные функции. Во всех остальных случаях числовому значению всегда будет присваиваться вещественный тип данных.
 
Для хранения целого числа в памяти может быть использовано разное число битов, а именно 8, 16 и 32. От количества используемых битов зависит диапазон целых чисел. Кроме того, имеется возможность включения и отключения знакового бита, что бывает полезно, когда отрицательные целые числа не требуются.
 
В таблице ниже приведены функции для создания целых чисел и диапазоны возможных значений. Во всех случаях функция возвращает целое число, указанное в качестве аргумента, с определенным способом его хранения в памяти.
{| class="standard"
!Имя функции
!Тип целого числа
!Диапазон
!Код представления
|-
|'''int8()'''
|знаковое 8-битное число
|<math>[-2^{7}, 2^{7} - 1]=[-128, 127]</math>
|1
|-
|'''uint8()'''
|беззнаковое 8-битное число
|<math>[0, 2^{8} - 1]=[0, 255]</math>
|11
|-
|'''int16()'''
|знаковое 16-битное число
|<math>[-2^{15}, 2^{15} - 1]=[-32 768, 32 767]</math>
|2
|-
|'''uint16()'''
|беззнаковое 16-битное число
|<math>[0, 2^{16} - 1]=[0, 65 535]</math>
|12
|-
|'''int32()'''
|знаковое 32-битное число
|<math>[-2^{31}, 2^{31} - 1]=[-2 147 483 648, 2 147 483 647]</math>
|4
|-
|'''uint32()'''
|беззнаковое 32-битное число
|<math>[0, 2^{32} - 1]=[0, 4 294 967 295]</math>
|14
|}
Какой тип целочисленной переменной следует применить, пользователь решает сам. Целые числа могут быть использованы как в чисто математических задачах, так и программировании, в качестве счетчиков.
 
Для работы с целочисленными переменными существует две функции:
* '''iconvert(X, itype)''' — меняет представление в памяти в общем случае матрицы из вещественных или целых чисел. Функции при этом следует передавать имя этой матрицы X и код внутреннего представления целого числа itype из последней колонки таблицы выше;
* '''inttype(X)''' — возвращает код внутреннего представления в общем случае матрицы целочисленных данных.
 
{|
|style="background-color:Orange"|<big>'''Упражнение'''</big>
|-
|style="background-color:WhiteSmoke"|
Создадим целочисленную переменную
<source lang=Scilab>
--> integer=uint8(16)
integer =
16
</source>
Обратите внимание на то, что пропала точка, разделяющая целую и дробную части. Прибавим к целому числу вещественное
<source lang=Scilab>
-->integer=integer+32.6
integer =
48
</source>
Обратите внимание, что вещественное число не влияет на тип данных. Теперь из результат вычтем 49.
<source lang=Scilab>
-->integer=integer-49
integer =
255
</source>
Вместо -1 мы получили 255. Так как мы используем беззнакоый тип целого числа этого и следовало ожидать. Ситуация, когда мы выходим за диапазон возможных значений, называется ''переполнением''. Переполнение практически всегда нежелательное явление, поэтому следует четко представлять в каких диапазонах решается та или иная задача.
 
Отметим, что в функциях можно указывать более сложные алгебраические конструкции, например
<source lang=Scilab>
--> integer=int32(3*2-45^4)
integer =
-4100619
</source>
Введем команду, устанавливающую тип целочисленной переменной
<source lang=Scilab>
-->inttype(integer)
ans =
4.
</source>
Посмотрев по таблице код внутреннего представления, приходим к выводу, что это действительно целая 32-битная знаковая переменная. Вызовем команду, меняющую внутреннее представление переменной, например, отключим знаковый бит
<source lang=Scilab>
-->iconvert(integer,14)
ans =
4290866677
</source>
Теперь знаковый бит кодирует часть числа, увеличив тем самым возможный диапазон, однако, мы потеряли исходное число. Теперь уберем часть битов
<source lang=Scilab>
-->iconvert(integer,2)
ans =
28149
</source>
Разберемся, почему получилось именно такое число. Несложно представить двоичную форму числа 4290866677, а именно
<center>1111 1111 1100 0001 0110 1101 1111 0101.</center>
Преобразовав внутреннее представление в 16-битное, мы отсекли 16 старших битов (находящихся слева) и получили
<center>0110 1101 1111 0101.</center>
Если выполнить обратное преобразование в десятиричную систему счисления, то получается как раз число 28149.
|}
 
==== Комплексные числа ====
Теперь поговорим о комплексных числах. Показанный ранее способ ввода комплексного числа не всегда удобен и требует ввода знаков '+' и '%i'. Ввод комплексного числа в значительной мере можно упростить, если воспользоваться функцией '''complex(a,b)''', в которой в качестве аргументов указать действительную и мнимую части соответвенно. Согласно справочной информации, данная функция позволяет избежать проблем в объявлении комплексных переменных, в которых возможно появление констант %nan и %inf.
 
Попутно познакомим читателя с константами %nan и %inf. Константа %nan ({{lang-en|Not-a-Number}}) кодирует особое состояние вещественного числа и возвращается, когда результат не может быть определен числовым значением (например, при неопределенности типа ноль на ноль). По умолчанию, режим, при котором в случае неопределенного результата формируется %nan, отключен и, если вы попробуете разделить на ноль, интерпретатор вернет сообщение об ошибке. Для включения режима необходимо вызвать функцию '''ieee()''', где в качестве аргумента следует передать 2.
<source lang=Scilab>
--> ieee(2)
--> 0/0
ans =
Nan
</source>
Константа %inf ({{lang-en|Infinity}}) является машинным представлением бесконечно большого числа. Обе эти константы могут быть использованы для объявления комплексных чисел, например
<source lang=Scilab>
--> complex(%nan,%inf)
ans =
Nan + Infi
</source>
Покажем ситуацию, в которой показана необходимость в функции complex() и которая представлена в качестве примера в справке. Попытаемся объявить следующую комплексную переменную
<source lang=Scilab>
--> %inf+%i*%inf
ans =
Nan + Infi
</source>
Очевидно, что инициализация прошла с ошибкой, потому что в действительной части ожидалось %inf. Это произошло потому, что системой произведение %i*%inf интерпретируется как (0+%i)*(%inf+%i*0), что дает промежуточное выражение 0*%inf = %nan.
 
Корректно проинициализировать значение в этом случае возможно только с помощью функции
<source lang=Scilab>
--> complex(%inf,%inf)
ans =
Inf + Infi
</source>
 
 
Для работы с комплексными числами также существует небольшой набор функций:
* '''conj(X)''' — возвращает комплексное число сопряженное числу X;
* '''real(X)''' — возвращает действительную часть комплексного числа X;
* '''imag(X)''' — возвращает мнимую часть комплексного числа X;
* '''isreal(X)''' — возвращает логическое %T, если передаваемый аргумент является комплексным числом, %F в противном случае.
* '''imult(X)''' — умножает мнимую единицу на аргумент. Согласно справочной информации, данную функцию ркомендуется использовать, когда приходится иметь дело с константами типа %nan и %inf, появляющихся в комплексном числе.
 
Предлагаем читателю самостоятельно попробовать все функции над комплексными числами.
 
==== Строки ====
Строковый тип данных образуется заключением символов в одинарные или двойные кавычки.
<source lang=Scilab>
--> a='Scilab', b="is smart"
</source>
В памяти строка представляет собой массив кодов символов, из которых она образуется. Однако, после объявления строки, она представляется для пользователя единым куском, поэтому без специальных функций для работы со строками вы не сможете добраться до отдельно взятого символа строки.
 
Функций для работы со строками уже несколько больше, чем для работы, например, с теми же комплексными числами, и простое их перечисление будет просто не эффективным способом их изучить. Мы познакомимся с этими функциями чуть позже, когда будем решать практические задачи.
 
Пока вам следует запомнить, что строки сами по себе поддерживают лишь операцию конкатенации (объединения), которая вызывается с помощью оператора сложения. Например,
<source lang=Scilab>
--> a+' '+b
ans =
 
Scilab is smart
</source>
 
==== Переменная ans ====
Переменная ans (от {{lang-en|answer}} — ответ) — это зарезервированная переменная, в которую сохраняется любой последний «безымянный» результат. Переменная ans является особой, например, на нее не действуют функции predef и clear. Зона ее видимости всегда остается локальной.
 
Переменная ans может быть использована для проведения цепочки вычислений, промежуточные результаты которых вам не нужны.
<source lang=Scilab>
-->2*2
ans =
4.
-->ans+4
ans =
8.
-->ans/ans
ans =
1.
</source>
 
=== Матрицы и векторы ===
'''Вектор в Scilab''' — это упорядоченная совокупность элементов (одномерный массив) одного типа данных. Упорядоченность для пользователя в этом смысле проявляется в том, что к каждому элементу вектора можно обратиться по его уникальному порядковому номеру или ''индексу''. В среде Scilab все индексы начинаются с единицы, что немного не привычно, так как например в программировании на языке Си те же индексы массивов начинаются с нуля.
 
Ранее мы уже не раз создавали вектора и вы уже знаете, что для этого нужно элементы заключить в квадратные скобки, т.е.
<source lang=Scilab>
Vector = [e1, e2, e3]; // Вектор с тремя элементами в виде переменных с именами e1, e2 и e3
</source>
При объявлении вектора совершенно не обязательно отделять их друг от друга запятыми — достаточно простого пробела. Например, следующее объявление не приведет к синтаксической ошибке
<source lang=Scilab>
Vector = [e1 e2 e3];
</source>
Вектор, элементы которого представляют собой числовую последовательность в виде арифметической прогрессии, может быть создан особым образом. Для этого используется конструкция
<blockquote><начальное знаение>:<шаг>:<конечное значение></blockquote>
 
Например, создадим вектор с начальным значением -5, конечным значением 10 и шагом между элементами 2
<source lang=Scilab>
--> -5:2:10
ans =
- 5. - 3. - 1. 1. 3. 5. 7. 9.
</source>
Вообще говоря, шаг можно не указывать. В этом случае его значение по умолчанию принимается равным 1. Если шаг не указывается, то начальное значение всегда должно быть меньше конечного, иначе Scilab создаст пустой вектор.
<source lang=Scilab>
-->1:5
ans =
1. 2. 3. 4. 5.
</source>
Вектор может быть записан столбцом или строкой. В первом случае он называется вектор-столбцом, а во втором — вектор-строкой. От того, как представлен вектор (столбцом или строкой), зависит применимость некоторых операторов. Например, из линейной алгебры вы знаете что скалярное произведение двух векторов возможно только, если первый множитель представлен строкой, а второй — столбцом.
 
Выше мы создавали векторы-строки. Векторы-столбцы создаются путем отделения каждого элемента точкой с запятой, т.е.
<source lang=Scilab>
-->[1; 2; 3]
ans =
1.
2.
3.
</source>
Вектор-столбец также может быть получен операцией транспонирования (оператор в виде апострофа)
<source lang=Scilab>
-->[1 2 3]'
ans =
1.
2.
3.
</source>
что иногда бывает намного удобнее, чем создание с помощью точки с запятой.
 
Так как каждый элемент внутри вектора имеет свой идентификатор в виде индекса, то к нему можно обратиться. Для того, чтобы обратиться к элементу вектора, необходимо записать имя вектора, а затем в круглых скобках указать индекс.
<source lang=Scilab>
-->A=1:5
A =
1. 2. 3. 4. 5.
-->A(4) // Обращаемся к элементу 4 внутри вектора А
ans =
4.
-->A=A';
-->A(4) // Обратите внимание, что операция транспонирования не влияет на индексацию
ans =
4.
</source>
В любой момент вы можете удалить элемент вектора. Для этого достаточно на желаемой позиции создать, так называемую, ''пустую матрицу'' в виде конструкции '[]'.
<source lang=Scilab>
-->A
A =
1. 2. 3. 4. 5.
-->A(2)=[] // Удаляем элемент 2 внутри вектора А
A =
1. 3. 4. 5.
</source>
Если вы хотите обратиться к последнему элементу вектора, но не знаете его размер, вы можете воспользоваться служебным символом в виде знака доллара '$'.
<source lang=Scilab>
-->A($)
ans =
5.
</source>
 
Мы не зря начали свое изложение именно с понятия вектора, так как матрица по сути является расширением этого понятия.
 
'''Матрица в Scilab''' — это двухмерный массив однотипных элементов. Можно понимать матрицу как несколько векторов-строк, записанных столбцом.
 
Создать матрицу в Scilab можно одним из нескольких способов:
* Матрицу можно создать из составляющих ее элементов;
* Из имеющихся векторов, упорядочив их строками или столбцами;
* Одной из специальных функций.
 
В общем случае синтаксическая конструкция имеет вид
<blockquote>
[x11, x22, ..., x1n; x21, x22, ..., x2n; ...; xm1, xm2, ..., xmn]
</blockquote>
Таким образом, вы создаете векторы-строки, которые отделяете точкой с запятой. Запятая в этом случае, как и с вектором, не обязательна.
<source lang=Scilab>
-->A=[1 2; 3 4] // создадим матрицу из составляющих ее элементов
A =
1. 2.
3. 4.
</source>
Матрицу можно собрать из векторов. Вот два поучительных примера
<source lang=Scilab>
--> [1:5; 5:-1:1]
ans =
1. 2. 3. 4. 5.
5. 4. 3. 2. 1.
--> [(1:5)' (5:-1:1)']
ans =
1. 5.
2. 4.
3. 3.
4. 2.
5. 1.
</source>
Обратите внимание на второй случай, как сначала мы транспонируем векторы, создаваемые особой конструкцией, а затем присоединяем их столбцами друг к другу.
 
В любом случае, вы всегда должны помнить, что нельзя допускать конфликты с размерами векторов. Например, если вы образуете метрицу из векторов-строк, то число элементов в них должно быть одинаковым, иначе произойдет ошибка.
 
При работе с матрицей сохраняются абсолютно все принципы, что ранее были показаны ранее с векторами, с той разницей, что каждый элемент имеет уже два индекса. Первый из них мы будем называть строковым, а второй — столбцовым. Первым всегда идет строковый индекс.
 
Разберем эти принципы в следующем упражнении.
{|
|style="background-color:Orange"|<big>'''Упражнение'''</big>
|-
|style="background-color:WhiteSmoke"|
Для начала сгенерируем матрицу, над которой будем экспериментировать. Так как нам по существу все равно, чем она будет заполнена, воспользуемся стандартной функцией rand(), которая генерирует массивы, заполняя их псевдослучайными числами.
<source lang=Scilab>
-->A=rand(4,4) // создает матрицу 4x4
A =
0.2113249 0.6653811 0.8782165 0.7263507
0.7560439 0.6283918 0.0683740 0.1985144
0.0002211 0.8497452 0.5608486 0.5442573
0.3303271 0.6857310 0.6623569 0.2320748
</source>
Обратимся к элементу, стояшему во второй строке и третьем столбце
<source lang=Scilab>
-->A(2,3) // 2-ая строка, 3-ий столбец
ans =
0.0683740
</source>
Кроме простого обращения к элементам, можно обратиться ко всему столбцу или строке. Для этого используется символ двоеточия ':', который кодирует слово «все». Например,
<source lang=Scilab>
-->A(:,3) // обращение к 3-му столбцу
ans =
0.8782165
0.0683740
0.5608486
0.6623569
</source>
При использовании такого обращения на первых порах очень легко запутаться и вообще перестать понимать к чему вы обращаетесь. Чтобы этого не происходило, начинайте про себя проговаривать «я обращаюсь к <число> столбцу (строке)», при этом держа взгляд не на двоеточии, а на индексе с числом.
 
Теперь обратимся к последней строке
<source lang=Scilab>
-->A(4,:) // обращение к 4-ой строке
ans =
0.3303271 0.6857310 0.6623569 0.2320748
</source>
Опять же, если вы не знаете размера матрицы или не хотите вникать в такую подробность, то можете воспользоваться знаком доллара. Например, обратимся сначала к последнему столбцу, а потом к элементу, стоящему на пересечении последней строки и столбца
<source lang=Scilab>
-->A(:,$)
ans =
0.7263507
0.1985144
0.5442573
0.2320748
-->A($,$)
ans =
0.2320748
</source>
В качестве индексов матриц могут выступать векторы. В этом случае они выполняют роль диапазона индексов по строке или столбцу, что позволяет извлекать из матрицы сразу несколько отдельных элементов. Извлечем из нашей матрицы середину.
<source lang=Scilab>
-->A([2 3],[2 3]) // извлекаем из А элементы (2,2), (2,3), (3,2) и (3,3)
ans =
0.6283918 0.0683740
0.8497452 0.5608486
</source>
Следующая конструкция может показаться очень запутанной и непонятной
<source lang=Scilab>
-->A([1 $],[2 3 4])
ans =
0.6653811 0.8782165 0.7263507
0.6857310 0.6623569 0.2320748
</source>
Если вы внимательно ее изучите, то догадаетесь, что Scilab извлекает элементы с адресами, являющиеся сочетаниями без повторений двух множеств, образуемых векторами. Чтобы не путаться при этом, вам всегда нужно представлять себе, что Scilab извлекает элементы построчно. Разберем предыдущий пример. В качестве строкового индекса мы представили вектор [1 $], который говорит нам, что Scilab обработает строки исходной матрицы с номерами 1 и последним номером. Далее возникает вопрос «из каких столбцов будут извлекаться элементы?», на который отвечает диапазон столбцовых индексов [2 3 4], т.е. из столбца 2, столбца 3 и столбца 4. Таким образом полный набор сочетаний с учетом того, что обработка идет построчно, будет такова: (1,2), (1,3), (1,4), диапазон по столбцам закончился — переходим на новую строку: ($,2), ($,3), ($,4). Таким образом, вы можете с помощью векторов пропускать неугодные вам строки или столбцы.
 
Важно, чтобы индексы не противоречили реальным размерам матрицы, в противном случае система вернет ошибку обращения к матрице. Для того чтобы извлекать миноры из исходной матрицы, можно воспользоваться конструкцией с двоеточием, определяя диапазоны индексов с шагом. Например так,
<source lang=Scilab>
-->A([2:4],[1:3])
ans =
0.7560439 0.6283918 0.0683740
0.0002211 0.8497452 0.5608486
0.3303271 0.6857310 0.6623569
</source>
Последняя запись эквивалентна следующей
<source lang=Scilab>
-->A([2 3 4],[1 2 3])
ans =
0.7560439 0.6283918 0.0683740
0.0002211 0.8497452 0.5608486
0.3303271 0.6857310 0.6623569
</source>
В матрице вы также можете удалять строки и столбцы. Для этого вам нужно к ним обратиться и на их место поставить пустую матрицу. Удалим столбец 3 и строку 2.
<source lang=Scilab>
-->A
A =
0.2113249 0.6653811 0.8782165 0.7263507
0.7560439 0.6283918 0.0683740 0.1985144
0.0002211 0.8497452 0.5608486 0.5442573
0.3303271 0.6857310 0.6623569 0.2320748
-->A(:,3)=[]; A(2,:)=[]
A =
0.2113249 0.6653811 0.7263507
0.0002211 0.8497452 0.5442573
0.3303271 0.6857310 0.2320748
</source>
|}
Векторами и матрицами все не заканчивается. Пользователь может создавать массивы больших размерностей, например, создадим трехмерный массив
<source lang=Scilab>
-->B=rand(2,2,2)
B =
(:,:,1)
0.4419389 0.1607456
0.2987960 0.4816621
(:,:,2)
0.8496411 0.6894972
0.1152915 0.6928246
</source>
Для того, чтобы представить себе трехмерный массив, воспользуйтесь следующей аналогией. Представьте себе лист бумаги, на котором вы мысленно можете записать матрицу. Из примера это матрица с адресом (:,:,1). Один лист представляет первые два измерения (строки и столбцы матрицы). Теперь вы откладываете первый лист и берете второй, на котором пишите уже вторую матрицу (:,:,2). Затем второй листок вы накладываете поверх первого. Если бы в нашем примере было, скажем, не 2 матрицы, а 30, то столб из листков был бы относительно высоким. Именно высота этого столба представляет третье измерение.
 
Не теряя общности, вы можете продлжать рассуждения для четырехмерного массива, когда четвертым измерением предстает одна из сторон стола, на котором в ряд вы выкладываете столбики бумаги — трехмерные массивы. При пятом измерении вы раскладываете столбики уже по всему столу, а при шестом вы уже имеете много столов и так далее.
 
Количество измерений массива упирается в текущий размер стека, иными словами, пока есть память для хранения таких массивов. Хотя вам никто не запрещает пользоваться многомерными массивами, по возможности лучше держаться в пределах двух-, трехмерных массивов. Это связано не сколько с ограничением размера памяти, сколько неудобством ручной обработки таких массивов. Например, ввести вручную многомерный массив невозможно — для этого нужно воспользоваться специальной функцией '''hypermat()'''.
<source lang=Scilab>
// Пример применения функции hypermat(D[, V])
// D - вектор, каждый элемент которого представляет размер измерения многомерного массива
// [, V] - необязательный вектор, значениями которого заполняется многомерный массив.
// Его размер должен быть равен количеству всех элементов многомерного массива. Если он не указан, многомерный массив заполняется нулями.
-->A=hypermat([2 2 3])
A =
(:,:,1)
0. 0.
0. 0.
(:,:,2)
0. 0.
0. 0.
(:,:,3)
0. 0.
0. 0.
-->A=hypermat([2 2 3],1:12)
A =
(:,:,1)
1. 3.
2. 4.
(:,:,2)
5. 7.
6. 8.
(:,:,3)
9. 11.
10. 12.
</source>
 
Все принципы работы с массивами, рассмотренные ранее, распространяются и на многомерный случай.
 
==== Операции над матрицами ====
Для матриц и векторов предусмотрены следующие операции:
* сложение '+' — поэлементное сложение двух матриц. Матрицы должны быть одинаковых размеров;
* вычитание '-' — поэлементное вычитание элементов двух матриц. Матрицы должны быть одинаковых размеров;
* транспонирование " ' " (оператор в виде апострофа) — представление столбцов матрицы строками;
* матричное умножение '*' — умножение одной матрицы на другую. Матрицы должны быть совместны (число столбцов первого множителя должно быть равно числу строк второго). Если один из операндов представлен переменной, то каждый элемент матрицы будет помножен на эту переменную;
* возведение в степень '^' — умножение матрицы на себя n-ое количество раз;
* правое деление '/' — первый операнд делится на второй. Матрицы должны быть совместны;
* левое деление '\' — второй операнд делится на первый. Матрицы должны быть совместны;
* поэлементное умножение '.*' — матрицы перемножаются поэлементно (не путать с матричным умножением). Матрицы должны иметь одинаковые размеры;
* поэлементное возведение в степень '.^' — каждый элемент матрицы возводится в степень (не путать с возведением в степень матрицы);
* поэлементное правое деление './' — элементы первой матрицы делятся на элементы второй (не путать с делением матриц). Матрицы должны быть одинаковых размеров;
* поэлементное левое деление '.\' — элементы второй матрицы делятся на элементы первой (не путать с делением матриц). Матрицы должны быть одинаковых размеров.
 
Обратите внимание, что во всех поэлементных операциях присутствует точка. К массивам также применимы логические операции, которые производятся исключительно поэлементно.
 
{|
|style="background-color:#4169e1"|<big>'''Самостоятельно'''</big>
|-
|style="background-color:WhiteSmoke"|
# Создайте матрицу с помощью функции rand() размером 4x4 и присвойте ей имя 'А'.
# Создайте вектор 'v' из последней строки матрицы А. Помножьте вектор v на матрицу А и результат поставьте на место столбца 1 матрицы А (не забывайте о существовании операции транспонирования).
# Помножьте матрицу А на вектор v (не забывайте об условии «совместности»). Результат запишите во вторую строку матрицы А.
# Создайте единичную матрицу того же размера, что и А, и присвойте ей имя 'B'.
# Умножьте матрицу А на B. Затем поэлементно умножьте матрицу А на B. Объясните полученные результаты.
# В матрице удалите последний столбец и последнюю строку так, чтобы ее размер стал раным 3x3.
# Заполните диагональные (и по главной, и по побочной) элементы нулями любым кажущимся для вас рациональным способом (не забывайте и о существовании редактора переменных).
# Поэлементно возведите матрицу А в квадрат.
# Составьте из ненулевых элементов матрицы А новую матрицу 2x2 по следующему правилу: первый столбец матрицы представлен ненулевыми элементами второго столбца, ненулевой элемент первого столбца должен встать на позицию (2,2), а ненулевой элемент третьего столбца на оставшуюся свободную позицию. Результат запишите в А.
# Возведите матрицу в степень куба.
|}
 
'''Примечание''': в пункте 9 мы надеемся, что находчивый читатель догадался до следующей конструкции
<source lang=Scilab>
-->A=[A([1 3],2) A(2,[3 1])`]
</source>
Если вы поступили по-другому, то не переживайте, потому что в Scilab одна и та же задача может решаться многими способами, и на ранних порах важно достигли ли вы требуемого результата.
 
==== Функции для работы с матрицами ====
Так как все объекты в Scilab являются представлением массивов данных, то большинство функций «заточены» на работу с объектами как с массивами. Для работы с векторами и матрицами существует большое количество внутренних функций и простое их перечисление так же не эффективно в рамках обучения работе в среде. Необходимо пробовать их на практике и учиться на результатах.
 
Тем не менее, можно выделить ограниченный набор функций для работы с массивами, используемые так часто, что их заучивание является приоритетной целью. Именно этому мы посвятим данный раздел. Ниже в таблице переислены функции, которые рекомендуется запомнить.
 
{| class="standard"
!Имя функции
!Аргументы
!Назначение
|-
|'''size(V,[flag])'''
|V — массив;<br/>
flag — возможны следующие варианты: 'r' или 1 — возвращает число строк; 'c' или 2 — возвращает число столбцов
|Функция возвращает размеры массива в виде вектора, если не указаны флаги.
|-
|'''length(V)'''
|V — массив
|Функция возвращает число элементов в массиве
|-
|'''max(V,[flag])'''<br/>
'''max(V1,V2,...,Vn)'''
|V — массив
|Функция возвращает элемент с максимальным значением в указанном массиве или группе массивов (см. второй вариант вызова).
|-
|'''min(V,[flag])'''
|Аналогично функции '''max()'''
|Функция возвращает элемент с минимальным значением в указанном массиве или группе массивов.
|}
 
==== Разреженная матрица ====
Несложно догадаться, что общий объем памяти, необходимый для хранения матрицы, равен количеству элементов матрицы помноженному на объем памяти, который необходимо выделить для хранения типа данных, записываемого в эту матрицу. Такой способ хранения приемлем, когда каждый элемент несет в себе данные, однако, на практике имеют место быть особые виды матриц, называемые разреженными.
 
В разреженных матрицах большая часть элементов несет нулевое значение, что делает обычное выделение памяти на всю матрицу не эффективным. В системе Scilab предусмотрено создание разреженных матриц, в котором хранение элементов оптимизировано: память выделяется только на ненулевые элементы. Создать разреженную матрицу можно с помощью функции
<source lang=Scilab>
sparse([i1 j1;i2 j2;...],[n1,n2,...])
</source>
В качестве аргументов данной функции необходимо передать два вектора:
* в первом векторе необходимо перечислить адреса ненулевых элементов;
* в втором векторе необходимо перечислить значения, которые будут записаны по данным адресам.
<source lang=Scilab>
// Пример
--> A=sparse([1 1;2 1;4 4;1 3],[25 26 31 32])
A =
 
( 4, 4) sparse matrix
 
( 1, 1) 25.
( 1, 3) 32.
( 2, 1) 26.
( 4, 4) 31.
</source>
Обратите внимание на особый формат представления разреженной матрицы. Разреженная матрица ничем не отличается, кроме способом выделения памяти, следовательно к этим матрицам применимы все операции рассмотренные ранее.
<source lang=Scilab>
//Пример
-->B=zeros(4,4);
-->A+B
ans =
25. 0. 32. 0.
26. 0. 0. 0.
0. 0. 0. 0.
0. 0. 0. 31.
-->A(4,1)
ans =
( 1, 1) zero sparse matrix
-->A(1,1)
ans =
( 1, 1) sparse matrix
( 1, 1) 25.
</source>
Иногда формат вывода разреженных матриц, используемый по умолчанию, не всегда удобен, поэтому специально для них используется функция '''full()'''.
<source lang=Scilab>
-->full(A)
ans =
25. 0. 32. 0.
26. 0. 0. 0.
0. 0. 0. 0.
0. 0. 0. 31.
</source>
 
=== Списки ===
'''Список в Scilab''' — это массив (или структура), состоящий из элементов разных типов данных.
 
Список может быть создан вручную или с помощью одной из следующих функций:
* '''list()''' — создает список, поля которого могут содержать произвольный тип данных;
* '''tlist()''' — создает ''типизованный список'';
* '''mlist()''' — создает матричноориентированный типизованный список.
Типизованные списки используются главным образом для создания классов объектов в рамках объектно-ориентированного программирования.
{|
|style="background-color:Orange"|<big>'''Упражнение'''</big>
|-
|style="background-color:WhiteSmoke"|
Для начала создадим простой список с помощью функции '''list()'''. Для этого достаточно вызвать функцию и в качестве аргументов перечислить объекты списка. При этом мы не ограничены типами объектов.
<source lang=Scilab>
-->lt=list(complex(12,6),[23 12],[1 2;3 4]);
</source>
Чтобы обратится к элементу списка, достаточно указать его индекс. Например, обратимся к первому элементу и к элементу (4,4) матрицы
<source lang=Scilab>
-->lt(1),lt(3)($,$)
ans =
12. + 6.i
ans =
4.
</source>
Обратите внимание, как при обращении к матрице происходит индексация:сначала индекс списка, а затем индекс матрицы. Список может наращиваться с начала и с конца. Для наращивания с начала необходимо обратиться к нулевому элементу списка, после чего добавленный элемент станет первым, а все остальные сместятся на позицию вправо. Для добавления элемента в конец нужно обратится к элементу списка с индексом ($+1).
<source lang=Scilab>
-->lt(0)=25;
-->lt(1)
ans =
25.
-->lt($+1)=24;
-->lt($)
ans =
24.
</source>
В любой момент можно удалить элемент списка. Для этого нужно воспользоваться специальной функцией '''null()'''.
<source lang=Scilab>
-->lt(3)=null()
lt =
lt(1)
25.
lt(2)
12. + 6.i
lt(3)
1. 2.
3. 4.
lt(4)
24.
</source>
Как и для вектора, служебный символ ':' кодирует слово «все», позволяя выделить все элементы списка
|}
 
=== Другие ===
В Scilab имеют место быть объекты, которые могут быть созданы только с помощью функций, а их внутренняя организация скрыта от пользователя под оболочкой. Такие объекты мы классифицировали как другие, и им посвящен данный раздел.
 
==== Полином ====
Из алгебры вы знаете, что полиномом называется алгебраическое уравнение вида
<center><math>
a_n x^n+a_{n-1} x^{n-1} + ... + a_{1} x + a_0 =0, a_n \ne 0, n \geqslant 1 .
</math></center>
Полином в среде Scilab может быть определен как объект polynomial, с которым работают специальные функции, например функции поиска корней. Полином можно определить через функцию '''poly()'''.
<source lang=Scilab>
poly(a,vname,['flag'])
// a — число или матрица (смысл зависит от используемого флага).
// vname — имя символьной переменной в виде строки. В строке используется первые 4 символа.
// ['flag'] — флаг, определяющий принцип расстановки коэффициентов полинома.
// Возможны варианты:
// 'r' или 'roots' — коэффициенты формируются относительно корней полинома, представленных в 'a';
// 'c' или 'coeff' — коэффициенты формируются из значений, представленных в 'a'.
</source>
Для работы с полиномами существует несколько функций:
* '''varn()''' — позволяет поменять или узнать символичесуцю переменную у указанного полинома;
* '''coeff()''' — позволяет выписать коэффициенты полинома. Коэффициенты выписываются, начиная с младшей степени при символической переменной, и записываются в вектор-строку.
{|
|style="background-color:Orange"|<big>'''Упражнение'''</big>
|-
|style="background-color:WhiteSmoke"|
Введем полином второго порядка, который мы разрешали ранее в разделе «[[Scilab#Работа с сессией|Работа с сессией]]». Напомним, что его коэффициенты -10, 4, 2.
<source lang=Scilab>
-->p=poly([-10 4 2],'x','c')
p =
2
- 10 + 4x + 2x
</source>
Теперь попробуем поменять символьную переменную на 's'.
<source lang=Scilab>
-->p=varn(p,'s')
p =
2
- 10 + 4s + 2s
</source>
Для поиска корней полинома в Scilab существует функция roots(). Применим ее на данном полиноме.
<source lang=Scilab>
-->R=roots(p)
R =
- 3.4494897
1.4494897
</source>
Если бы вы знали об этой функции и об объекте polynomial раньше, то упражнение по работе с командным окном показалось бы вам по меньшей мере странным, так как вы добились того же результата всего в две строки. Теперь относительно этих корней сгенерируем тот же полином
<source lang=Scilab>
-->poly(R,'x','r')
ans =
2
- 5 + 2x + x
</source>
Обратите внимание на то, что Scilab учел кратность.
<source lang=Scilab>
-->2*ans
ans =
2
- 10 + 4x + 2x
-->coeff(ans)
ans =
- 10. 4. 2.
</source>
В качестве первого аргумента вы можете передавать матрицу, однако генерировать полином можно будет только с флагом 'r'. Например так
<source lang=Scilab>
-->A=[1 2 3; 4 5 6]
A =
1. 2. 3.
4. 5. 6.
-->poly(A,'x','r')
ans =
2 3 4 5 6
720 - 1764x + 1624x - 735x + 175x - 21x + x
</source>
|}
 
==== Математическая функция ====
В Scilab есть предопределенные математические функции, такие как тригонометрические, экспонента и другие. Но что, если вам необходимо определить собственную функцию? Далее мы будем отличать математические функции и программируемые функции. Разница между ними заключается в том, что программируемые функции призваны реализовывать некоторый алгоритм, в то время как математическая функция отражает связь между множеством аргументов и множеством значений функции.
 
Отметим, что математическую функцию можно объявить через программирование, но так как обычно ее тело состоит из одной строчки, то рациональнее всего объявлять ее через специальную функцию '''deff()'''. Общий синтаксис имеет вид
<source lang=Scilab>
deff('[Y1,Y2...]=Fname(X1,X2,...)',['Y1=выражение_1';'Y2=выражение_2;...'])
// [Y1,Y2...] — вектор возвращаемых переменных (имена назначаете сами)
// Fname — имя функции, которое вы назначаете сами
// (X1,X2,...) — список из аргументов функции
// 'Y1=выражение_1;Y2=выражение_2;...' — для каждой выходной переменной должно быть определено выражение,
// которое может зависеть от аргументов, а может и не зависеть.
</source>
Данная конструкция поначалу кажется сложной и неизбежны ошибки при ее вводе. Главное не забывать, что аргументы для функции deff() вы передаете в виде строк, которые затем разбиваются на лексемы и из которых среда строит программируемую функцию.
 
{|
|style="background-color:Orange"|<big>'''Упражнение'''</big>
|-
|style="background-color:WhiteSmoke"|
Объявим квадратичную функцию следующим образом
<source lang=Scilab>
-->deff('y=f(x)','y=x^2')
</source>
Убедимся в том, что мы объявили функцию
<source lang=Scilab>
-->whos -name 'f'
Name Type Size Bytes
f function 192
fft fptr 40
fileiolib library 624
functionslib library 752
</source>
Отметим, что наша функция хранится в памяти в компилированном или бинарном виде, так как по умочанию был применен флаг 'c'. Компилированные функции работают быстрее, однако после компиляции они привязываются к операционной системе, в которой работает Scilab. В большинстве случаев вам не нужно задумываться над тем «компилировать функцию или нет?». О компиляции функций мы поговорим, когда будем учиться писать библиотеки функций, а сейчас попробуем вызвать функцию
<source lang=Scilab>
-->f(25)
ans =
625.
</source>
Очевидно, что функция работает правильно. Отметим, что deff() еще и интегрирует функцию в среду, в связи с чем вы можете передавать в качестве аргументов векторы. Например так
<source lang=Scilab>
-->f([2 3 4 5])
ans =
4. 9. 16. 25.
</source>
Усложним функцию следующим образом
<source lang=Scilab>
-->deff('[x y]=f(z,u)',['x=z^2-u';'y=u^3'])
// Примечание: в версии для Linux может возникнуть ошибка 37. Чтобы ее присечь, необходимо обязательно разделять элементы вектора запятой, т.е. [x,y].
</source>
Созданная функция переопределится, о чем вам скажет предупреждающее сообщение. Если вы не хотите постоянно видеть это предупреждение, то воспользуйтесь функцией '''funcprot(0)'''.
 
Этой строкой мы создали сложную функцию, которая принимает уже два обязательных аргумента и возвращает вектор результатов. Функция сложная потому, что ее тело состоит уже из двух строк. Обратите внимание, что тело сложной функции должно передаваться '''deff()''' вектором-столбцом, каждая строка которого является инструкцией, записываемой строковым типом данных.
 
Вызовем нашу функцию
<source lang=Scilab>
-->f(2,2)
ans =
2.
</source>
Очевидно, что мы получили не то, что хотели, ведь функция должна была вернуть вектор. К сожалению, в данном случае ''ans'' не переопределилась автоматически системой в вектор и был записан только результат расчета переменной x, потому что при объявлении в '''deff()''' мы ее записали первой. Чтобы получить ответ целиком, мы должны слева от вызова явно показать вектор. В этом случае мы должны объявить некоторые переменные, в которые будет записываться результат, либо воспользоваться переменной ''ans'' вот так
<source lang=Scilab>
-->[ans ans]=f(2,2)
ans =
2.
ans =
8.
</source>
В этом случае в ''ans'' сначала запишется результат первой инструкции, а затем результат второй инструкции. Такой способ записи результата приемлем, если мы хотим просто посмотреть результат расчета, но сам результат не планируем никак использовать. Запишем результат расчета в вектор следующим образом
<source lang=Scilab>
-->[a(1),a(2)]=f(2,2);
-->a
a =
2.
8.
</source>
Все аргументы нашей сложной функции являются обязательными и нельзя вызвать функцию, не передав их все. Например, попробуйте сделать такой вызов
<source lang=Scilab>
-->f(3)
!--error 4
Неизвестная переменная: u
at line 2 of function f called by :
f(3)
</source>
В дальнейшем мы научимся обходить это ограничение, перегружая функцию.
|}
Обратите внимание на функцию '''funcprot()''' (от {{lang-en|function protection}}). С помощью '''funcprot()''' вы можете защитить ваши функции от случайного их переопределения. Функция принимает один целочисленный аргумент:
* 0 — отключение механизма защиты;
* 1 — формирование предупреждения (используется по умолчанию);
* 2 — формирует ошибку при попытке переопределения существующей функции.
 
Вообще говоря, при определении функции через '''deff()''' она может иметь сколь угодно много инструкций, которые необходимо записывать в вектор, как это было показано в упражнении. Однако, запись становится неудобочитаемой и в этом случае целесообразнее использовать уже вторую конструкцию '''function...endfunction''', а также пользоваться редактором ''scinotes'', о котором мы будем говорить дальше. Общий синтаксис выглядит так
<source lang=Scilab>
function <выходные переменные>=имя_функции(аргументы)
...
инструкции
...
endfunction
</source>
Данная конструкция, как правило, используется для написания пользовательских программируемых функций, однако, в зависимости от предпочтений пользователя, она может использовать и вместо функции '''deff()'''. Использовать эту конструкцию можно в интерпретаторе, который воспринимает ее по особому. Сначала необходимо ввести первую строку с ключевым словом ''function'', именем функции, аргументами и выходными переменными. Далее вы можете нажать <Enter> и интерпретатор будет воспринимать все, что вы вводите, как инструкции для данной функции до тех пор, пока вы не введете ключевое слово ''endfunction''. Если вы не допустили синтаксических ошибок в теле функции, то она будет готова к использованию, в противном случае интерпретатор выведет вам ошибку и объявлять придется заново. Именно поэтому при написании больших функции следует пользоваться исключительно ''scinotes''.
 
В рамках данного раздела покажем как можно объявить функцию f через конструкцию '''function...endfunction'''.
<source lang=Scilab>
-->function x=f(z)
-->x=z^2
-->endfunction
-->f(4)
ans =
16.
</source>
 
== Практикум ==
В данном разделе будут представлены конкретные примеры и способы их решения в среде Scilab. Целью данного раздела является закрепление уже накопленных вами знаний, а также попутное изучение возможностей среды.
 
Практически для всех тривиальных задач в системе заготовлены стандартные функции. Перед тем, как мы начнем их разбирать, возьмите за правило:
<blockquote>
Если в системе существует функция, которая реализует по крайней мере часть задачи, которую вы решаете, всегда используйте эту функцию и не прибегайте к программированию.
</blockquote>
Дело в том, что все функции, входящие в стандартную комплектацию, тестируются разработчиками и оптимизированы под среду. В этом случае любой ваш программируемый алгоритм будет всегда менее эффективен по скорости, чем уже готовый. Хотя возможно это и не всегда так, но поверьте, что затраты времени на «придумывание велосипеда» в большинстве случаев не окупаются.
 
=== Простые выражения ===
Для начала попробуем повычислять простые выражения.
 
'''Пример 1'''
Вычислить<br\>
<center><math> \sin{\left( \frac{5 \cdot 6\sqrt{94-56}+6\sqrt{291+2}}{6 \cdot 41,25^2\cdot\sqrt{25 \cdot 26 +1}}\right)}^{\lg{36,25}+\ln{34,25}} .</math></center>
 
Данное выражение является сложным и требует предварительного разбора. Конечно, можно ввести данное выражение одной строкой в командное окно, но в данном примере мы вычислим его по частям для лучшего понимания материала.
 
Для начала необходимо определиться с очередностью выполняемых действий. При несложном разборе очередность такова:
# Рассчитать числитель дроби функции синуса;
# Рассчитать знаменатель дроби функции синуса;
# Числитель поделить на знаменатель;
# Найти синус от результата 3;
# Рассчитать выражение ''степени'';
# Возвести результат 4 в степень результата 5.
 
Описанный алгоритм отражает следующий листинг
<source lang=Scilab>
-->5*6*sqrt(94-56)+6*sqrt(291+2); // Вычисляем числитель
-->ans/(6*41.25^2*sqrt(25*26+1)); //Вычисляем знаменатель
-->sin(ans); // Вычисляем синус
-->ans^(log10(36.25)+log(34.25)) // Возводим в степень
ans =
8.715D-16
</source>
Обратите внимание на то, что мы используем для хранения промежуточных результатов переменную ''ans''. В этом примере исходный алгоритм немного облегчен, так, в 4 строке листинга мы объединили пункты 4 и 5.
 
В этом примере мы использовали две новые функции:
* '''log10()''' — вычисляет десятичный логарифм;
* '''log()''' — вычисляет натуральный логарифм.
В среде нет функции, которая реализует логарифм по произвольному основанию, но это не является проблемой. По свойству логарифма<br/>
<center><math>\log_a b = \frac{\log_c b }{\log_c a} ,</math></center>тогда, например, логарифм 4 по основанию 2 можно вычислить так
<source lang=Scilab>
-->log10(4)/log10(2) // через десятичный логарифм
ans =
2.
-->log(4)/log(2) // через натуральный логарифм
ans =
2.
</source>
Стоит упомянуть, что в среде есть также встроенная функция для вычисления логарифмов по основанию 2 — '''log2()'''.
 
'''Пример 2'''<br\>
Вычислить<br\>
<center><math>\frac{log_6 4+log_7 9}{log_{4^{-1}} 32 \cdot log_5 500} .</math></center>
 
В примере мы вновь возвращаемся к проблеме вычисления логарифма по произвольному основанию, однако применение свойства в данном случае напрямую серьезно усложнит само выражение. В данном случае рациональнее всего объявить собственную функцию, которая бы вычисляла логарифмы при любом основании.
 
Воспользуемся свойством логарифма и объявим функцию '''logn()'''.
<source lang=Scilab>
-->deff('out=logn(m,n)','out=log10(m)/log10(n)')
// Имея теперь функцию, легко записать исходное выражение
-->(logn(4,6)+logn(9,7))/(logn(32,4^-1)*logn(500,5))
ans =
- 0.1971180
</source>
 
=== Алгебра ===
В рамках данного раздела мы рассмотрим способы решения самых распространенных задач алгебры.
 
==== Решение алгебраических уравнений ====
Найти корни уравнения<br />
<center><math>2x^3-8x^2-7x+21=0.</math></center>
 
Ранее мы решали подобную задачу. Напомним, что для решения линейных уравнений в среде имеется функция '''roots()''', которая принимает в качестве аргумента объект ''полином''. Практически все действия выполняет за вас среда, необходимо только объявить полином. Напомним, что полином объявляется функцией '''poly()'''. В нашем случае полином составляется из коэффициентов, которые нужно переписать в обратном порядке.
 
<source lang=Scilab>
-->p=poly([21 -7 -8 2],'x','c')
p =
2 3
21 - 7x - 8x + 2x
-->roots(p)
ans =
4.2415355
- 1.6987739
1.4572384
</source>
 
Функция '''roots()''' имеет флаг, определеяющий используемый алгоритм:
* 'f' — расчет по алгоритму Дженкинса-Трауба (RPOLY-алгоритм); используется по умолчанию;
* 'e' — расчет через собственные вектора сопровождающих матриц.
RPOLY-алгоритм используется главным образом для поиска действительных и комплексных корней с порядком полинома, не превышающем 100. Второй алгоритм существует как альтернатива ему. В большинстве случаев RPOLY-алгоритма достаточно для решения многих задач, поэтому пользоваться флагом приходится редко.
 
Для примера, найдем корни следующего полинома по второму алгоритму
<center><math>x^3+0,4 x^2+0,6 x - 1 = 0 .</math></center>
 
<source lang=Scilab>
-->roots(poly([-1 0.6 0.4 1],'x','c'),'e')
ans =
- 0.5576818 + 1.0425361i
- 0.5576818 - 1.0425361i
0.7153636
</source>
 
==== Решение систем уравнений ====
 
==== Решение трансцендентных уравнений ====
Трансцендентные уравнения решаются преимущественно численными методами. Обычно этот процесс заключается в выборе интервала, в который попадает по крайней мере один корень уравнения, а затем производится численное приближение к этому корню.
 
В Scilab определена всего одна функция для решения трансцендентных уравнений '''fsolve()'''. Если возможности этой функции по какой-либо причине не устраивают, то обычно пишут собственную функцию, реализующую некоторый численный метод.
 
Найти корни<br />
<center><math>e^x/5-2(x-1)^2-\sqrt[3]{x^2}=0 .</math></center>
 
==== Матричная алгебра ====
 
=== Функциональный анализ ===
 
=== Интегральное и дифференциальное исчисления ===
 
=== Статистика ===
 
=== Работа с текстовыми строками ===
 
== Программирование ==
В данной главе будут рассматриваться возможности программирования в среде Scilab. Помимо встроенного в среду структурного языка, Scilab позволяет использовать некоторые другие языки программирования.
 
Написание сценариев составляет большую часть работы в среде.
 
=== Основные понятия и определения ===
Для начала мы введем несколько терминов, которые будут использоваться при изложении. Прежде всего это понятия '''сценарий''' и '''программируемая функция'''.
 
''Сценарием'' мы будем называть любую программу Scilab. Любой сценарий состоит из '''инструкций''', которые описывают конкретные действия с объектами Scilab. Инструкция может быть представлена несколькими операндами, связанные каким-либо образом операторами. Также вызов программируемой функции мы тоже будем называть инструкцией.
 
'''Программируемая функция''' или просто '''функция''' также является сценарием, но выделяется она наличием имени, благодаря которому к ней можно обратиться из любого места сценария, в котором эта функция вызывается.
 
=== Язык Scilab ===
В Scilab имеется встроенный язык программирования, который необходимо знать для эффективной работы в среде. Данный язык является ''структурным'' с поддержкой объектов.
 
В структурном программировании сценарий представляет последовательность инструкций, которые выполняются последовательно друг за другом, словно на конвейере. До этого момента вы еще не писали серьезные сценарии, хотя работа с командной строкой в каком-то смысле является написанием сценария, в котором инструкции генерируются вами «по ходу».
 
В структурном программировании существует ряд особых конструкций, которые мы не использовали до сих пор, так как наши инструкции были очень простыми. К ним относятся:
* '''Ветвление''' — однократное выполнение одной из двух или более операций в зависимости от заданного условия;
* '''Цикл''' — многократное выполнение одной или нескольких инструкций до тех пор, пока не выполнится некоторое условие. Один проход по всем инструкциям внутри цикла называется '''итерацией'''.
Данные конструкции кодируются с помощью специальных ''служебных слов'', которые не могут быть использованы для имен объектов.
 
Сценарии Scilab, как правило, пишутся пользователем во встроенном редакторе ''Scinotes'', тем не менее, не запрещается использовать любой другой доступный текстовый редактор. Чтобы открыть редактор можно:
* Ввести команду '''scinotes''' в командное окно;
* Сделать активным командное окно, а затем на панели инструментов нажать на кнопку ''Открыть SciNotes'', либо открыть меню ''Инструменты'' и выбрать пункт ''Текстовый редактор SciNotes''.
 
Перед вами появится следующее окно <!-- рисунок -->
 
Внешне SciNotes похож на обыкновенный текстовый редактор на вроде ''gedit'' или ''блокнота''. В нем присутствуют команды по форматированию текста и специфичные команды для запуска сценариев, которые вы можете найти в раскрывающемся меню ''Выполнить''.
 
Для примера попробуем написать простой сценарий. Введите в Scinotes следующий код
<source lang=Scilab>
s='Hello, World!'
disp(s)
</source>
Таким образом вы написали сценарий, состоящий из двух инструкций: объявление строки и вывода строки в командное окно с помощью встроенной функции '''disp()'''. Сохраним наш сценарий, для чего необходимо:
# В раскрывающемся меню ''Файл'' выбрать пункт ''Сохранить как'', либо нажать комбинацию <Ctrl>+<Shift>+<nowiki><S></nowiki>;
# В диалоговом окне выбрать доступную директорию, затем ввести имя файла сценария, например ''myScript'', и выбрать расширение ''*.sce'' (от {{lang-en|Scene}});
# Нажать кнопку ''Сохранить''.
 
Файлы сценариев имеют расширение ''*.sce'' и могут хранить в себе программируемые функции и исполняемые участки кода, т.е. собственно сценарий. Также есть и другое расширение — ''*.sci''. Файлы с таким расширением должны хранить в себе только программируемые функции, которые можно будет подгрузить в текущую сессию для вызова их либо пользователем, либо каким либо сценарием. Эти два расширения являются часто используемыми, однако кроме них Scinotes позволяет создавать файлы с рядом других специфичных расширений, о которых мы поговорим чуть позже.
 
Теперь попытаемся выполнить наш сценарий, для чего нужно выполнить одно из следующих действий:
* Сделать активным окно ''Scinotes'' и нажать на панели инструментов кнопку ''Выполнить'' (обратите также на кнопку команды ''Сохранить и выполнить'');
* Выбрать в раскрывающемся меню ''Выполнить'' желаемую команду;
* Нажать горячую клавишу <F5>.
 
В командном окне вы увидите следующее
 
<source lang=Scilab>
-->exec('D:\myScript.sce', -1)
Hello, World!
</source>
Очевидно, что нажатие по кнопке вызывает встроенную функцию '''exec()''', которая исполняет сценарий, передаваемый ей в качестве аргумента. Отметим также, что функцией '''exec()''' подгружаются и sci-файлы. Пока не будем акцентировать внимания на приемы работы со сценариями и попробуем создать sci-файл.
 
Сделав активным окно ''Scinotes'', нажмите комбинацию <Ctrl>+<N>, либо нажмите на кнопку ''Новый'' на панели инструментов. Вы увидите, что под внутренним заголовком окна появится вкладка нового безымянного документа. Нажмите на комбинацию <Ctrl>+<Shift>+<nowiki><S></nowiki> и сохраните файл под именем ''myFunc'' с расширением ''sci''. В самом файле запишите следующий код
<source lang=Scilab>
function y=cube(x)
y=x^3
endfunction
 
function y=pow(x)
y=x^2
endfunction
</source>
Во время объявления функций вы могли заметить, что при вводе ключевого слова ''function'', ключевое слово ''endfunction'' вводится автоматически. Эта возможность включается и отключается в меню Настройки->Автоопределение включить (комбинация <Ctrl>+<Shift>+<nowiki><H></nowiki>). Туда же входит не менее полезная функция автоматического закрывания скобок.
 
Сохраните изменения. Теперь для загрузки ваших функций в окружение можно нажать кнопку <F5>. Вы увидите как функция '''exec()''' подгрузит в среду ваши функции. Теперь вы можете свободно вызывать их из командной строки
<source lang=Scilab>
-->cube(3),pow(2)
ans =
27.
ans =
4.
</source>
Далее мы рассмотрим основы программирования на встроенном языке Scilab и по ходу знакомится с методами написания сценариев.
==== Основы языка Scilab ====
Для начала введем несколько правил относительно стиля написания сценариев. Это необходимо для того, чтобы уменьшить число ошибок на первых порах и сохранить удобочитаемость кода.
* Каждая инструкция должна писаться с новой строки;
* В сценариях можно допускать объявление переменных по мере их необходимости, но в функциях мы будем придерживаться правила объявления всех используемых объектов строго сверху;
* Правилом хорошего тона считается явное удаление объектов, если не предполагается их дальнейшее использование в сценарии.
 
В языке Scilab существует небольшой набор базовых конструкций, реализующих циклы и ветвления. Рассмотрим их по порядку.
 
===== Ветвления =====
В языке Scilab две конструкции, организующие ветвление:
# Конструкция '''if ... else''';
# Конструкция '''select ... case'''.
 
Общий синтаксис конструкции '''if ... else''' имеет следующий вид
<source lang=Scilab>
if <условие 1> then
<операторы 1>
elseif <условие 2> then
<операторы 2>
...
elseif <условие n> then
<операторы n>
else
<операторы>
end
</source>
На позициях <условие> записываются логические выражения, которые возвращают логический или числовой тип данных. Общий алгоритм работы данной конструкции выглядит так:
# Проверяется <условие 1>. Если условие истинно или, если это число, оно больше нуля, то выполняются <операторы 1> и ветвление завершается, в противном случае переход к пункту 2;
# Проверяется <условие 2> Если условие истинно или, если это число, оно больше нуля, то выполняются <операторы 2> и ветвление завершается, в противном случае переход к следующему elseif и так далее;
# Если ни одно из условий elseif не выполнилось, то выполняются операторы по ветке else и на этом ветвление завершается.
 
Общий синтаксис второй конструкции имеет вид
<source lang=Scilab>
select <значение>
case <значение 1>
<операторы 1>
case <значение 2>
<операторы 2>
...
case <значение n>
<операторы n>
else
<операторы>
end
</source>
 
В отличии от первой конструкции, вторая требует не логическое выражение, а конкретное значение, которое затем сравнивается по порядку со значением каждой ветви, начинающейся с ключевого слова case. При первом же совпадении выполняются операторы этой ветви. Если ни одного совпадения не оказалось, то выполняются операторы ветви else.
 
В первой конструкции объявление ветвей elseif не является обязательным, но должна быть по крайней мере ветвь по if. Ветвь else в обоих конструкциях также не является обязательной.
 
{|
|style="background-color:Orange"|<big>'''Упражнение'''</big>
|-
|style="background-color:WhiteSmoke"|
С одним из примеров ветвлений можно столкнуться при решении квадратных уравнений на множестве действительных чисел. Если дискриминант уравнения больше нуля, то мы можем сказать, что уравнение имеет два действительных корня; если дискриминант меньше нуля, то действительных корней уравнение не имеет и, наконец, если дискриминант равен нулю, то уравнение имеет два совпадающих по значению действительных корня.
 
Для примера напишем функцию, которая бы искала корни квадратного уравнения на множестве действительных чисел. Откройте SciNotes и введите следующую функцию
<source lang=Scilab>
function [y1,y2]=rootsOfBinomial(cf)
c=cf(1)
b=cf(2)
a=cf(3)
D=b^2-4*a*c
if D<0 then
disp("Уравнение не имеет действительных корней")
y1=%nan
y2=y1
elseif D==0 then
y1=-b/(2*a)
y2=y1
else
y1=(-b+sqrt(D))/2*a
y2=(-b-sqrt(D))/2*a
end
endfunction
</source>
|}
 
===== Циклы =====
В языке Scilab всего два вида циклов:
# Цикл '''for''';
# Цикл '''while'''.
 
Общий синтаксис для цикла '''for''' имеет вид
<source lang=Scilab>
for <счетчик>=<начальное значение>:<шаг>:<конечное значение>
<операторы>
end
</source>
Цикл '''for''' как правило используется для перебора элементов с операциями над ними на некотором ограниченном множестве, либо когда количество итераций нам известно. Цикл будет выполняться до тех пор, пока счетчик не станет больше введенного конечного значения. Шаг является не обязательным параметром для счетчика и по умолчанию он принимается равным единице.
 
Для цикла while синтаксис имеет следующий вид
<source lang=Scilab>
while <условие>
<операторы>
end
</source>
Цикл '''while''' выполняется до тех пор, пока условие истинно. Обычно данный цикл используется, когда число итераций нам заранее неизвестно. С данным циклом необходимо быть особенно внимательным, так как зачастую можно задать условие, которое будет истинно всегда. В этом случае цикл становится бесконечным и имеет место так называемое '''зацикливание'''.
 
Иногда довольно сложно записать точное условие выхода из цикла явно. В этом случае нарочно создают бесконечный цикл, а условие выхода задают уже в теле с помощью специальных управляющих операторов.
 
Управление циклом в его теле возможно с помощью следующих специальных операторов:
* '''continue''' — передача управления следующей итерации;
* '''break''' — прекращение текущей итерации и выход из цикла.
 
{|
|style="background-color:Orange"|<big>'''Упражнение'''</big>
|-
|style="background-color:WhiteSmoke"|
|}
 
=== Использование других языков программирования ===
 
=== Создание пользовательских библиотек ===
 
== Визуализация ==
 
=== Построение графиков ===
 
=== Создание интерфейса пользователя ===
 
=== Анимация ===
 
[[Категория:Языки программирования]]