잘 알려져 있다시피 클래스(class)는 객체지향 프로그램에서 핵심적인 역할을 하고 있고 루아에서는 이 기능을 베이스 수준에서 지원하지는 않지만 어느 정도 흉내는 낼 수 있다. 사실 객체지향에서 중요한 특성으로 캡슐화, 상속, 다형성 세 가지 정도가 언급이 되지만 소규모 프로젝트에서는 캡슐화 정도만 어느 정도 구현되어도 코딩과 수정 그리고 디버깅이 상당히 용이해진다고 개인적으로 생각한다. 글을 쓰고 있는 본인도 깊이 있는 지식은 없으므로 여기에서는 초보자들이 간단하게 쓸 수 있는 정도로만 설명하고자 한다.


  

  객체지향이나 클래스의 개념이 생소하다면 일단은 ‘특정한 임무에 관련된 변수들과 그 변수들을 핸들링하는 관련 함수의 집합’ 정도로 이해해도 될 것 같다. 예를 들어서 ‘좌표점과 그것에 관련된 계산’이라는 임무에 대해서


   (1) x좌표

   (2) y좌표

   (3) 한 좌표의 원점으로부터의 거리를 구하는 함수

   (4) 두 점의 거리를 구하는 함수


정도를 구현한다고 하자. 보통 (1),(2)번을 멤버변수라고 하고 (3)(4)번은 멤버함수라고 한다. 이것들을 전체를 하나의 이름으로 묶은 것을 클래스라고 한다.


코로나에서 이것을 외부 모듈로 구현한다면 먼저 다음과 같은 형태를 생각해 볼 수 있다. (외부모듈에 대한 기본적인 것은 이전 포스트를 참조)


┌─────────────────────────────


     local Sqrt = math.sqrt

     local M={}

     

     function M.New(x,y)

          local pt = {x=x or 0, y = y or 0} -- 먼저 멤버변수를 테이블로 새로 생성


          function pt:GetLength() -- 첫 번째 멤버함수를 pt안에서 생성

               return Sqrt(self.x*self.x + self.y*self.y)

          end


          function pt:DistTo(pt2) -- 두 번째 멤버함수를 pt 안에서 생성

               local dx = self.x - pt2.x

               local dy = self.y - pt2.y

               return Sqrt(dx*dx + dy*dy)

          end


          return pt -- 생성된 테이블(인스턴스)를 반환한다.


     end


     return M


└─────────────────────────────


  이 예제에서는 M.New() 함수 안에서 새로운 테이블을 생성한 후 이 안에서 변수와 함수를 다 정의하여 반환하는 식으로 처리했다. 이것을 예를 들어서 ‘point.lua’라고 저장했다면 다른 파일(예를 들어서 main.lua)에서 다음과 같이 불러서 쓸 수 있다.


┌── "main.lua" ───────────────────────────


     local CPoint = require "point" -- 외부모듈을 읽어들인다.


     local pt1 = CPoint.New(10,20) -- 첫 번째 인스턴스 생성

     local pt2 = CPoint.New(30,40) -- 두 번째 인스턴스 생성


     print("length of pt1:".. pt1:GetLength() ) -- 길이 22.36이 찍힘

     print("length of pt2:".. pt2:GetLength() ) -- 길이 50이 찍힘


     print("distance:".. pt1:DistTo(pt2) ) -- 두 점의 거리 28.28이 찍힌다


└─────────────────────────────


이제 CPoint.New()함수를 호출해서 새로운 점좌표를 얼마든지 생성할 수 있으며 보통 이렇게 생성되는 객체를 인스턴스(instance)라고 부른다. 그리고 이렇게 생성된 인스턴스를 통해서 관련 함수를 호출할 수 있다. (print 함수 안의 명령들)


  그런데 이 point1.lua 의 단점은 인스턴스를 생성할 때 마다 그 인스턴스 안에 함수의 본체도 같이 구현된다는 것이다. 예를 들어 100개를 생성하면 함수 본체도 각각 100개가 존재한다. 멤버함수의 개수나 덩치가 커진다면 이것은 실행이나 메모리 관점에서 굉장히 비효율적이다. 그래서 다음과 같이 멤버함수는 외부로 빼는 방식을 생각해 볼 수 있다.


