심파이에서 대수 기호를 사용하기 위해서는 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 살레시오
,

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


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


loop1: for(...) {

    for (… ) {

        …

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

        …

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

    }

}


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


Posted by 살레시오
,

  C++의 클래스에는 복사 생성자 (copy constructor)라는 것이 있는데 일반 생성자에 비해서 처음 C++을 익힐 때 그 동작에 대해서 간과하기 쉽다. 하지만 그 동작에 대해서 꼼꼼하게 살펴보지 않으면 논리적 오류가 만들어지기 쉽다.


  복사생성자가 호출되는 경우는 다음과 같은 경우가 있다.


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

ClassOne c1, c2; // c1이 만들어지면서 일반 생성자를 호출

ClassOne c3 = c1;// ① 선언과 동시에 대입이 일어날때 복사 생성자를 호출

ClassOne c4(c1); // 위와 동일하게 복사생성자를 호출한다. 즉, ClassOne c4=c1 과 완전히 동일하다.

...

c2 = func(c1); //

...

ClassOne func(ClassOne co) { // ② 함수의 입력 인수 co 는 복사생성자로 생성됨

...

ClassOne cr;

....

return cr; // ③ cr을 넘겨줄 때도 복사 생성자 호출

}

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


사용자가 작성하지 않은 경우 디폴트 복사 생성자가 자동으로 만들어지지만 얕은 복사를 수행한다. 이 경우 멤버 변수에 동적으로 메모리가 할당되는 포인터라도 있다면 문제가 발생한다.


  따라서 사용자가 포인터의 내용까지도 따로 복사해 주는 깊은 복사를 수행하는 복사생성자를 항상 작성해 두는 것이 바람직하다.

