맥시마는 반복 수행을 위한 명령어 for 가 있다. 문법은 다음 표에 정리한 바와 같다.


[표 1] for반복문의 문법


생략 가능

(기본값은 1)

다음 중 택일

(반드시 하나는 있어야 함>


for <변수>:<초기값>

step <증감값>

thru <끝값>

do <수행문>



while <조건식>



unless <조건식>


for <변수> in <list>

do <수행문>


먼저 반복문에서 사용할 변수를 초기화 시켜야 한다. 그 다음에 증감값을 step명령 다음에 지정해 준다. 이 증감값은 생략가능하며 이 경우 기본값인 1로 지정된다.


가장 기본적인 사용법의 예는 다음과 같다. (display함수는 단순히 변수의 값을 화면에 출력하는 함수임)

만약 1부터 100까지의 합을 구하고 싶다면 다음과 같다.

증감값을 정하고 싶다면 step 명령어를 다음과 같이 이용한다.

for문을 이용하여 x5+x4+x3+x2+x+1을 생성하면 다음과 같다.

같은 명령을 thru 대신 while을 이용하면 다음과 같다.


또 다른 예로서 리스트 [0, 1, 2, 3, … , 29, 30]를 생성하려면 다음과 같이 하면 된다. 다음 명령을 입력한 후에 그 결과를 확인해 보자. (/*~*/사이의 주석문은 입력할 필요가 없다.)


똑같은 명령을 unless를 이용하여 작성하면 다음과 같다.

이러한 for문을 이용하여 다양한 반복 작업과 많은 요소를 갖는 객체(리스트나 다항식 등)를 생성할 수 있다.





Posted by 살레시오
,

 이전 포스트들에서 설명한 계산식, 변수 대입, 수식 등등이 모두 Maxima의 표현식(expression)이다. 표현식은 그 자체로서 객체를 이루며 또는 정해진 동작을 수행하여 결과 값을 반환해 주기도 한다.



위의 두 예는 동일한 동작을 수행한다. 먼저 x에 2+i 라는 복소수를 대입한 후 그 값을 다시 a변수에 저장한다. 맥시마에서는 표현식을 괄호 ( )로 묶을 수 있으며 단일 표현식에서는 보통 괄호를 생략한다. 따라서 (x:2+%i)는 하나의 표현식이며 그 값은 2+i 라는 값을 가진다. 표현식이 값을 가지는 것이다. 따라서 a변수에 (x:2+%i)의 값인 2+i 가 대입되게 되는 것이다.



표현식이 하나라면 보통 괄호를 생략하지만 여러 개의 표현식을 묶을 때는 괄호를 사용하고 각각의 표현식은 콤마(,)로 구분한다.



위의 예를 보면 첫 번째 줄에서 네 개의 표현식이 괄호로 묶여있다. 이 명령을 내리면 각각의 표현식이 하나씩 실행이 된다. 즉 a변수에 cos2(x)+sin(x)수식이 입력되고 b변수에는 3/sqrt(2)값이, 변수 c에는 3값이 저장된다. 그런데 결과를 보면 (%o1) 3이 나온다. 즉 (...) 안의 표현식은 몇 개가 되었든지 하나의 값을 가지는데 제일 마지막 표현식의 값을 가지며 그 결과가 찍혔다는 것을 알 수 있다. 따라서 다음과 같은 대입이 가능하다.



위의 예를 보면 x:( ... ) 명령어에서 ( ) 안에 두개의 표현식이 있다. 각각은 실행되며 전체 표현식의 값은 마지막 표현식의 값이 되므로 그 값이 변수 x에 저장된다. 따라서 이 예제를 실행시키면 변수 a, b, x 세 개에 각각 값이 저장된다.



  이제 아래 예들의 동작을 구분해 보자.



첫 번째 예는 세 개의 표현식 각각을 독립적으로 실행시킨 것이다. 따라서 그 결과 값도 각각 독립적으로 저장된다. (%o1, %o2, %o3) 두 번째 예는 첫 번째 것과 동작은 똑같지만 결과값은 하나만 생성된다.(%o4) 괄호로 묶여서 전체가 하나의 표현식이고 그 값은 마지막 표현식의 그것이기 때문이다.




Posted by 살레시오
,

 리스트(list)는 맥시마의 기본 자료형 중 하나로서 다양한 표현식을 하나의 집합으로 묶어놓은 것이다. 기본적인 정의는 대괄호 [ ] 를 이용하며 각각의 요소는 콤마(,)로 구분한다. (공백 문자가 아님에 주의하자.)



위의 예는 lsA라는 변수에 리스트 [1, 2, 7, x+y]를 대입한 것이다. 리스트명은 임의의 식별자가 될 수 있다. 만약 x나 y가 어떤 값을 갖는 변수라면 그 값이 대신 들어간다. 그렇지 않다면 그냥 문자 상수로 인식된다.


 리스트 내부의 하나의 요소를 참조할 때에는 리스트명 뒤에 역시 대괄호를 이용하여 인덱스를 지정한다.



리스트의 요소로는 표현식(상수, 변수, 수학 함수 등등)과 리스트 자체도 리스트의 요소가 될 수 있다. 다음 예를 보자.



lsA는 네 개의 요소를 갖는 리스트인데 네 번째 요소는 리스트이다. 따라서 lsA[4]는 리스트 [a,b,c]인 것이다. 리스트 안의 리스트를 인덱싱하기 위해서는 위의 마지막 예와 같이 하면 된다.


 만약 값을 가진 변수를 이용하여 리스트를 정의한 후에 사용된 변수의 값을 바꾸면 어떻게 될까? 변경된 값이 리스트에 영향을 미칠까? 다음 예를 살펴보자.



만약 위와 같이 변수 a, b값을 이용하여 lsA를 정의했다면 정의된 그 시점의 a, b값이 lsA에 사용되는 것이지 변수 a, b 자체를 사용한 것은 아니다. 따라서 이후에 변수 a, b값을 바꾸는 것은 lsA에 아무런 영향을 미치지 않는다는 사실에 유의해야 한다.



그리고 리스트와 스칼라와의 산술 연산은 리스트 내의 모든 요소에 적용된다.



그리고 리스트끼리의 산술연산은 크기가 똑같아야 성립된다.



 리스트를 다루는 여러 함수 중에 많이 사용되는 몇 개만 소개하면 다음과 같다. 먼저 append() 함수는 두개의 리스트를 입력받아서 그 두개를 붙인 리스트를 생성한다.



리스트의 크기를 구하는 함수로서 length() 함수가 있다.



그리고 첫 번째 요소와 마지막 요소를 반환하는 함수는 각각 first(), last() 함수이다.



[표 1] 리스트 관련 함수 정리

기호

의미

append(lsA, lsB)

lsA와 lsB를 붙여서 새로운 리스트 생성

length(lsA)

lsA의 요소의 개수를 반환

first(lsA)

lsA의 첫 번째 요소

last(lsA)

lsA의 마지막 요소




Posted by 살레시오
,

 맥시마를 처음 시작할 때 잘못 쓰기 쉬운 기호 중 하나가 바로 =이다. 보통 다른 프로그래밍 언어에서는 대입 연산자(우항 값을 좌항에 저장하는)로 사용되므로 이것에 익숙해서 여기에서도 당연히 대입 연산자일거라고 생각하기 때문이다. 그런데 맥시마의 대입 연산자는 : , :=, :: , ::= 이 네 가지이다.


맥시마에서 =는

① 등식(eqation)을 만들거나

② ‘같다’를 판변하는 비교 연산자로 사용되는 기호이다.


아래 예를 보자


첫 번째에서 x=2라고 입력하면 변수 x에 2를 입력한 것이 아니다. 그냥 (x=2)라는 등식을 입력한 것이다. 두 번째 예에서는 변수 a에 (x=2)라는 등식 자체를 입력한 것이다. Maxima에서 변수는 상수뿐만 아니라 뒤에 나오겠지만 표현식(expression)도 저장할 수 있다. 아래의 예는 변수 b에 x2-2x+1=0 이라는 방정식 자체를 입력한 것이다.


그리고 ‘=’기호는 조건 검사문 if 문과 뒤에오는 조건식에서 ‘같다’를 판별하는 논리 연산자로 쓰인다.

위에서 if 문 뒤의 (x = %pi) 에서 =는 변수 x값이 π와 같은지를 검사하는 비교 연산자이다. 이 논리식이 참이기 때문에 변수 a에 1값이 대입되었다.

 비교 연산자로 쓰이는 <, >, <=, >=도 비교 연산자 뿐만 아니라 부등식(inequality)를 만드는 데에 사용된다.

위의 첫 번째 입력은 c라는 변수에 2y+1<0 이라는 부등식을 대입한 것이다. 두 번째 입력에서 (d>2)는 if문 뒤의 조건식이다. 이것이 참이므로 e변수에 true값이 저장된다.



Posted by 살레시오
,

 식별자(identifier)라는 것은 이름을 말하는데 이 식별자를 변수나 함수의 이름으로 사용할 수 있다. Maxima에서 식별자를 만드는 데 사용될 수 있는 구성 요소는 아래와 같다.

  • 알파벳 대소문자 (A~Z, a~z)

  • 숫자 (0~9)

  • _ (under bar)

  • %

  • \(백슬래쉬)+(특수문자)

 다른 프로그래밍 언어와 달리 맥시마는 식별자를 만들 때 %나 \#, \$와 같은 특수문자 조합도 사용할 수 있다. 또한 식별자를 만들 때 주의할 점은 숫자로 시작하면 안 된다는 것이며 대소문자를 구별한다는 것이다. 올바른 식별자의 예는 다음과 같다.

mA, aa, AA, lstB, _abc, %number, \@myVar, is_this_\#var

 변수에 어떤 수치 값을 대입하려면 콜론(:)을 사용하며 등호(=)가 아님에 유의해야 한다. 처음에 wxMaxima를 사용하기 시작할 때 가장 하기 쉬운 실수 중에 하나가 바로 변수 값을 대입할 때 콜론(:)대신 등호(=)를 사용하는 것이다.



이제 입력과 출력 앞에 붙은 (%i53), (%o60)와 같은 표시를 주의 깊게 살펴보면 이것들이 식별자라는 것을 알 수 있다. 맥시마에서 새로운 명령을 입력하거나 결과가 산출될 때 그것들은 이 변수에 자동으로 저장이 된다. 따라서 차후에 이 변수를 가지고 과거의 입력이나 출력을 참조할 수 있으며 그것들도 일반 변수와 같이 사용할 수 있다.


 기호 _ 는 바로 직전의 입력, %는 바로 직전의 출력이다. 다음 예를 따라서 해보고 결과를 확인해 보자.



그리고 현재 정의된 모든 변수를 확인하려면 values 라는 명령어를 입력하면 된다. 특정한 변수를 삭제하려면 kill() 함수를, 정의된 모든 변수를 제거하려면 kill(all) 명령을 내리면 된다.



 변수명으로 써서는 안 되는 예약어들은 다음과 같은 것들이 있다. (매뉴얼 pp.87)


if, then, else, elseif, and, or, unless,
integrate, next, from, diff, in, at, limit, sum, for, do,
product, while, thru, step



Posted by 살레시오
,

  클래스나 메소드 혹은 변수를 선언할 때 final 제어자가 붙을 수 있는데 각각 다음과 같은 제한이 생기게 된다.


[표 1] final 제어자의 효과

대상

제한

클래스

다른 클래스에서 상속을 하지 못 한다.

메소드

상속 받은 클래스에서 오버라이딩 하지 못한다.

클래스 변수

선언과 동시에 값을 지정하여야하며 이후 수정이 불가하다.

인스턴스 변수

선언과 동시에 초기화하거나 생성자 내에서 값을 지정할 수 있다. 이후에는 수정이 불가하다.

지역 변수

선언과 동시에 초기화하거나 그 이후에 값을 지정할 수 있다. 이후에는 수정이 불가하다.


예를 들어보자 .


final class CA {

   private static final int ia = 11;
   private final int ib = 22;
   private final int ic;

   public CA() {
       ic = 22;
   }

   public final void func() {
       final int id = 22;
       final int ie;
       System.out.println(id);
       ie = 22;
       //이후에 id는 수정 불가
   }

}

클래스 CA는 파이널 클래스이므로 이것을 상속 받아서 파생클래스를 만들지 못한다. 그리고 func()메소드는 final이므로 상속 받은 클래스에서 오버라이딩하지 못한다. (이 경우는 클래스 자체가 final이므로 별 의미가 없으나 일반 클래스의 final 메소드는 자식 클래스가 오버라이딩하지 못한다.) 많이 사용되는 String 클래스나 Math클래스도 final클래스이므로 이것을 상속받아 새로운 클래스를 파생시키지 못한다.


 그리고 final 정적 변수 ia는 반드시 선언하면서 그 값을 지정해 주어야 하며 다른 곳에서 초기화하지 못한다. 하지만 final 인스턴스 변수(위 예에서 ib와 ic)는 선언부에서 값을 지정하거나 생성자에서 값을 지정해 줄 수도 있으며 이후에 값을 변경하지 못하다는 점은 동일하다. 이 점을 이용해서 final 멤버 변수가 인스턴스마다 서로 다른 값을 가지도록 할 수 있다.


 func()메소드의 id, ie와 같이 메소드 내부의 final 변수는 메소드가 실행되면서 생성되고 메소드가 종료되면 소멸되는 것은 일반 변수와 같지만 한 번 초기화되면 그 이후에는 값을 변경할 수 없다. 지역 변수는 인스턴스 변수와 유사하게 선언하면서 값을 지정할 수도 있고 선언한 후에 별도로 초기화할 수도 있다. 따라서 이 점을 이용하면 메소드가 호출될 때마다 final 지역 변수가 다른 값을 가지도록 할 수 있다.


 만약 어떤 클래스의 인스턴스가 final로 생성되었다고 가정하자.


final ClassA ca = new ClassA();

ca는 클래스의 인스턴스로서 내부적으로는  참조값(주소)을 갖는 변수인데 final로 제한되면 한 번 참조가 생성된  이후에는 새로운 참조값을 가지지 못한다.


final ClassA ca = new ClassA();

….

….

ca = new ClassA(); //에러 발생


따라서 위와 같이 다른 곳에서 ClassA()의 새로운 인스턴스(참조값)를 대입하려고 하면 에러를 발생시킨다.



Posted by 살레시오
,

 비주얼 스튜디오 (Visual Studio, 이하 VS) 는 마이크로소프트(MS) 사의 대표적인 개발툴이다. MS가 2000년대 초반에 .NET framework을 발표하면서 비주얼 베이직, 비쥬얼 C++ 등과 같은 기존의 프로그래밍 언어 외에 C#이라는 새로운 언어를 발표했는데 이것이 .NET의 핵심 언어로서 현재는 버젼이 4.x이다. 이름에서 유추할 수 있듯이 C#은 C/C++에 뿌리를 둔 객체 지향 언어인데 C++과 JAVA의 장점을 계승한 최신의 개념이 들어간 언어이다. 실제 사용해 보면 JAVA보다도 더 편리한 문법과 무엇보다도 비주얼 스튜디오라는 최고의 개발툴 때문에 쾌적하게 코딩을 할 수 있다. JAVA를 시작할 때는 어느 IDE를 사용해야 하는가부터 고민해야 하지만 C#의 경우는 (윈도를 사용한다면) 그럴 필요가 없다.



C언어 정도만 어느 정도 알고서 C#을 공부하면서 감탄을 많이 했던 기억이 난다. 이런 것도 있구나. ('포인터가 없어!'하고 놀랐던 기억도) 무엇보다도 어렵게만 느껴졌던 윈도우 프로그래밍이 폼(form)이라는 객체들을 이용하여 이용하여 직관적으로(드래그 & 드랍) 디자인하고 개별 폼 뒤에 동작하는 코드 조각을 작성하여 전체를 짜맞추어 나가는 과정이 상대적으로 쉽게 느껴졌다. 지금은 또 WPF라는 차세대 개발 방법까지 나와 있지만 내 경우에는  {윈도우 프로그래밍 == 폼 프로그래밍} 으로  인식되어 있다.


그런데 아무리 좋은 언어라도 개발 환경이 고가라면 역시 쉽게 접근하기 어려울 것이다. 하지만 VS Express라는 이름으로 MS사는 개발툴을 무료로 배포하고 있었는데 요즈음에는 아예 .net framework 를 오픈소스로 공개하고 개발툴도 무료로 배포하고 있다. 심지어 이 무료툴로 상용 프로그램을 개발해서 판매를 하더라도 아무런 제약이 없다. 앞으로는 C#으로 맥용 뿐만 아니라 (자바와 같이) 리눅스 앱도 만들 수 있게 될 것이라고 한다. 또한 윈도우에서만 쓸 수 있던 개발 환경이 멀티 플랫폼으로 옮겨가고 있으니 전에는 상상도 못 했던 일이다.




Posted by 살레시오
,

 Scilab함수는 다음과 같이 세 가지 상태가 있다.


➊ 컴파일이 안 된 상태

➋ 컴파일이 된 상태

➌ 프로파일링을 위한 구문이 들어간 상태로 컴파일 된 상태


만약 콘솔에서 함수를 정의한다면 endfunction이 입력되는 순간 컴파일이 된 후 workspace에 함수가 로드된다. 따라서 그 즉시로 호출하여 사용할 수 있다. 파일로 저장된 Scilab함수는 그 자체로는  컴파일이 안된 상태이고 Scilab에서 이 함수를 사용하기 위해서는 반드시 컴파일한 후 workspace에 로드하여야 한다. 프로파일링(profiling)이란 함수를 실행하는데 각각의 줄(line)이 몇 번 실행되었는지 그리고 실행 시간이 얼마나 되는지를 분석하는 것을 말하며 이를 위해서는 추가적인 구문이 필요하다. 함수가 컴파일 된 것인지 아닌지를 확인하려면 type(functoin_name) 함수를 실행해보면 된다. 결과값이 11이면 컴파일이 안된 함수이고 13이면 컴파일된 것이다.


 Scilab에서 함수를 생성하는 방법은 콘솔창에서 직접 입력하는 방법 외에도 다음에 소개하는 deff()함수를 이용하는 방법과 파일(sci파일)에서 로드하는 방법이 이다.

인라인 함수

 함수를 생성하는 방법은 앞 장에서 설명한 바와 같이 콘솔창에서 직접 입력하는 방법 외에 deff()함수를 이용하여 인라인 함수(in-line function)을 생성하는 방법도 있다. 예를 들어서 다음과 같다.



deff() 함수의 첫 번째 인자는 함수 헤더이고 두 번째 인자는 함수의 본체인데 반드시 문자열로 입력해야 한다. 세 번째 인자는 선택 사항인데 함수를 컴파일할 것인지 (‘c’) 아닌지 (‘n’)를 지정하는 문자열이고 생략하면 ‘c’가 기본적으로 선택된다. (‘p’는 프로파일링 기능을 넣은 컴파일 옵션임) 컴파일을 하는 것이 훨씬 더 실행 효율이 높으므로 보통은 기본 옵션으로 생성하면 문제가 없을 것이다.

파일에 저장된 함수

 함수를 파일에서 정의할 수 있으며 Scilab 함수 파일의 확장자는 .sci 으로 정해져 있다.( 다른 확장자도 사용할 수는 있다.) Scilab 의 sci파일에는 여러 개의 함수가 정의될 수 있으며 파일명과 함수명은 크게 상관이 없어서 서로 달라도 된다. 그리고 외부에서 각각의 함수를 개별적으로 호출할 수 있다. (MATALB은 파일명과 첫 함수명이 같아야 하고 첫 번째 함수를 제외하고 다른 함수들은 외부에서 호출할 수는 없다.)


 파일에 저장된 함수를 사용하기 위해서 컴파일/로드 되어야 한다. 이것을 수행하는 함수는 exec()함수이며 이 함수는 스크립트파일을 실행할 때뿐만 아니라 함수를 컴파일하고 로드하는데에도 사용된다. (인라인 함수를 정의하는 deff()함수도 컴파일을 자동으로 수행한다.)


>> exec(‘filename’ [,mode])


만약 함수 파일이 현재 디렉토리에 있다면 파일명만 써도 되는데 그렇지 않다면 파일명을 포함한 전체경로를 첫 번째 인자로 써주어야 한다. 두 번째 인자는 실행모드로서 선택사항이다. 옵션으로 주는 mode값과 해당하는 동작은 다음과 같다.


[표 1] exec()함수의 mode 옵션

mode 값

동작

0

초기값. 세미콜론(;)이 붙지 않은 명령의 결과만 콘솔창에 출력.

-1

아무런 출력도 하지 않음.

1

(마치 직접 콘솔창에 입력하듯이) 한 줄씩 명령과 그 결과를 출력.

2

프롬프트(-->>) 표시 ??? (0번과 거의 유사함)

3

각 명령 줄과 프롬프트 표시. (2번과 거의 유사함)

4

???

7

한 줄씩 실행 후 멈춤. 엔터키 입력으로 실행 (데모를 보일 때 유용함)


exec()함수로 읽어들인 사용자 함수는 workspace에 컴파일되서 올라오므로 바로 사용가능하다.



Posted by 살레시오
,

 어떤 함수가 실행되면 기본 작업공간과 별도로 그 함수만의 작업공간이 생성되어 함수 내부에서 사용되거나 생성된 객체가 저장되게 된다. 그리고 함수의 실행이 끝나면 그 작업공간은 소멸되므로 함수 내에서 초기화된 변수는 함수의 실행 끝나는 시점에서 소멸된다. 함수 내부에서 사용할 수 있는 외부 변수는 다음과 같은 세 가지 경로로 전달된다.


       ❶ 입력 변수

       ❷ global로 선언된 변수

       ❸ 함수 내부에서 초기화되지 않고 호출된 곳의 workspace에서 정의된 변수


여기서 ❶과 ❷는 MATLAB에서도 동일하지만 ❸의 경우는 그렇지 않다. 함수가 호출되면 호출된 곳의 작업공간과는 별도로 그 함수만의 분리된 작업공간이 생성된다. 편의상 호출된 곳의 작업공간을 기본 작업공간(base workspace, BWS)라고 칭하겠다. 만약 함수 내부에서 어떤 변수를 참조하려고 하면 먼저 자신의 작업공간을 먼저 검색해보고 만약 없다면 기본 작업공간에서 찾아본다. 두 곳 모두에서 없다면 에러가 발생될 것이다.


예를 들어서 다음과 같은 함수가 정의되었다고 가정하자.


function y=fA(x)
         w=(w+1)^2 // (a)
         y=x*w // (b)
endfunction


이렇게 정의한 후


>> fA(1)


이라고 호출하면 에러가 발생된다. 왜냐면 (a)의 우변에서 쓰이는 변수 w는 현재의 workspace에서도 없고 기본 작업 공간에서도 초기화되지 않았기 때문이다.


[그림 1] 작업 공간의 개념도


하지만


>> w=1
>> fA(1)


와 같이 변수 w를 먼저 초기화한다면 이제는 4라는 결과값이 표시될 것이다. 한 가지 정말로 혼동하기 쉬운 것은 (a)의 우변의 변수 w는 기본 작업 공간에서 참조하고 좌변의 w는 이 함수 자신의 작업 공간에 새로운 변수로 초기화된다는 것이다. 따라서 (b)의 변수 w는 이렇게 새롭게 생성된 변수가 참조된다. 기본 작업 공간의 변수 w가 아님에 주의해야 한다. 이 변수 w와 기본 작업 공간의 변수 w는 별개의 것이므로 기본 작업 공간에서는 여전히 1값을 유지한다. 이렇게 기본 작업 공간에서 이미 초기화되어 있는 변수를 함수 내부에서 다시 초기화한 경우 “shadowed” 되었다고 하며 이 경우 기본 작업 공간의 변수를 접근할 수는 없게 된다.


[그림 2] 함수의 작업공간과 기본 작업공간은 분리되어 있다.


 만약 기본 작업 공간에서 변수 w를 global로 지정한 후 초기화했다면 어떤 일이 발생할까.


>> global w, w=1
>> fA(1)
>> disp(w)


이 경우에도 변수 w는 여전히 1값을 유지하며 global로 지정했더라도 함수 내부에서 그 값을 변경할 수는 없다. 즉, 앞의 경우와 동일하게 동작한다는 것이다. 그렇다면 함수 내부에서 여전히 기본 작업공간의 변수를 접근할 수 있는데 global로 지정해주어야 하는 필요가 있을까하는 의문이 생긴다. 일견 아무런 차이점이 없어 보이기 때문이다. 함수 내부에서 상위 workspace의 변수값을 변경해주려면 함수의 내부에서도 global로 지정해 주어야 한다.


function y=fB(x)
         global w
         w=(w+1)^2
         y=x*w
endfunction


이제


>> fB(1)
>> disp(w)


를 실행하면 변수 w는 4로 바뀐다. 즉, 상위 workspace의 변수 w가 fB()함수 내부에서 바뀐 것이다. 이와 같이 외부 변수의 값을 바꿀 필요가 있다면 외부에서뿐만 아니라 내부에서도 그 변수를 global로 지정해 주어야 한다.

[그림 3] 글로벌 변수의 동작 개념도


 함수의 결과값을 기본 작업 공간으로 내보내는 데에도 다음과 같은 세 가지 방법이 있다.


       ❶ 출력 변수로 반환하는 방법

       ❷ global로 지정된 변수를 이용하는 방법

       ❸ resume 혹은 return 명령의 인수를 이용하는 방법


❶ 은 함수의 정의부에서 선언한 출력변수를 통해서 기본 작업 공간으로 값을 내보내는 것이고 ❷는 직전 절에서 기술한 바와 같이 함수의 내부에서 global로 지정한 변수를 통해서 기초 작업 공간에서 접근할 수 있는 전역 공간에 변수값을 내보내는 방법이다.


 함수 내부에서 return 이나 resume을 만나면 그 즉시 함수가 종료되는데 보통은 단문으로 사용되어서 함수를 강제로 종료시키는 기능을 수행한다. 하지만 다음과 같은 문법도 가능하다.


[x1, x2, … xn] = return(a1, a2, … an)
[x1, x2, … xn] = resume(a1, a2, … an)

 

이러한 명령들은 함수 내부의 변수들 a1, a2, … , an 을 호출한 곳의 작업 공간에 변수 x1, x2, …, xn 으로 내보내는 기능을 수행한다. 예를 들면 다음과 같다.


function foo(a)
           a=a+1
           b=resume(a) //(*)
           c=52 // (**)
endfunction

 

이 예제에서 (**)줄은 실행되지 않고 (*)줄에서 함수는 종료된다. 또한 기본 작업공간에 변수 b를 생성시켜서 함수 내부의 a변수 값을 넘겨주게 된다. 따라서


>> foo(42)


라고 함수를 실행시키면 workspace에 변수 b가 43값으로 생성된다.


그렇지만 Scilab 매뉴얼(도움말)에 의하면 이러한 용법은 쓸데없이 프로그램의 복잡도만 증가시키므로 출력 변수를 이용하는 것이 바람직하다고 기술되어 있다. 따라서 가급적 ❶번 방법을 주로 사용하고 필요시 ❷번 방밥을 사용하도록 하는 것이 좋다. 또한, resume명령은 pause명령에 의해서 실행이 멈춘 함수를 다시 시작시키는 데에도 사용되는 명령이다.



Posted by 살레시오
,

 Scilab에서 함수의 정의는 다음과 같이 키워드 function 으로 시작하고 endfunction으로 끝난다.


function [y1, y2, … ] = function_name(x1, x2, …)
      …
      ...
endfunction


출력변수(들)은 대괄호 [ ] 로 묶지만 만약 출력 변수가 하나라면 대괄호는 생략이 가능하다. 입력변수는 괄호 ( )로 묶는데 만약 입력 변수가 없다면 정의에서는 괄호를 생략할 수 있다. 하지만 함수를 호출할 때는 입력 변수가 없다고 하더라도 괄호를 생략하지 못 한다. 함수의 몸체는 Scilab의 문장들(statements)로 작성된다.


 간단한 예로 입력변수를 단순하게 세 제곱하여 반환하는 함수는 다음과 같이 입력할 수 있다.


>> function y=pow3(x)
>> y=x^3
>> endfunction


이렇게 입력하면 pow3()라는 함수가 내부적으로 컴파일 된 후 작업 공간에 올라오며 이 후에 호출할 수 있다. 예를 들어서


>> a=pow(4)

 

라고 호출하면 변수 a에 64가 저장될 것이다.


 또 다른 예로서 숫자 x가 소수(prime number)이면 %t를 아니면 %f 를 반환하는 IsPrime()이라는 함수는 다음과 같다.


function y=isPrime(x)
         for n=2:(x-1)
                   if modulo(x,n)==0 then
                             y=%f
                             return
                  end
         end
         y=%t
endfunction


여기서 함수 내부의 return 명령을 만나면 그 즉시 함수의 실행이 종료되고 호출된 곳으로 되돌아가게 된다. 알고리듬은 2와 x-1 사이의 모든 수로 나누어 보고 한 번이라도 그 나머지가 0이라면 %f를 반환하는 아주 간단한 방법을 사용했다.


 Scilab의 함수는 변수처럼 취급된다. 예를 들어서 입력의 3제곱을 반환하는 다음과 같은  함수를 고려하자.


>> function y=foo(x), y=x^3, endfunction


전술한 바와 같이 이렇게 함수를 정의하면 작업 공간에 이 함수가 올라오게 된다. 그 다음 일반적인 변수에 이 함수를 대입할 수 있다.


>> foo2 = foo


이 명령을 보면 좌변의 새로운 변수에 함수명을 대입했다.  이렇게 되면 함수 본체가 복사되어 새로운 변수 foo2에 대입된다. 이 말은 이후에 원래의 함수 foo를 삭제/변형하더라도 foo2 함수에는 영향을 미치지 않는다는 말이다.


이렇게 함수를 변수처럼 취급할 수 있다는 것은 여러가지 이점이 있다. 함수 자체가 다른 함수의 입력 변수, 혹은 출력 변수가 될 수 있으며 구조체나 리스트의 필드가 될 수도 있다.


 만약 정의된 함수를 삭제하고 싶다면 변수를 삭제할 때와 같이 clear 함수를 이용하면 된다.


>> clear foo
>> clear(‘foo’)


이렇게 원래의 함수 foo()가 삭제되더라도 foo2()함수는 여전히 메모리에 남아있게 된다.




Posted by 살레시오
,