┌─────────────────────────────

          local Sqrt = math.sqrt

          

          local function GetLength(tbl) -- 함수 본체를 외부에 정의

                    return Sqrt(tbl.x*tbl.x + tbl.y*tbl.y)

          end


          local function DistTo(pt1, pt2) -- 함수 본체를 외부에 정의

                    local dx = pt1.x - pt2.x

                    local dy = pt1.y - pt2.y

                    return Sqrt(dx*dx + dy*dy)

          end


          local M={}


          function M.New(x,y)

                    local pt = {x=x or 0, y = y or 0}


                    function pt:GetLength() -- 본체로 리다이렉션시킨다

                              return GetLength(self)

                    end


                    function pt:DistTo(pt2) -- 본체로 리다이렉션시킨다

                              return DistTo(self, pt2)

                    end

                    

                    return pt

          end

          return M

└─────────────────────────────


이제 함수 본체는 (인스턴스 개수와 상관없이) 외부에 하나만 존재하며 인스턴스 안에는 단지 본체로 리다이렉션 시켜주는 조그만 함수가 있을 뿐이다. 앞의 경우보다는 훨씬 효율적이지만 여전히 (작은 크기지만) 함수가 인스턴스 내부에 존재하고 본체로 재호출한다는 점에서 비효율적이다.


  좀 더 루아스럽고 우아하게(...) 개선하려면 이전 포스트에서 설명한 메타테이블의 __index 를 사용하면 된다.


┌─────────────────────────────

          local Sqrt = math.sqrt

          

          local mtIndex = {}


          function mtIndex:GetLength()

                    return Sqrt(self.x*self.x + self.y*self.y)

          end


          function mtIndex:DistTo(pt2)

                    local dx = self.x - pt2.x

                    local dy = self.y - pt2.y

                    return Sqrt(dx*dx + dy*dy)

          end


          local M={}


          function M.New(x,y)

                    local pt = {x=x or 0, y=y or 0} -- 멤버변수를 생성

                   return setmetatable(pt, {__index = mtIndex}) -- 멤버 함수를 메타테이블로 첨부한 후 반환

          end

          

          return M

└─────────────────────────────


이 방법이 코딩의 간결성이나 실행의 효율성에서 앞에서 소개한 방법들 보다 좀 더 앞선다고 할 수 있다.


Posted by 살레시오
,

  루아에서는 테이블에 메타테이블(metatable)이라는 것을 붙일 수 있다. 이 메타테이블에 미리 정해진 필드가 채워져 있다면 이것에 의해서 메타테이블이 붙어 있는 원래 테이블의 동작(특성)을 바꿀 수 있다.

  어떤 테이블에 메타테이블을 붙이는 것은 setmetatable()이라는 함수를 사용한다.



          setmetatable(tA, mtA) -- 테이블 tA에 메타테이블 mtA를 첨가

          tB = setmetatable({}, mtA) -- 빈 테이블에 메타테이블을 mtA를 첨가한 것을 tB에 반환


메타테이블에는 정해진 문자열 키값을 갖는 테이블을 필드로 가져야 되는데 이 미리 정해진 문자열 키값들은 __index, __newindex, __call, __tostring, __add 등등이 있다.

  이 중에서 __index 에 대해서만 간단히 설명하면 다음과 같다. 만약 테이블 tA 의 키값으로 요소들을 접근한다고 할 때(tA.nA, tA[1], tA[“FuncA”] 등등) 그 키값이 tA에 없을 때에는 nil 을 반환할 것이다. 하지만 tA에 메타테이블이 연결되어 있다면 그 연결된 메타테이블의 __index 테이블에 등록된 필드를 추가로 검사한다. 예를 들어서



          local tA={x=10}

          print(tA.y) -- "y"라는 키값이 없으므로 nil 이 찍힌다.

          local mt = { __index = { y = 20 } }

          setmetatable(tA, mt)
          print( tA.y ) -- 메타테이블에 있는 20이 찍힌다.



