SCILAB: Часть 1.Основы программирования в Scilab

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

Александр Бикмеев, разработчик, EPAM Systems

Бикмеев А.Т.Бикмеев Александр Тимерзянович, кандидат физико-математических наук, доцент кафедры Высокопроизводительных вычислительных технологий и систем УГАТУ. Убежденный сторонник свободного ПО и давний пользователь ОС GNU Linux. Александр считает, что знания должны быть открыты для всех и поэтому занимается популяризацией и расширением возможностей свободных приложений для науки и производства.



12.02.2010

Обозначения

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

  • код из консоли Scilab или для редактора скриптов Scipad записывается
    моноширинным шрифтом на сером фоне
  • жирным шрифтом указываются ключевые слова;
  • в угловых скобках указываются <названия элементов>, которые вводятся или определяются пользователем. При этом в настоящем коде угловые скобки не вводятся.

Что такое Scilab

Scilab – это кроссплатформенная система компьютерной алгебры (СКА), обладающая сходным с Matlab синтаксисом встроенного языка. Разработка системы Scilab ведется сотрудниками французского Национального института информатики и автоматизации (INRIA – Institut National de Recherche en Informatique et Automatique) с 80-х годов прошлого века.

Изначально это был коммерческий проект под названием Blaise, а затем Basile. С 2003 года продукт получил новое имя Scilab и стал бесплатным. В настоящее время он распространяется по свободной лицензии CeCILL.

Сама система Scilab, как и Matlab, предназначена прежде всего для численных расчетов и работы с матрицами. Кроме того, она обладает развитыми средствами программирования (включая отладчик скриптов), так что ее в какой-то мере можно рассматривать как систему разработки высокотехнологичных приложений.

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


Редактор SciPad

В данном цикле статей мы не будем останавливаться на выполнении вычислений в Scilab, не будем также рассматривать встроенные функции и их параметры. Эту информацию можно найти в Интернете (см. раздел «Ресурсы»), а также в справочных материалах самой системы. Мы займемся изучением непосредственно программирования в Scilab.

Для удобства написания скриптов (функций) в Scilab имеется встроенный редактор – Scipad. Он позволяет редактировать тексты функций, выполнять их в режиме отладки, содержит функцию автодополнения кода, а также средства непосредственной передачи текста программы в среду Scilab на выполнение.

Открыть редактор можно двумя способами:

  • подать в консоли Scilab команду scipad
  • выбрать в главном окне последовательно пункты меню Инструменты → Редактор.
Рисунок 1. Внешний вид редактора SciPad
Рисунок 1. Внешний вид редактора SciPad

В моей системе установлена Scilab 5.1, в которой присутствует редактор Scipad 7.18. Внешний вид редактора показан на рисунке 1. Как видно, интерфейс достаточно прост. Кратко рассмотрим пункты меню:

File – здесь находятся стандартные команды для работы с файлами: открыть (Open), закрыть (Close file), сохранить (Save) и т. д., а также команды импорта файлов функций из формата Matlab и формирования справочных материалов.

Edit – содержит стандартные для пункта меню Правка операции: копировать (Copy), вставить (Paste), вырезать (Cut), выделить все (Select All) и т. д.

Search – здесь находятся функции поиска по тексту.

Execute – содержит пункты, позволяющие передать содержимое редактора в среду Scilab на выполнение или выполнить только выделенную часть.

Debug – содержит команды для организации и выполнения отладки, такие как включение точек останова (breakpoint), добавление переменных в список наблюдения (watch), настройка запуска функции и т. д. К сожалению, в Scilab 5.1 данный режим недоступен вследствие наличия неустраненной ошибки.

Scheme – команды управления подсветкой синтаксиса.

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

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

Мы будем использовать этот редактор во всех уроках серии для создания новых функций и их тестирования.


Сохранение, загрузка и выполнение скриптов пользователя

Сохранить созданный скрипт можно при помощи пунктов меню File:

  • File > Save – сохранить скрипт;
  • File > Save as – сохранить скрипт под другим именем;
  • File > Save all – сохранить все открытые скрипты.

Для открытия файла скрипта необходимо выполнить File > Open, а затем перейти в каталог с необходимым файлом, выбрать его и нажать кнопку Open. Кроме того, в самом меню File имеется список последних открывавшихся файлов.