[#00064]


Posted by 살레시오
,

  이미 생성된 인스턴스에 다른 인스턴스를 대입할 때 대입 연산자(=)가 이용되며 실제로는 복사가 수행된다. 다음과 같은 간단한 클래스를 고려해 보자.


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

class Led {

    public :

        int pin;

        char *name;

};

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


이 클래스는 복사 생성자도 없고 =연산자도 오버로딩되지 않았다. 이 경우 디폴트=연산자 함수는 얕은 복사를 수해하게 된다. 이제 다음과 같은 두 예를 보자


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

//ex1

Led led1;

led1.pin=13;

Led led2 = led1; // 복사생성자 호출


//ex2

Led led1, led2;

led1.pin=13;

led2 = led1; // 대입 함수 호출

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


<ex1>에서 led2가 생성될 때는 복사생성자가 실행되고  <ex2>에서는 대입 연산 함수가 호출된다.


하지만 멤버변수에 포인터가 있으므로 여기에 문자열이 저장된 경우 얕은 복사는 문제가 일어나게 된다. 


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

Led led1, led2;

led1.name = new char[3];

strcpy(led1.name, "hi");


led2 = led1; // 얕은 복사가 일어나므로 문제를 야기함.

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


심지어 깊은 복사를 수행하는 복사생성자가 정의되어 있어도 대입 연산자는 얕은 복사만을 수행하므로 주의해야 한다. 즉, 대입연산은 자동으로 사용자가 정의한 복사 생성자를 호출하지 않는다. 아래와 같이 깊은 복사를 수행하는 복사 생성자를 작성했다고 하자.


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

class Led {

    public :

        int pin;

        char *namer;

        Led(const Led& src) {

            pin = src.pin;

            name = new char[strlen(src.name)+1];

            strcpy(name, src.name);

        }

};

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


복사 생성자는 생성자이므로 인스턴스가 새로 생성될 때 수행된다. 따라서 name필드에 이전에 메모리를 할당한 적이 없을 것이니 해제할 필요도 없다.


  이렇게 작성한 뒤에서 대입연산은 여전히 얕은 복사를 수행하게 된다. 즉, 복사생성자와 대입연산자는 별개이다.  대입 시에도 깊은 복사를 수행하려면 대입연산자를 오버로딩하여 사용자가 작성해주어야 한다. 한 가지 주의할 점은 대입연산자는 이미 생성된 인스턴스에다 복사해 넣는 것이므로 기존의 문자열을 해제하는 코드가 추가로 필요하다는 것이다. 이것이 대입연산자와 복사생성자의 차이이다.


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

Led& Led::operator= (const Led& src) {

    if (this == &src) return *this; // 자기 대입 방지


    pin = src.pin;

    i(name != NULL) delete[] name; // (주의)

        name = new char[strlen(src.name)+1];

        strcpy(str, src.name);


    return *this;

}

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


이제는 대입연사자를 사용하면 깊은 복사가 일어나게 된다. 만약 복사 생성자와 코드가 많이 중복된다면 중복되는 부분은 private 멤버 함수로 따로 작성하는 것이 더 효율적일 것이다.

[#00063]


Posted by 살레시오
,

_ (1) 정수형 상수 


 표에서 분류한 것과 같이 정수형은 크게 다섯 가지(char, short, int, long, long long)의 자료형이 있으며 바이트 수가 클수록 숫자 데이터의 범위도 커지게 된다. 정수형 변수에는 정수형 상수를 저장할 수 있으며 소수점(혹은 e/E)가 없는 숫자는 정수형 상수이다.


  예를 들어 부호가 있는 int 형 변수 ia 를 숫자 0으로 초기화하려면 다음과 같이 하면 된다.


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

int ia = 0;

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


이후에는 ia라는 int형 변수를 '사용'하여 정수 값을 저장하거나 산술 연산을 수행할 수 있다. 


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

int ia = 0;

ia = 34*567; // *는 곱셈 연산자임

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


  정수형 상수는 기본적으로 int형으로 간주되므로 저장하는데 내부적으로 4 byte(혹은 2 byte)가 소요가 된다. 만약 숫자 상수를 특정한 자료형으로 지정해 주고 싶다면 접미어를 붙여서 그 데이터형을 지정할 수 있는데 U(혹은 u)를 붙이면 unsigned int형이고 l(혹은 L)은 long형, ul(혹은 UL)은 unsigned long형임을 나타낸다.



접미어

자료형

예제

u/U

unsigned int

37u, 123U

l/L

long

12l, 12L

ul/UL

unsigned long

89ul, 89UL


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

unsigned int uia = 0u;

unsigned long ula = 123ul;

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


하지만 보통은 숫자 상수는 대입하려는 변수의 자료형에 자동으로 변환되어 저장되므로 굳이 이렇게 일일이 자료형에 맞추어 접미어를 붙여줄 필요는 없다. 즉,


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

unsigned long ula = 123; 

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


이라고 초기화하여도 123이라는 int형 상수는 자동으로 unsigned long 형으로 변환된 후 변수 ula에 저장된다.


  만약 숫자상수를 short 형이나 unsigned char 형으로 지정하고 싶다면 다음과 같이 해야 한다.


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

short sa = (short)1; 

unsigned char uca = (unsigned char)123;

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


이와 같이 숫자 상수 앞에 (자료형) 을 붙여기 자료형을 강제로 변환하는 것을 형변환(casting)이라고 한다. 하지만 이 경우도 아래와 같이 할 수 있다. 자동으로 형변환이 일어나기 때문이다.


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

short sa = 1; 

unsigned char uca = 123;

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


  한 가지 알아두어야 할 사실은 C/C++언어에서 정수를 표현할 때 0으로 시작되는숫자는 8진수이고, 0x로 시작하는 숫자는 16진수라는 것이다. 예를 들어서 123은 그냥 10진수 123이지만 0123 이라고 입력하면 8진수 123이기 때문에 10진수로 변환하면 83이다. 그리고 0x123은 16진수 123이기 때문에 10진수로 변환하면 291이 된다. 이것을 다음 표에 정리하였다.



숫자 상수

십진수값

비고

123

123

10진수

0123

83

8진수

0x123

291

16진수

0b1110

14

2진수(gcc에서 지원, C++14)


(2) 문자 상수


  C/C++ 언어에서는 정수형 변수에 정수뿐만 아니라 문자를 저장할 수 있으며 특별히 char형과 int형은 문자를 저장하는 목적으로도 자주 사용된다. 문자상수는 작은 따옴표(‘’)를 이용하여 표현되며 예를 들면 ‘a’, ‘+’, ‘0’ 등이 있다. 문자상수는 아스키(ASCII)코드라는 고유의 상수값이 정해져 있는데 다음 표에 몇몇 문자상수와 아스키코드값을 수록하였다.



종류

문자와 ASCII 코드

숫자 (문자)

ASCII 코드

‘0’

48

‘1’

49

‘2’

50

‘9’

57

알파벳 대문자

ASCII 코드

‘A’

65

‘B’

66

‘C’

67

...

‘Z’

90

알파벳 소문자

ASCII 코드

‘a’

97

‘b’

98

‘c’

99

...

‘z’

112

특수문자

ASCII 코드

‘&’

38

‘*’

42

‘+’

43




  char형은 크기가 1바이트이므로 부호 없는 unsigned char 변수인 경우 0부터 255까지의 작은 숫자를 저장할 수 있으며 short형은 2바이트로 부호 없는 숫자의 경우 0부터 65,535까지 저장할 수 있다. 만약 char형 변에 문자상수, 예를 들어서 ‘a’가 저장되면 내부적으로는 97이라는 숫자가 저장된다는 것을 알아야 한다.




bit7

bit6

bit5

bit4

bit3

bit2

bit1

bit0

‘a’ (97)

0

1

1

0

0

0

0

1


  부호가 있는 정수형 데이터는 음수를 2의 보수로 저장하기 때문에 저장범위가 char형은 –128~+127이 되고 short형은 –32,768~+32,767이 된다.


Posted by 살레시오
,

2.3 기본 자료형    [DOC]    [SMTS]

 자료형(data type)이란 정수, 실수, 문자 등과 같이 프로그램에서 사용되는 자료(data)의 종류를 의미한다. 사용하고자 하는 데이터의 종류가 정해지면 그것을 저장할 변수는 그것에 맞추어서 만들어져야 한다.  C 언어는 기본 자료형을 제공하고 사용자들이 필요에 따라 새로운 자료형을 정의할 수 있는 방법을 제공하고 있다.


 표준 C언어에서 제공하는 기본적인 자료형을 다음 표에 정리하였다.


[표 2.1.1] C언어의 기본 자료형

분류

데이터형

byte

범위

비고

정수형

(signed) char

unsigned char

1

-128~ 127

0~255


(signed) short

unsigned short

2

-32,768 ~ 32,767

0 ~ 65,535


(signed) int


unsigned int

4/2

-2,147,483,648 ~ +2,147,483,647

0~4,294,967,295


(signed) long

unsigned long

4

-2,147,483,648 ~  +2,147,483,647

0~4,294,967,295


(signed) long long

unsigned long long

8

-2^63 ~ 2^63-1

0 ~ 2^64-1

C99

C99

실수형

float

4



double

8



long double

12


C99

논리형

bool

boolean

1

1

true, false

true, false

C99(1)

C++

  1. stdbool.h 를 인클루드 한 후에 사용가능하다.


 자료형은 크게 정수형과 실수형, 논리형으로 나뉜다. 정수형은 부호가 있는 signed 형과 부호가 없는 unsigned 형이 별개로 존재하지만 실수형은 그렇지 않다. 또한 각각의 자료형은 정해진 크기가 있으나 PC환경에 따라 그 크기가 변화하는 데이터 형이 있음에 주의해야 한다. 대표적인 것이 int형과 long double형이다.


 논리형은 true, false 두 가지 값만을 가지는 자료형이다. C 언어에서는 C99이후에 stdbool.h 라는 표준 헤더 파일을 인클루드하면 bool형을 사용할 수 있다. (C++은 boolean 자료형이 기본형으로 제공된다.)


 변수(variable)는 자료를 담는 그릇이다. 변수를 사용하려면 반드시 먼저 선언을 해야 하며 문법은 다음과 같다.


자료형 변수명;

예를 들어서 int 형 변수 ia를 사용하려면 다음과 같이 선언을 해야 한다.


int ia;

이렇게 선언을 한 이후에는 이 변수에 값을 대입한다든지 계산을 하는데 사용할 수 있다.


int ia; // 선언
ia = 100; //사용(초기화) 정수값을 대입
ia = 12 * 34; //사용 :곱셈 계산

변수의 '초기화'는 선언된 이후에 맨 처음으로 어떤 값을 대입하는 것을 의미한다. 위와 같이 변수를 선언한 후 초기화를 별도로 할 수도 있고 선언과 동시에 초기화를 수행할 수 도 있다.


long la = 0; // 선언과 동시에 초기화
double da = 1.0; // 선언과 동시에 초기화

이렇게 한 이후에는 자유롭게 변수를 사용할 수 있다.


ex02-01.c

#include <stdio.h>

int main() {
short sa = 11;
int ib = sa + 12; // sa값과 12를 더한다.
int ic = sa * ib; // sa값과 ib값을 곱한다.

printf("%d, %d, %d", sa, ib, ic);
}

실행 결과

11, 23, 253


이 예는 변수 sa, ib, ic를 생성하여 그 값을 printf()함수를 이용하여 화면에 출력하는 것이다. 컴파일한 후 실행해서 결과를 직접 확인해 보자.



Posted by 살레시오
,

생성된 plot  control 에 축을 추가했다면 그림을 도시할 데이터를 등록해야 되는데 이것을LineSeries라고 한다.


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

      plot1.Model.PlotType = PlotType.XY;

      LineSeries s1 = new LineSeries { Title = "Data1",                         StrokeThickness = 1 };

      plot1.Model.Series.Add(s1);

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


이제 실제 데이터를 추가해야 하는데 다음과 같이 한다.


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

       s1.Points.Add(new DataPoint(dTm, dAngle));

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


이런식으로 DataPoint를 추가시키면 이 점들을 선으로 이어주는 그래프를 생성한다. 현재까지 등록된 점들을 이용해서 그래프를 갱신시키려면 RefreshPlot()함수를 호출한다.


    ------------------------------------------------------------------       plot1.Model.RefreshPlot(true);

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


이것이 가장 기본적인 사용법이다.


  만약 실시간으로 데이터가 들어온다면 그 데이터를 DataPoint로 추가시킨 다음 갱신시키면 된다.


Posted by 살레시오
,

오랜만에 다시 oxyplot 라이브러리를 사용하려하니 사용법이 잘 생각나지 않아서 여기에 정리하려고 한다. 일단 Visual Studio 2012 (Express)에서 windows form 을 하나 생성한다.


1. 솔루션탐색기에서 Reference(참조)에서 오른클릭하여 [NuGet 패키지관리] 라는 항목을 선택한다. 이 창에서 oxyplot.WindowsForms 을 검색한 후 설치한다. (전에는 일일이 인터넷으로 다운로드 해서 dll을 추가했었는데 참 편리해졌다.)




그러면 Reference에 다음과 같이 OxyPlot 과 OxyPlot.WindowsForms 가 생성된다.




2. 이제 tool box(툴박스)에 plot control을 추가해야 한다. 그러기 위해서는 다음 단계를 따른다.


  • 도구상자 안에서 오른클릭하여 [항목 선택(choose item..)]을 선택한다.
  • [.NET framework 구성요소] 탭에서 [찾아보기] 버튼을 클릭한다
  • 솔루션 폴더에 보면 packages라는 폴더가 생성되었을 것이다. 여기서 OxyPlotWindowsForms.dll 파일을 찾아서 [열기]버튼을 누른다. 그러면 [.NET framework 구성요소] 탭에 Plot 이라는 항목이 생긴다. [확인]버튼을 누른다.
  • 이제 도구상자에 Plot이라는 control이 생겼다. 이것을 원하는 영역으로 끌어서 놓으면 된다.



3. 다음과 같은 namespace를 추가한다.

     using OxyPlot;

     using OxyPlot.Axes;

그리고 다음 코드는 PlotModel 객체를 생성한 후 여기에 x축과 y축을 추가하고 control에 붙이는 예제이다.


        private void Form1_Load(object sender, EventArgs e)

        {

            PlotModel pm = new PlotModel();

            var lnrAxsX = new LinearAxis(AxisPosition.Bottom, 0, 60, 10, 5);

            lnrAxsX.MajorGridlineStyle = LineStyle.Dash;

            lnrAxsX.MinorGridlineStyle = LineStyle.Dot;

            var lnrAxsY = new LinearAxis(AxisPosition.Left, -300, 300, 60, 10);

            lnrAxsY.MajorGridlineStyle = LineStyle.Dash;

            lnrAxsY.MinorGridlineStyle = LineStyle.Dot;

            pm.Axes.Add(lnrAxsX);

            pm.Axes.Add(lnrAxsY);

            plot1.Model = pm;

        }


이것을 실행하면 다음과 같은 그래프창이 생성된다.




Posted by 살레시오
,