메타테이블의 __index 내부에는 함수도 물론 정의할 수 있다.



          local mtIndex = {}

          function mtIndex:sum()
                    return self.x + self.y — self는 메타테이블이 붙은 원래 테이블

          end

          local tA={x=10, y=20}
          setmetatable( tA, { __index=mtIndex } )

          print( tA:sum() ) -- 30이 찍힌다


          local tB = setmetatable( {x=30, y=40}, {__index = mtIndex} )
          print( tB:sum() ) -- 70이 찍힌다



위의 예제는 간단하지만 이것을 이해했다면 루아(코로나)에서 객체지향을 간단하게나마 구현하는데 응용할 수 있다.


Posted by 살레시오
,

  루아는 C언어와 다르게 true, false 값만을 가지는 부울형이 있다. C언어에서는 내부적으로 0값을 거짓(false)으로 취급하지만


     ‘루아는 nil 과 false 만을 거짓으로 간주한다


는 점을 유의해야 한다. 정수 0도 루아에서는 진리값이 true이다. C언어에 익숙했다면 참 헷갈리기 쉬운 부분이다.


이 사실을 염두에 두고 루아의 논리연산자를 살펴보자. 루아의 논리연산자는 and, or, not 세 가지가 있다. 각각의 동작을 정리하면 다음과 같다.


  • not A - A가 거짓이면 (즉 nil 혹은 false이면) true, 아니면 false 반환
  • A and B — A가 거짓이면 (즉 nil 혹은 false이면) A를 바로 반환, A가 참이면 B를 반환
  • A or B — A가 참이면 (즉 nil도 false도 아니면) A를 바로 반환, A가 거짓이면 B를 반환


A and B 연산에서 A가 거짓이면 B는 아예 보지도 않고(계산도 안하고) 바로 A를 반환하며, 반대로 A or B 연산에서는 A가 참이면 B는 아예 보지도 않고 바로 A를 반환한다. 이것을 조금만 생각해 보면 not은 항상 부울값(true, false)을 반환하는데 반해서 and와 or는 그 반환값이 부울값이 아닐 수도 있다는 것을 알 수 있다. 몇 가지 예를 들어보면


local a = 1 and 0 — a에는 0값이 이 저장됨

local b = nil and 1 — b에는 nil 이 저장됨

local c = 1 or 0 — c에는 1값이 이 저장됨

local d = nil or 0 — d에는 0 이 저장됨


이것을 응용하면 예를 들어서 함수의 입력인자가 nil인지 아닌지를 따져서 내부변수를 다르게 초기화할 때 용이하다.


---------------------------------------------------

local function Func( xR, yR )

     local x, y

     if xR==nil then

          x = 0

     else

          x = xR

     end

     if yR==nil then

          y = 0

     else

          y = yR

     end

---------------------------------------------------


위와 같은 긴 코드를 다음과 같이 간단하게 한 줄로 줄일 수 있다.


---------------------------------------------------

local function Func( xR, yR )

     local x, y = xR or 0, yR or 0

---------------------------------------------------


또 다른 예로 어떤 테이블이 nil인지 아닌지를 따져서 그 내부 요소를 참조하고자 할 때도 유용하다. 예를 들면


---------------------------------------------------

local x = tLoc.x

---------------------------------------------------


의 경우 만약 tLoc 테이블 자체가 nil 인 경우에는 변수 x에 nil 이 저장되는 것으로 오해하기 쉬운데 실제로는 런타임 에러가 발생하고 프로그램이 멈추게 된다. 개인적으로 코로나로 코딩하면서 초기에 많이 접한 것이 이런 종류의 런타임 에러이다. (반면 tLoc 테이블 자체는 nil이 아닌데 x요소가 없는 경우에는 x에 nil 이 저장되고 런타임 에러는 발생하지 않는다.)