Чтобы протестировать функцию, ее необходимо передать в основное окно Scilab (консоль). Для этого необходимо воспользоваться меню Execute, в котором присутствуют три пункта:

  • Load into Scilab – загрузить в Scilab текущий скрипт;
  • Load all into Scilab – загрузить в Scilab все открытые скрипты;
  • Evaluate selection – выполнить в консоли Scilab только выделенные строки.

Стандартные конструкции встроенного языка

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

Переменные не описываются, а создаются путем присвоения им начального значения, например так:

a = 1
b='Hello'
c= %t

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

Вследствие Unix-корней системы, важен регистр букв в имени переменных, например:

-->d=3;D='три';
-->d*3
ans =
   9.0
-->D*3
!--error 144 
Операция для заданных операндов не определена.
-->D+' – это текст'
ans =
   три – это текст

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

def_base=2 //глобальная переменная

function rez=log_b(num, base)
   chk_log=%f //локальная переменная

   rez=log(num)/log(base)
endfunction

Из приведенного примера видно, что в общем случае описание функции выглядит следующим образом:

function [выходные параметры]=имя_функции(входные параметры)
   …
   тело функции
   …
   [выходные параметры]=…
endfunction

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

Линейный процесс вычислений

Создадим стандартную, для начинающих программировать, функцию, которая будет приветствовать всех по имени:

function [outS]=Hello1(Name)
   outS='Привет, '+Name+'!'
endfunction

Вот пример выполнения этой функции:

-->Hello1('незнакомец')
ans =
Привет, Незнакомец!

Теперь укажем в качестве входного параметра не одно значение, а массив значений:

Hello1(['Незнакомец';'Инкогнито'])
ans =
!Привет, Незнакомец!  !
!Привет, Инкогнито!   !

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

В пользовательских скриптах можно использовать любые сторонние функции, входящие в состав самой системы Scilab или ее пакетов-расширений. При этом используются следующие знаки действий: + (сложение), – (вычитание), * (умножение), / (деление), ^ (возведение в степень), ' (транспонирование). Изначально эти операции служат для выполнения матричных действий по правилам матричной алгебры. Например:

-->a=[1 2 3],b=[3 2 1]
a =
  1.  2.  3.
b =
  3.  2.  1.

-->a*b
  !--error 10
Некорректное умножение.

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

-->a*b'
ans =
   10.

-->b' * a
ans =
   3.  6.  9.
   2.  4.  6.
   1.  2.  3.

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

-->a .* b
ans =
   3.  4.  3.

То же самое относится и ко всем остальным действиям кроме операции транспонирования.

Операторы ветвления

Создадим теперь функцию для расчета логарифма числа по произвольному основанию:

function rez=logB(num,base)
   rez = log(num)/log(base)
endfunction

Однако, как известно, логарифм числа a по основанию b имеет смысл только при выполнении условий: a,b > 0, a ≠ 1. Наложим дополнительное условие: входные параметры должны быть скалярными величинами, т. е. не векторами или матрицами. Для того чтобы функция не приводила к выводу сообщения об ошибке или краху системы, входные данные следует проверять на корректность. Сделать это можно при помощи условного оператора, общий вид которого показан ниже:

if <Условие> then <Выражения>
elseif <условие2> then <Выражения2>
...
elseif <условиеN> then <ВыраженияN>
else <Выражения>
end

Запишем новый вид функции с проверкой входных данных на корректность:

function [rez]=logB(num, base)
   //Проверка размера массивов
   if or([length(num)>1, length(base)>1]) then
     error('Ошибка: массив не может быть входным параметром');
   else
     if and([num>0, base>0, base<>1]) then
        rez = log(num)/log(base)
     else
       error('Ошибка: неверные входные данные');
     end
   end
endfunction

В приведенном фрагменте кода используется функция or([массив условий]), возвращающая результат применения логической операции ИЛИ ко всем, перечисленным в квадратных скобках, условиям. Сходна с ней и функция and([список условий]), возвращающая результат применения логической функции И ко всем элементам списка условий. Однако можно использовать и стандартные операции C++, т. е. & – И, | – ИЛИ.

Также нуждается в пояснении функция error(<сообщение>). Эта функция останавливает вычисления и сообщает пользователю о том, что произошла ошибка и указывает имя и строку функции, в которой эта ошибка возникла. Более мягким решением может быть использование предупреждений (warning), которые позволяют вывести сообщение о возникших проблемах, но вычисления при этом не останавливаются. Способ использования прост:

warning('on') //включение режима вывода предупреждений
warning('сообщение') //вывод сообщения
warning('off') //выключение режима вывода предупреждений

Иногда возникает необходимость выполнить те или иные действия в зависимости от значения некоторой переменной. Если тип этой переменной является перечислимым, т. е. переменная может принимать конечное количество значений, то можно воспользоваться оператором множественного выбора. Общий вид этого оператора показан ниже:

select <переменная>
  case <значение 1> then <действия 1>
  case <значение 2> then <действия 2>
  case <значение 3> then <действия 3>
…
  case <значение N> then <действия N>
  else
     <действия по умолчанию>
end

Иными словами, в заголовке оператора множественного выбора указывается переменная перечислимого типа, затем указывается один из вариантов (case) значения переменной и выполняется соответствующее данному значению действие. Следует отметить, что служебное слово then должно находиться на одной строке со словом case.

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

function rez=edIzm(N)
   sN = string(N)
   select length(sN)
     case 1 then rez='Байт'
     case 2 then rez='Байт'
     case 3 then rez='Байт'

     case 4 then rez='Килобайт'
     case 5 then rez='Килобайт'
     case 6 then rez='Килобайт'

     case 7 then rez='Мегабайт'
     case 8 then rez='Мегабайт'
     case 9 then rez='Мегабайт'
   else
        warning('on')
        warning('Введенное больше чем 999 Мегабайт')
        warning('off')
        rez='Много'
   end //select
endfunction

Циклы

Для организации повторяющихся вычислений в Scilab присутствует два стандартных типа циклов: счетный (for) и условный (while). Первый используется в тех случаях, когда заранее известно количество повторений тела цикла, второй – в обратном случае.

Общий вид оператора счетного цикла следующий:

for <счетчик>=<Выражение>
   <тело цикла>
end

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

for <счетчик>=<начальное значение>:<шаг>:<конечное значение>
   <тело цикла>
end

Рассмотрим описанную нами функцию edIzm. Если на вход ей будет подано не одно значение, а несколько, то, вне зависимости от количества элементов, будет выведен единственный и абсолютно неверный результат:

-->edIzm([1,2,4])
ans =
  Байт
-->edIzm([1,23,4])
WARNING: Введенное больше чем 999 Мегабайт
ans =
  Много

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

function [rez]=edIzm(N)
   i=0
   for iN=N
     i=i+1
     sN=string(iN)
     select length(sN)
       case 1 then rez(i)='Байт'
       case 2 then rez(i)='Байт'
       case 3 then rez(i)='Байт'

       case 4 then rez(i)='Килобайт'
       case 5 then rez(i)='Килобайт'
       case 6 then rez(i)='Килобайт'

       case 7 then rez(i)='Мегабайт'
       case 8 then rez(i)='Мегабайт'
       case 9 then rez(i)='Мегабайт'
     else
        warning('on')
        warning(sN+' больше чем 999 Мегабайт')
        warning('off')
        rez(i) ='Много'
     end //select
   end //for
endfunction

Кроме использования оператора цикла for, в коде функции появилась переменная i для нумерации элементов результата и переменная-результат заключена в квадратные скобки, чтобы показать, что в результате получится массив. Возможен и такой вариант начала функции:

function [rez]=edIzm(N)
   NSize=length(N)
   for i=1:NSize
     sN=string(N(i))
     select length(sN)
. . .

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

while <выражение>
   <тело цикла>
end

Пока результат вычисления выражения равен True, цикл выполняется. Чтобы отделить выражение-условие от тела цикла, можно использовать ключевые слова then или do, но они должны находиться на той же строке, что и while. Кроме того, перед end можно вставить блок else, инструкции которого будут выполнены после того, как выражение-условие станет ложью (False).

Итак, вместо строк

sN=string(N(i))
select length(sN)

можно вставить следующее:

iN=0
NTemp=N(i)
while NTemp>0 do
   iN=iN+1
   NTemp=int(NTemp/10)
end
select iN

Окончательную версию функции вы можете загрузить по ссылке в разделе «Загрузка».


Заключение

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


Загрузка

ОписаниеИмяРазмер
Образец кодаedIzm.sci.zip0,5KB

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux
ArticleID=468021
ArticleTitle=SCILAB: Часть 1.Основы программирования в Scilab
publish-date=02122010