이러한 런타임 에러를 없애고 테이블 자체가 nil일 경우를 처리하려면 예를 들어서 다음과 같이 해야 할 것이다.


---------------------------------------------------

local x

if tLoc == nil then

     x = nil

else

     x = tLoc.x

end

---------------------------------------------------


위와 같은 코드를 and연산자를 이용하면 다음과 같이 한 줄로 바꿀 수 있다.


---------------------------------------------------

     local x = tLoc and tLoc.x

---------------------------------------------------


이와 같이 and 와 or 연산의 특성을 이용하면 프로그램을 간결하게 작성할 수 있다.


Posted by 살레시오
,

루아의 변수는 다음과 같이 8가지 데이터타입을 갖는다.


nil

부울값

숫자

문자열

테이블

함수

----------

코루틴

유저데이터


이 중에서 코루틴과 유저데이터는 코로나SDK와 별로 관련이 없으므로 제외하고 나머지 여섯 개 중 참조를 갖는 것은 함수와 테이블이다. 문자열은 참조가 아니라는 것에 유의해야 한다. 참조란 실제 데이터가 저장된 곳을 가리키는 주소이다. (사실 참조도 주소'값'이므로 루아는 다 값이라고 주장하기도 하지만 혼동의 여지가 있으므로 여기서는 참조와 값을 구분하도록 하겠다.)

따라서 만약 어떤 테이블을 함수의 입력파라메터로 넘길 때 참조가 넘어가므로 그것을 받아서 조작하면 원래의 테이블값도 바뀌게 된다.


┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓

    local function Func1(a, tA)

        a = 20

        tA.x = 20

    end


    local function Func2(tA)

        tA = {x=30}

    end


    local x, tX = 10 , {x=10}

    Func1(x, tX) -- x는 값이, tX는 참조가 넘어간다.

    print(x, tX.x) -- 10, 20 이 찍힌다.

    Func2(tX)

    print(tX.x) --20이 찍힌다.

┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛


위의 예에서 Func1()을 호출할 때 로컬 변수 x는 값이 넘어가고 테이블 tX는 참조가 넘어가므로 함수 호출 후 테이블의 필드만 값이 변경되었다. 반면에 Func2()내에서는 tA가 tX의 참조를 받기는 하지만 새로운 테이블의 참조로 초기화되었다. 따라서 이경우 tA는 넘어온 tX와는 전혀 별개의 것이 되어서 tX에는 아무런 영향을 끼치지 못한다. 그래서 맨 마지막 print()에서 20이 찍히는 것이다.


이와 마찬가지로 함수의 리턴값이 테이블이나 함수일 경우도 참조를 반환한다. 다음 예는 처음에는 조금 이해하기 힘들 수 있으나 한 번 살펴보도록 하겠다.


┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓

    local function Func1(xR)

        local x = xR or 0 -- 내부변수 x를 넘어온 값으로 초기화

        local y = 0

        local Func = function() print("x :"..x);end -- 여기서 x가 사용되었다.

        return y, Func -- y는 '값'을, Func는 '참조'를 반환

    end


    local y1, Func2 = Func1(10)

    local y2, Func3 = Func1(20)

    Func3() -- 20 이 찍힌다.

    Func2() -- 10 이 찍힌다.

┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛


함수 Func1()은 그 안에서 내부변수 y의 '값'과 내부변수 Func의 '참조'를 반환한다. 기본적으로 어떤 함수의 지역변수는 함수가 종료되면 사라진다는 것은 알고 있을 것이다. 변수 y는 함수가 종료되면 더 이상 참조되는 곳이 없으므로 GC의 타겟이 되어 사라질 것이다. 하지만 내부함수 Func는 그 참조가 호출된 곳의 Func2 변수를 통해서 계속 사용되므로 사라지지 않고 살아남게 된다. 그럼 내부변수 x는 어떨까? x변수는 Func안의 print()문에서 참조를 하고 있으므로 Func가 살아있는 한 x도 계속 살아있게 된다.


또 한가지 주의할 것은 Func2 와 Func3에서 참조하는 변수 x는 서로 별개의 것이라는 점이다. 따라서 처음 Func3()호출에는 20이 찍히고 맨 마지막 Func2() 함수를 호출하면 10이 찍힌다. 서로 '다른' 변수 x를 참조하고 있기 때문이다.


이것을 이해했다면 클래스를 구현할 때 외부에서는 접근할 수 없고 내부에서만 사용할 수 있는 private 변수/함수 를 구현하는데 응용할 수 있다.

Posted by 살레시오
,


  자바 식별자는 길이에 제한이 없으며 '_' 뿐만 아니라 '$' 문자도 사용할 수 있다는 점이 특이하다.


  자바에서는 반복문 앞에 라벨을 붙여서 그 라벨을 break, continue 문 뒤에 붙여 중첩된 반복문을 한꺼번에 벗어날 수 있다.


loop1: for(...) {

    for (… ) {

        …

        break loop1; //바깥쪽 루프를 벗어남.

        …

        continue loop1: //바깥쪽 루프의 그 다음 반복을 바로 수행.

    }

}


반복문의 이름이 지정되지 않은 break, continue 문은 그것을 포함하는 가장 안쪽의 반복문을 제어하지만 이처럼 라벨링을 이용하면 그 바깥쪽의 반복문을 제어할 수 있다.


  그리고 JAVA5 이상부터는 C#의 foreach 나 파이썬의 for문과 같은 기능을 사용할 수 있다. 문법은 다음과 같다.


for(자료형 변수명: 집합) {

}


여기서 집합은 배열,콜렉션,enum 등이다. 이렇게 하면 예를 들어 배열의 각 요소가 변수명에 대입되어 차례로 반복문을 수행하게 된다.

enum Week { 월, 화, 수, 목, 금, 토, 일 }

public static void main(String args []) {
    // enum 타입을 foreach 로 출력

    for (Week day : Week.values()) { // Week.values()에는 Week 의 값들이 교대로 들어갑니다.
    System.out.println(day + "요일");
}

// 정수 배열을 foreach 로 출력
int[] num = { 14, 54, 52, 26, 62, 55 };
for (int i : num)
    System.out.println(i);

// 문자열 배열을 foreach 로 출력
String names[] = { "수성", "금성", "지구", "화성" };
for (String s : names)
    System.out.println(s);
}


Posted by 살레시오
,

 심파이(sympy)에서 미리 정의된 상수들은 다음과 같은 것들이 있다.


[표 1] 심파이의 기정의된 상수들

sympy 상수
의미
I, 1j, 1J
허수. (예를 들어 3+4j 는 3+4*I 와 같이 입력해야 한다.)
pi
원주율(3.141592..)
E
자연상수(2.718281..)
nan
not a number
oo
(positive) infinity
zoo
complex infinity


허수로 I를 이용할 때는 허수부와 I 사이에 반드시 곱기호를 넣어 주어야 한다.


>>> abs(1+2*I)
sqrt(5)


무리수의 근사값을 알고 싶다면 evalf() 멤버함수를 이용하면 된다.


>>> pi.evalf()
3.14159265358979

>>> E.evalf()
2.71828182845905




Posted by 살레시오
,

 심파이에서 대수 기호를 사용하기 위해서는 symbols() 함수를 사용하면 된다.


>>> a = symbols(‘a’)


여기서 대입 연산자(=) 왼쪽의 변수명과 symbols()로 생성되어 표기되는 대수기호는 같은 것으로 하는 것이 좋다. (즉 a=symbols(‘b’) 는 바람직하지 않다.)


다음 예와 같이 여러 대수 기호들을 한꺼번에 생성할 수도 있다.


>>> x = symbols(‘x:5’) # x0, x1, x2, x3, x4 를 튜플로 생성
>>> y = symbols(‘y1:11’) # y1, y1, ..., y10 을 튜플로 생성


대수 기호의 종류를 지정할 수도 있다.


>>> a = symbols(‘a’, integer = True) #정수
>>> b = symbols(‘b’, real = True) #실수
>>> c = symbols(‘c’, complex = True) #복소수
>>> d = symbols(‘d’, positive = True) #양수로 정의
>>> f, g, h = symbols(‘f g h’, cls=Function) #함수 기호로 정의


 아래 심파이 라이브 웹페이지를 처음 접속하면 x, y, z, t 는 대수 기호로, k, m, n은 정수 대수 기호로, f, g, h는 함수 기호로 사용할 수 있도록 미리 symbols()함수로 생성된다는 것을 알 수 있다.


[그림 1] live,sympy.org 접속시 실행되는 명령들


따라서 기정의된 대수기호를 이용하여 바로 명령을 입력할 수 있다.



Posted by 살레시오
,

 심파이에서는 변수를 대수 기호로 사용하려면 반드시 symbols()함수를 써서 지정해 주어야 한다. 만약 x, y, z를 대수 기호로 사용하겠다면 다음과 같이 하면 된다.


>>> x = symbols(‘x’)
>>> y,z=symbols(‘y z’)


아래부터는 live.sympy.org 에서 직접 확인해 볼 수 있다.


[그림 1] live.sympy.org 접속화면

대수 방정식

 이것을 이용하여 수식 x+2y 를 입력해 보자.


>>> expr = x+2*y
x+2*y


여기서 x, y는 마치 파이썬의 변수처럼 사용되었지만 내부적으로는 대수기호로 지정되어 있는 상태이다.


>>> expr+1
x + 2*y + 1

>>> x*expr
x*(x + 2*y)

>>> expr2 = expand(x*expr)
x**2 + 2*x*y

>>> factor(expr2)
x*(x + 2*y)


이와 같이 expand() 함수를 이용하여 수식을 전개할 수 있고 factor()함수로 인수분해를 할 수 있다.


 분수식을 통분하거나 분리할때는 together() 함수와 apart()함수를 이용한다.


>>> a, b, c, d = symbols('a b c d')

>>> together(a/b + c/d)
(a*d + b*c)/(b*d)

>>> apart( (a**2+a+4)/(a+2) )
a - 1 + 6/(a + 2)


 대수 방정식을 풀기 위해서는 solve()함수를 이용하면 된다.


>>> solve(x**2-2,x)
[-sqrt(2), sqrt(2)]


미분

 이제 함수 sin(x)ex 를 미분해 보자. 미분은 diff() 함수를 이용하면 된다.


>>> diff(exp(x)*sin(x),x)
exp(x)*sin(x) + exp(x)*cos(x)


적분

 함수 exsin(x) + excos(x)의 부정적분을 계산해 보자. integrate()함수를 이용하면 된다.


>>> integrate(exp(x)*sin(x)+exp(x)*cos(x),x)
exp(x)*sin(x)


정적분을 구하려면 integrate()함수의 두 번째 인수에 범위를 지정해 주면 된다. sympy에서 무한대는 oo (소문자 o 두 개) 기호를 사용한다.


>>> integrate(sin(x**2),(x,-oo, oo))
sqrt(2)*sqrt(pi)/2


극한

 극한값을 구하려면 limit()함수를 이용하면 된다.


>>> limit(sin(x)/x,x,0)
1


미분방정식

 심파이를 이용하면 미분 방정식도 풀 수 있다.


>>> t=symbols('t')
>>> y=Function('y')
>>> dsolve( Eq(y(t).diff(t,t)-y(t), exp(t)), y(t))
y(t) == C2*exp(-t) + (C1 + t/2)*exp(t)


선형대수

 선형대수도 가능하다. 예를 들어 행렬


[ 1 2 ]

[ 3 4 ]


의 고유값을 구하려면 다음과 같이 하면 된다.


>>> A = Matrix([[1,2],[2,2]])
>>> A.eigenvals()
{-sqrt(17)/2 + 3/2: 1, 3/2 + sqrt(17)/2: 1}


 이와 같이 sympy를 이용하면 다양한 대수식을 표현하거나 방정식을 풀 수 있다.




Posted by 살레시오
,

 컴퓨터는 원래 수치 계산(numerical calcuation)을 빠르고 정확하게 수행할 목적으로 개발되었다. 수치 계산과는 다르게 기호식 계산(symbolic calculation)은 대수 기호가 들어간 수식을 다루는 것으로서 유한수로 정확히 표현되지 못하는 무리수를 기호로 표현하거나 또는 대수 기호가 포함된 방정식 등을 다루는 것이다. 사람이 이러한 개념을 사용하기는 어렵지 않으나 컴퓨터가 이러한 일을 하는 것은 전통적인 수치 계산 알고리듬보다 훨씬 더 어려운 일이다.


 예를 들어서 sin(x)/x의 x에 대한 미분을 구하려고 한다면 다음과 같이 간단하게 구할 수 있다.(다음은 live.sympy.org에서 수행한 것임)


 다른 예로 exp(x)*sin(x)의 정적분을 구하려고 한다면 이것 역시 심파이로 간단하게 수행할 수 있다. (손계산을 하려면 부분적분 공식을 적용해야 한다.) 다음은 winpython 의 ipython쉘에서 수행한 결과이다.



 이것은 기호식 계산의 한 가지 예일 뿐이고 실제로는 이것보다 훨씬 더 복잡한 수식과 문제들을 다룰 수 있다.


 이러한 시스템은 보통 CAS (Computer Algebra System)으로 불리며 심파이도 CAS 중 하나이다. CAS의 잘 알려진 다른 예로 Mathematica (상용 프로그램), Maxima, Sage  등이 있다. 심파이의 가장 큰 장점은 무료로 제한 없이 사용할 수 있는 오픈소스 모듈이라는 점이며 순수한 파이썬으로 만들어져 파이썬에 익숙하다면 배우는데 많은 시간이 걸리지 않는다.


 심파이(sympy)는 기호식 계산을 수행하기 위한 파이썬 모듈이며 현재(2015년 5월) 버전은 0.7.6 으로 활발하게 개발이 진행되고 있으며 많은 사용자들이 있다,




Posted by 살레시오
,

  제목이 좀 거창하긴 한데 파이썬은 컴퓨팅 환경의 첫 번째로 영향력 있는 언어이기도 하지만 마이컴 보드에서도 편리하게 하드웨어를 제어할 수 있는 언어로 점차 그 영역을 넓혀가고 있다. 하드웨어 제어는 닥치고 C/C++ ... 이라는 공식 비슷한 것이 이제는 변하고 있다.


  그 선두에 있는 기기가 바로 잘 알려진 라즈베리파이(raspberry pi)이다. 이 35불 짜리 원보드 리눅스 컴퓨터는 GPIO핀이 내장되어 있고 이것을 제어할 수 있는 파이썬 모듈이 잘 개발되어 있다. C/C++ 몰라도 LED를 깜박이거나 모터를 돌리는 등의 일을 파이썬 코드로 얼마든지 수행할 수 있다.



최근에 출시된 라즈베리 파이 2



본격적으로 파이썬만으로 제어가능한 마이크로 콘트롤러 보드인 micropython 이라는 보드도 있다. 이 보드는 SD카드에 저장된 파이썬 프로그램을 읽어들여서 수행한다. 파이썬의 간결한 문법을 이용하여 다양한 하드웨어를 제어할 수 있다.




좀 더 최근에는 영국의 BBC (알다시피 방송국이다..)에서 어린 학생들의 코딩 능력을 길러주기 위해서 개발하여 보급하고 있는 MicroBit 이라는 보드도 있다.




왜 방송국에서 이런 일을 하는지 알다가도 모르겠지만 어쨋든 이 보드가 지원하는 세 가지 주력 언어 중 하나도 파이썬이다. (이렇게 예를 들고 보니 우연히도 세 가지 보드 모두 영국에서 만들어진 것들이다.)


Posted by 살레시오
,