C# VS DELPHI

Posted by NUL PROG. : 2014. 12. 4. 23:00
C# 이 등장한지 (등장한걸 알게 된지) 대략 15년 쯤 된 것 같다.

처음엔 무시했고 시간이 지나도 굳이 저걸 쓸필요는 없겠다 싶었는데...

DELPHI의 발전이 너무 더디고 상대적으로 C#의 발전은 순조로와서 윈도우즈 운영체제하의 어플리케이션을 개발하는 입장에서 C#을 무시할 수 없게 됐다.

무엇보다 팀원에게 점점 시장에서 밀리기만 하는... 엠바케데로의 툴만을 배우라고 하기는 꺼림칙하다.




이런 연유로

그간은 전혀 관심도 없었던 C#에 대해 최근 틈나는대로 파고들면서 DELPHI 와 비교해 볼까 한다....

아래의 내용은 아직 관련 지식이 부족하고 선입견이 있을수 있기에

또 금새 생각이 바뀔수도 있을 것이다.

다분히 주관적인 글이다.




C# 의 장점

1. user control 적용의 편리함...

   델파이와 달리 프로젝트별로 user control 관리한다.
   장기간 유지 보수할 경우에는 편리한 델파이 컴포넌트가 악몽이 될수도 있는데,
   이런 고민이 없어졌다... 이건 2번과도 이어진다.

2. partial class

   라이브러리를 개발하고 유지보수하면서 늘 겪는 문제다.
   비슷하지만 다른 S/W 를 줄창 개발하다보니 결국 프로젝트마다 라이브러리 버전이 달라져 버린다.
   다품종 소량 생산의 S/W 를 만들다 보니. 하위 호환까지 따져 가며 작성하기엔 너무 고단한 일인데...
   partial class 와 1번을 조합하면 확기적으로 코드관리가 수월해질 거다

 3. 안정적인 IDE

  IDE의 창시자는  터보 파스칼 / 터보 C의 Borland 이지만,
  현재의 IDE의 수준은 MS 툴에 비교가 안되게 허접하다.
  그래도 오브젝트 파스칼 자체가 가독성이 좋고 구조가 간단해서 그나마 다행이랄까

4. 더 있을건데 아직은 C#을 잘몰라서... 여기까지... 



C#의 단점

1. Save as project 가 없다.

   그게 굳이 필요한가? 라고 생각할 분들이 많겠지만,
   유사하지만 다른.... 다품종 소량 생산 하는 개발자 입장에선 귀찮음을 덜어주는 매우 고마운 기능이다.
 
2. 코드 공개

   델파이의 핵심 프레임워크인 VCL은 내부 클래스의 코드를 볼수 있다.
   입문서 하나 딸랑 읽고 델파이를 익혀서 VCL의 파생 클래스를 자유자재로 만들어 사용할수 있었던 것도
   VCL 을 들여다 볼수 있으니까 가능한 것이었고,
   디자인 패턴이 뭔지도 모를때부터 자연스럽게 클래스의 설계 방식을 익힐수 있었다.

3. 선언과 구현의 분리
 
   구세대 프로그래머라서 그런지 헤더가 없는게 영 보기 어렵다.
   헤더 파일 자체가 없어도 델파이 처럼 선언과 구현이 분리 되어야 눈에 잘 들어온다.
   특히 IDE 없이 일반 텍스트 편집기로 코드를 보는 일이 많고 작성하는 일도 가끔은 있기 때문에
   블럭이 접히는 에디터를 따로 구해야할 판이다.

4. 배열 형태의 property

  델파이는 Grid.Values[r,c], Grid.Colors[r,c] 이런 식으로 다양한 프로퍼티가 가능하다.
  최근엔 namespace 까지 해서... 이름이 길어지는게 요즘 추세라지만... 짧게 할수 있는 건 짧은게 좋다
  위의 예를 C#으로 하자면 Grid.Rows[r].Columns[c].Color ,Grid.Rows[r].Columns[c].Value 너무 길다.
  구현도 더 복잡해진다.



별 차이 없는 것 들

1. garbage collection

   개인적으론 garbage collection 보단 스마트 포인터를 쓰는 게 낫다고 본다
   일의 특성상 반드시 메모리 관리를 직접 해주어야만 하는 경우가 은근히 많은데...
   unsafe 로 예외적으로 관리하기 보단 smart pointer 를 쓰는게 개인적으로 더 낫다고 본다.
   근데 smart pointer 는 델파이 기본 제공이 아니다. 만들어써야한다. 그래서 별차이 없음으로 분류

2. 컨트롤 사용이 복잡함

   MS 의 컨트롤은 모양이 더 이쁘다. 하지만 클래스 구조나 사용상의 컨셉을 보자면 VCL 이 더 좋다고 본다.
   다만 VCL은 20년이 지나도록 그닥 발전이 없다
   발전하긴 했는데... 20년이란 세월에 비교하자면... 좋은 점수를 주긴 힘들다.
   그래서 별차이 없음으로 분류

3. H/W API 지원

   점점 델파이는 밀려나가고 있다. 윈도우즈하에선 벤더들이 DOT NET을 밀고 나갈 작정으로 보인다.
   그래도 C++ 혹은 C API는 필수로 지원하니까 C++과 함께 사용하면 된다.
   C#도 어차피 C++과 같이 써야만 하는 일이 생긴다.
   물론 C#은 VC++과 IDE 를 함께 쓰니 더 편하긴 하겠지만, 
   어차피 C++은 모듈로 작성하기 때문에 큰 문제는 되지 않는다.



 
  

GR32 (TBitmap32) 에서 Blurred Text 그리기

Posted by NUL PROG. : 2010. 11. 23. 18:45
늘 그렇듯 간단 팁입니다.


Blurred Text 란건 아래와 같은 걸 의미합니다. (영어가 맞는지는 모르겠지만 제가 쓰는 함수 이름임...;)



흰색 글자지만 배경에 흐릿하게 붉은빛이 돕니다.



이런 텍스트는 아래의 순서대로 출력합니다.

1. 붉은색 텍스트를 출력
2. Blur 처리
3. 흰색으로 다시 덮어 씀.

간단하죠


Blur 효과를 주기 위해 GR32_Lines 에 포함된 TStackBlur를 사용했습니다.
procedure JnDrawBlurredText( BMP: TBitmap32;
                        const Str: String;
                        const X, Y: Integer;
                        const ABlurrColor, ATextColor: TColor32;
                        const ARadius: Integer = 1;
                        const ARepeat: Integer = 3);
var
  i: Integer;
  BmpTxt: TBitmap32;
  szTxt: TSize;
begin
  BmpTxt := TBitmap32.Create;
  try
    BmpTxt.Font.Assign(BMP.Font);

    szTxt := BmpTxt.TextExtent(Str);
    BmpTxt.SetSize(szTxt.cx + ARadius * 2, szTxt.cy + ARadius * 2);

    BmpTxt.Clear(ABlurrColor and $00FFFFFF);
    BmpTxt.RenderText(ARadius, ARadius, Str, 0, ABlurrColor);

    with TStackBlur.Create(ARadius) do
    try
      for i := 1 to ARepeat do
        Execute(BmpTxt);
    finally
      Free;
    end;

    BmpTxt.RenderText(X, Y, Str, 0, ATextColor);
    BmpTxt.DrawMode := dmBlend;

    BmpTxt.DrawTo(BMP, X - ARadius, Y - ARadius);
  finally
    BmpTxt.Free;
  end;
end;

  

GR32 (TBitmap32) 에서 Flood Fill

Posted by NUL PROG. : 2010. 11. 17. 18:29
2010/11/15 - [PROG.] - GR32 (TBitmap32) 에서 Gradient Fill 에 이어서 Flood Fill 을 구현해 봅니다.
마찬가지로 GDI 함수로는 알파값이 누락 되기 때문에... 


1) 4 방향 FloodFill
procedure JnFloodFill1(BMP: TBitmap32; const X, Y: Integer; const AColor: TColor32);
var
  C: TColor32;
begin
  C := BMP.Pixel[X,Y];

  BMP.Pixel[X,Y] := AColor;

  if BMP.Pixel[X - 1, Y] = C then JnFloodFill1(BMP, X - 1, Y, AColor);
  if BMP.Pixel[X + 1, Y] = C then JnFloodFill1(BMP, X + 1, Y, AColor);
  if BMP.Pixel[X, Y - 1] = C then JnFloodFill1(BMP, X, Y - 1, AColor);
  if BMP.Pixel[X, Y + 1] = C then JnFloodFill1(BMP, X, Y + 1, AColor);
end;
가장 간단하게 생각할 수 있는 코드 입니다. 4방향을 탐색하면서 재귀호출을 합니다.

문제는 Stack Overflow 가 발생한다는 점.

델파이는 Tail Recursive Optimization 을 지원하지 않기 때문에 재귀호출로는 암만 고민을 하고 수정해봐야 헛일입니다. 지원한다해도 위의 코드 그대로는 안되겠죠.
델파이 프리즘은 TAILCALL 컴파일 지시자를 지원합니다.  다만 현재로서는 닷넷 기반의 델파이 프리즘은 그닥 내키지 않기 때문에 다른 방법을 써야 합니다. 이것 때문에 VC, GCC로 개발한다는것도 배보다 배꼽이 더 큰 격이죠.



2) 4 방향 FloodFill - Stack 사용
procedure JnFloodFill2(BMP: TBitmap32; const X, Y: Integer; const AColor: TColor32);
var
  C: TColor32;
  Stack: TStack;

    procedure Sub_Push(const APxPos: Integer);
    begin
      BMP.Bits[APxPos] := AColor;
      Stack.Push(Pointer(APxPos));
    end;

    procedure Sub_Check;
    var
      nPos, N: Integer;
    begin
      nPos := DWORD(Stack.Pop);

      N := nPos - 1;
      if BMP.Bits[N] = C then Sub_Push(N);

      N := nPos + 1;
      if BMP.Bits[N] = C then Sub_Push(N);
      
      N := nPos - BMP.Width;
      if BMP.Bits[N] = C then Sub_Push(N);

      N := nPos + BMP.Width;
      if BMP.Bits[N] = C then Sub_Push(N);
    end;

begin
  Stack := TStack.Create;
  try
    C := BMP.Pixel[X, Y];

    Sub_Push(X + Y * BMP.Width);
    while Stack.Count > 0 do
      Sub_Check;
  finally
    Stack.Free;
  end;
end;
재귀 호출을 없애고 TStack 을 사용했습니다.
GoTo 문으로도 작성이 가능할까요?.... 별로 하고 싶지 않습니다...;;

여기서는 속도에 문제가 좀 있습니다.
TStack 은 사실상 TList 이고, 이 놈은 매번 메모리를 늘였다 줄였다 하거든요



3) 4 방향 FloodFill - Array 사용
procedure JnFloodFill3(BMP: TBitmap32; const X, Y: Integer; const AColor: TColor32);
var
  C: TColor32;
  Stack: PIntegerArray;
  Index: Integer;

    procedure Sub_Push(const APxPos: Integer);
    begin
      BMP.Bits[APxPos] := AColor;
      Inc(Index);
      Stack[Index] := APxPos;
    end;

    procedure Sub_Check;
    var
      nPos, N: Integer;
    begin
      nPos := Stack[Index];
      Dec(Index);

      N := nPos - 1;
      if BMP.Bits[N] = C then Sub_Push(N);
      N := nPos + 1;
      if BMP.Bits[N] = C then Sub_Push(N);
      N := nPos - BMP.Width;
      if BMP.Bits[N] = C then Sub_Push(N);
      N := nPos + BMP.Width;
      if BMP.Bits[N] = C then Sub_Push(N);
    end;

begin
  Index := -1;
  C := BMP.Pixel[X, Y];

  GetMem(Stack, BMP.Width * BMP.Height);
  try
    Sub_Push(X + Y * BMP.Width);
    while Index > -1 do
      Sub_Check;
  finally
    FreeMem(Stack);
  end;
end
똑같은 코드를 TStack 대신 배열로 잡았습니다. 처음 한번만 넉넉하게 메모리를 잡아 줍니다.
이젠 불필요하게 메모리를 만지지 않겠죠.
이렇게 하니 속도가 조금 개선 되네요.
물론 그래봐야 재귀호출 보다는 느리니, 최적화된 재귀호출에 비해서도 느리겠죠...;



테스트 결과


1), 2), 3) 순서대로 200x200 사이즈의 BOX 내부에 FloodFill한 결과입니다.
1)번에서 스택 오버플로가 발생하지 않도록 기준점을 정중앙으로 잡았습니다.

1 ms 정도 느리지만 무시하고 그냥 씁시다......;;;


  

GR32 (TBitmap32) 에서 Gradient Fill

Posted by NUL PROG. : 2010. 11. 15. 18:44

Graphics32
 는 델파이를 사용하는 사람중에서는 모를 사람이 없을 정도로 유명한 라이브러리입니다.


Gradient Fill 을 구현할 경우 Angus Johnson 님의 GR32_Lines/GR32_Text 를 쓰면 대부분의 Gradient 를 구현할 수 있습니다. (Gradient 이외에도 유용한 기능이 많죠)


다만 속도가 문제인데요. 비교적 단순한 Gradient 효과를 주기 위한 용도로는 조금 느린감이 있습니다.

그렇다고 인라인 어셈블리어로 대체할 능력은 안되기 때문에... 저는 윈도우 API를 사용합니다.

function GradientFill; external msimg32 name 'GradientFill';


윈도우 2000 부터 지원하는걸로 알고 있고요.

제가 만들어 쓰는 GUI 용 컴포넌트들은 이걸 많이 사용합니다.


이 함수를 비롯한 여타의 GDI 함수를 Bitmap32에 적용할 때의 문제점은 알파값이 누락 되는데 있습니다.
(혹 가능한 방법이 있을지는 모르겠네요)

그래서 API 를 쓰고 해당 부분의 알파 값을 재지정 하는 단순무식한 방법을 쓰곤 합니다 -_-;


아래는 가로 방향 Gradient 의 한 예 입니다.
procedure JnGradientFillHor(BMP: TBitmap32; const R: TRect; const B, C1, C2: TColor32);
var  
  TriVertex: array[0..1] of TTriVertex;  
  GradRect: array[0..1] of TGradientRect;
  i: Integer;
  P: PColor32;
begin
  GradRect[0].UpperLeft := 0;
  GradRect[0].LowerRight := 1;
  GradRect[1].UpperLeft := 1;
  GradRect[1].LowerRight := 2;
  TriVertex[0].Red :=   (C1 and $00FF0000) shr 8;
  TriVertex[0].Green := (C1 and $0000FF00);
  TriVertex[0].Blue :=  (C1 and $000000FF) shl 8;
  TriVertex[1].Red :=   (C2 and $00FF0000) shr 8;
  TriVertex[1].Green := (C2 and $0000FF00);
  TriVertex[1].Blue :=  (C2 and $000000FF) shl 8;
  TriVertex[0].x := R.Left;  TriVertex[0].y := R.Top;
  TriVertex[1].x := R.Right;  TriVertex[1].y := R.Bottom;
  GradientFill(BMP.Canvas.Handle, @TriVertex[0], 2, @GradRect[0], 1, GRADIENT_FILL_RECT_H);
  
  P := @BMP.Bits[0];
  for i := 0 to BMP.Width * BMP.Height - 1 do
  begin
    P^ := P^ or $FF000000;
    Inc(P);
  end;

  BMP.FrameRectS(R, B);
end;
좌측이 GR32_Lines에서 제공하는 SimpleGradientFill 함수, 우측이 위의 함수를 사용한 결과입니다.




200x200 사이즈의 Gradient Fill 에서 속도 차이가 20배 가까이 나오네요 (단위는 nanosecond)


GradientFill 함수를 커스터마이징 하면 다양한 Gradient 효과를 줄수 있습니다.

다만 Radial Gradient Fill은 방법이 없네요.. 


아무튼 전 이런 식으로 쓰고 있답니다.



  

Delphi 2007 Remote Debuging

Posted by NUL PROG. : 2010. 1. 26. 03:09

방법

Using_the_Remote_Debugger_with_Delphi_2007_and_Delphi_2009

위의 링크에서 매우 친절하게 스샷에 박스 그려서 설명해 주고 있다. (영어 몰라도 한눈에 알수 있음)


원래 있는 문제점

델파이 2007이 원격 디버깅에 문제가 좀 있다. 디버깅 하다 보면 IDE가 자주 죽어버린다.

원격 디버깅 대상 프로그램도 함께 사라져버리기도 한다 -_-;


새로 발견한 문제점?

그동안 버그를 피해가며 잘 써온 원격 디버거인데... 새로 제작하는 장비의 PC에서 오류가 발생했다.

Exception Processing Message c0000013 Parameters 764cbf7c 4 764cbf7c 764cbf7c

무시하고 써도 되긴 하는데... 원격 PC에 뜨는 메세지창을 클릭해대는 것이 여간 귀찮은게 아니다. 당연하겠지만 IDE 오류도 더 빈번히 발생하다.

처음에는 델파이에 제공되는 리모트 디버거에 문제가 있나 생각에 여기저기 뒤져봤으나 소득이 없었다.

그런데 저 오류 메세지로 검색해보니 엄청난 양의 검색 결과가 나온다.

바이러스, 악성코드에서부터 하드웨어 혹은 윈도우의 설치상의 문제 등등 원인도 다양하다...


사실 바이러스일거라고는 생각조차도 못했는데...

아마도 특정 바이러스 혹은 악성 코드가 넷트웍을 사용하면서 특정 상황에서 저런 오류를 발생시키는가 보다.

바이러스/악성코드야 지워버리면 그만이지만 난 디버깅을 해야만하니까... 별 도움이 안되는 정보다.


내 개인 데스크탑도 같은 오류가 발생했는데... 혹시나 하는 생각에 바이러스 검사를 해봤다...

시간이 너무 오래 걸린다 5% 되자 취소.


다음은 하드웨어 관련(드라이버 설치 및 알수 없는 윈도우 시스템 파일등등) 문제를 확인해보려는데...

윈도우를 다시 깔기는 싫다 - 보통 한번 윈도우를 깔면 피씨가 안켜질때까지 써야 한다고 본다. -

결국 하드웨어 목록에서 안쓰는 걸 [사용안함]으로 체크하기로 결정 (http://pc.ahnlab.com/bluebelt_pcdic/pcdic_view.do?BBS_SEQ=274318 가뭄의 단비와 같은 글이다 ㅜㅜ)


내 데스크탑도 장비 PC와 같은 증상이라 일단 이걸로 테스트하기로 결정하고

장치관리자에서 필요없는 플로피 디스크 드라이버를 찾아 [사용안함]으로 체크...

그러니까 잘된다... 이게 도대체 뭔일인지 -_-;


바로 달려가 장비 PC에서 플로피 디스크 드라이버를 [사용안함]으로 체크...

역시 잘된다... 이런 허무한...

그런데 이건 고객이 플로피 디스크를 달아달라고 했기 때문에 장치를 없애 버리면 안된다.

장치관리자 목록을 보는데 뺼게 아무것도 없다. 장비 PC라보니 PCI 슬롯 가득, LPT, 추가적인 포트, USB 몽땅에 1394 까지 사용한다. 도대체 뺼수 있는게 없다.

결국 다시 운영체제를 설치해야만 하는가 그래도 안되면 디버깅할때만 플로프 디스크를 잠가둘까.... 하고 체념할 뻔 했는데...

장치관리자에 모니터가 2개가 보인다... 음 이거 뭐지... 하나 제거... 다시 테스트해보니 OK


결국 해결... 프로그래머 다운 해결법도 아니고 정확안 원인 파악은 안됐지만... 

리모트 디버거를 리버스 엔지니어링해서 원인을 규명하고픈 생각은 들지 않는다.


결론

XP 기준으로 내컴퓨터 - 하드웨어 - 장치관리자에서 쓰지 않는 장치는 모두 사용안함으로 체크.

  

OpenCV + Delphi

Posted by NUL PROG. : 2009. 11. 26. 22:34

어차피 DLL 인 라이브러리라 델파이에 못 붙일 것도 없죠
델파이용 DLL 헤더 만드는 일은 늘상있는 일이기도 하고요
그렇지만 전체 헤더를 몽땅 변환하는 건 정말 고되고도 재미 없는 작업입니다.
그래서 보통은 그때 그때 필요한 함수와 타입만을 끄집어 냅니다.
계속 같은 작업을 하다 보면 저절로 분량도 많아지고
같은 작업을 안하다보면 별로 쓸일이 없는 거니 굳이 전체 헤더 변환을 할필요가 없겠죠
(물론 시간만 된다면야 못할것도 없지만...)

아무튼 이번에도 그런식으로....
OpenCV 를 이용한 템플릿 매칭(Template Matching) + 소스 포함 이곳의 소스를 테스트 삼아 델파이로 컨버전 했습니다.

Source / exe / dll 포함
OpenCVDelpphi_Ex.7z



굳이 델파이로 헤더까지 만들어 쓸 필요가 있을까.... 싶을지도 모르겠지만

  1. 헤더 만들기가 그리 어려운게 아니고
  2. 헤더 만들다 보면 자연스럽게 함수 원형에 구조체나 자료 구조를 파악하게 됩니다.
  3. 가공할만한 델파이의 GUI 개발 능력에 편승할 수 있습니다.
  4. 특히 http://graphics32.org 와 연동하면 빠르고 화려한 GUI를 구성할수 있습니다... 그것도 무료로 (너무 오래된 거라 좀... 그렇지만... 아직까지도 몹시 쓸만합니다. MIL 에도 붙여 보았었죠)
  5. C 보다는 파스칼이 C++ 보다는 오브젝트 파스칼이 버그 유발 확률을 현저하게 줄여 줍니다.
  6. 알고리즘을 완벽히 파악한다면 GPU 활용에 쓰일 수도 있겠군요 (음 이건 C/C++도 마찬가지네)

위 샘플 이외에도 몇가지 더 돌려봤습니다.
그것들을 클래스로 단순화 / 캡슐화도 해봤고요.
꽤 쓸만합니다.

여가 시간이 많아진다면 계속 해보고 싶네요.
현업 때문에 쉽지는 않겠지만 가급적이면 OpenCV 의 사용을 줄이고 직접 알고리즘을 작성해 봤으면.... 하는데 ...



2015-11-24 내용추가

케케묵은 내용이지만 어쩌다가 구글링으로 여기까지 들어온 분들에게 민폐가 되지 않도록 내용 추가합니다.


델파이로 헤더를 만드는 건 아주 비효율적인 방법입니다. 

OpenCV는 현재까지 매우 빠른 발전을 보이고 있고, 앞으로도 그럴것이라 예상 되는바

그때마다 헤더 고치는 노가다를 하느니 C++ 을 사용하는 것이 훨씬 낫습니다.


델파이와 연동할 땐

C++로 DLL 제작 (virtual class 사용) Delphi에서 사용합니다. (graphics32는 여전히 쓸만합니다)





 

  

https://forums.embarcadero.com/thread.jspa?threadID=1069&tstart=0

간단 요약하면 환경변수의 Platform 항목을 지워주면 된다는 거


착한 직장 동료 덕에 4년만에 노트북을 업그레이드 하게 됐습니다.

술 사준다고 했는데 요즘 서로 바빠서 언제 먹으려나 -_-;

아무튼 문제는 OS가 비스타라는건데... 망할 HP사가 아예비스타밖에 못쓰도록 박아놔 버렸네요.

나중에 클래스 플랫폼 개발을 시도해보려는데 이거 리눅스 깔기도 고달플 듯


아무튼....


문제가 델파이 2007 사용시 설정한 컴파일 옵션이 제대로 안붙습니다.

뭘하든 --no-config가 붙어 버립니다. -_-;

처음엔 맵(map)파일과 리모트디버깅(rsm) 파일이 갱신이 안되길래 왜 그럴까 몇시간을 헤매다 찾았지요 어흑....

그 후엔 인터넷이 되는 여관(출장중이라...)에서 구글 검색 중 단 하나의 링크글을 발견...

...

스크립트 파싱을 못한 코드기어의 잘못인지 난데없는 Platform=MDC 가 세팅되는 비스타의 문제인지..

외진곳에 쳐 박힌 현재로선 알길이 없지만.... (별로 알고 싶지도 않음)

다른 버전의 윈도우에는 이런일이 없었죠....;

나중에 누군가 헤매는 사람이 또 있을까 봐(구글 보면 그리 많지는 않은 듯?) 블로깅합니다.

그외에도 느리고 불편한게 많네요.이노므 비스타... ㅜㅜ

  

반올림 (Rounding)

Posted by NUL PROG. : 2007. 8. 16. 19:15
일반적으로 반올림이라 하면 특정 자리수가 4이하면 버리고 5이상이면 올리는것을 말하며, 이를 산술 반올림(Arithmetic Rounding) 이라 합니다. 하지만 델파이에서는 이 산술 반올림을 쓰지 않죠. (다른 언어는 레퍼런스를 참조해야 합니다. 모르겠다는 뜻 -_-;)

델파이에서 사용하는 라운딩 방법은 Banker's Rounding이라 불리는 넘으로, 1.5와 2.5는 둘 다 2로, 3.5와 4.5는 둘 다 4로 즉, 가장 가까운 짝수로 라운딩합니다. 이는 Arithmetic Rounding 에서 발생하는 편중 오차를 줄이기 위함입니다. 1,2,3,4는 버림 6,7,8,9는 올림을 하고 5를 모두 올림해버리면, 올림을 할때가 1/9 번 많아지게 되는 것이니까요.
즉, Round(1.5) + Round(2.5) = Round(1.5 + 2.5) 가 성립합니다.

물론 Banker's Rounding도 오차의 여지가 있으므로 Random Rounding(제멋대로 반올림 -_-) 이나 Alternate Rounding(교대로 반올림) 등을 쓰기도 합니다.

하지만, 간혹 산술적인 반올림(Arithmetic Rounding)이 필요한 때가 있습니다. 이때는 직접 만들어 써 줍니다.
Arithmetic Rounding Function function RoundA( X : single ) : Integer;
begin
   if val > 0 then result := Trunc(val + 0.5)
   else result := Trunc(val - 0.5)
end;


Default8087CW 와 Set8087CW($1B32); 로 델파이의 반올림 방법을 바꿀수 있긴 합니다만......
매우 비추천하는 방법입니다.
CPU의 컨트롤 워드를 조작하는 것이기 때문에... 다른 어떤 부분에서 영향을 받을 수도 있기 때문입니다.
  

델파이는 객체지향적인 언어인가?

Posted by NUL PROG. : 2007. 5. 27. 13:46
사용자 삽입 이미지
유명한 델파이 동호회에서 이런 이야기가 잠시 흘러나온 적이 있다.
내 생각을 말하자면 "객체지향적이든 아니든 중요하지 않다."이다
물론 동문서답 격인 대답이므로 답글을 달진 않았다. (요즘은 인터넷 공간에 엉뚱한 글을 답글로 쓴다는 것은 상당한 용기가 있어야 한다.)

우선 객체지향(OOP : Object-Oriented Programming)적인 언어라는 것이 무엇을 의미하는지 알아야 한다.

Class, Object, Method, Message 등으로 구성되어 Encapsulation, ,Abstraction, Polymorphism의 특성이 있는 언어라 할 수 있겠다. ( 위키피디아 에서 따왔는데, 한글 위키라 그런지 설명이 좀 부실하다. 10년 전인가 이 개념을 이해하고자 3-4권의 책을 반복으로 정독하고 10여 권을 책을 훑어 본 적이 있음을 기억할 때 그리 간단하게 규정하기는 어렵다고 본다. 이것은 범위가 넓은 거대한(?) 이론이기 때문이다. )
아무튼 대강 그런 뜻이라 여기고 넘어가도록 하자.

항상, 그 이론보다 중요한 것은 그 이론이 발생하고 발전하게 된 동기이다.
즉, 왜 이러한 이론이 필요한지, 무엇을 위한 이론인지가 중요하다.

누가 이론이 아니랄까 봐 어려운 말들로 잔뜩 설명이 되어 있는 일도 있지만,
간단히 이야기하면 원하는 기능의 코드를 빠르고 유지보수가 쉽도록, 추후의 작업에 재사용 가능하도록. 최초 설계 단계에서의 편리성과 보다 정확한 검증을 위해......
한마디로, 생산성의 향상을 위한 것이다.

이렇게 본다면, 어떠한 언어가 얼마나 OOP인가를 따지는 것보다는 어떠한 언어가 생산성이 있는가를 따지는 것이 더 의미가 있다고 본다. 비록 일반적 이론상의 OOP에 미치지 못하는 부분이 조금 있다손 치더라도 그걸로 인해 생산성이 더 향상된다면 굳이 이론상의 OOP를 억지로 구겨 넣어야 할 필요가 없다.
물론 여기서 말하는 생산성은 단순히 빠른 작업 속도만이 아닌 편리성, 안정성을 추가한 개념이다. 뭐 사실 그것이 빠른 작업 속도에 영향을 끼치긴 마찬가지이지만.....

예를 들면, 폼 기반의 애플리케이션 구조를 가진 델파이의 VCL은 객체지향적이라고 하기엔 부족한 면이 있지만, 이는 매우 편리한 UI 제작을 위한 DESIGN 개념을 위한 것이고 그만큼의 충분한 생산성을 향상시켰기 때문에 객체지향적이지 못하다는 것이 큰 문제가 되지 않는다는 것이다. 같은 이유로 모호한 다중상속을 좋아하지 않는다.

또 한가지,

객체지향이라는 것은 방법이나 구조에 대한 이론이기에 그 언어가 크게 중요하지 않다.
즉 어느 정도 객체지향적으로 프로그래밍할 수 있는 언어라면 OOP 이론을 적용하여 프로그래밍하는 것 자체가 중요하지 언어가 중요한 것이 아니다.

실제로 class만 있을 뿐이지 C++ 인지 C 인지 구별이 안 되는 코드는 사방에 널려 있다.

델파이의 예로 들면 VCL의 폼 기반 애플리케이션 설계는 객체지향적이라 보기 미흡하지만 독립된 몇 가지의 클래스로 데이터를 관리하고 폼은 단지 보여주기만 할 뿐...... 의 방식으로 코딩한다면 매우 훌륭한 객체지향적 프로그래밍을 할 수 있다.

요약하면... (구세대 교육을 받은 결과 인지, 요약을 하지 않으면 끝맺음이 뭔가 부실한 느낌이다. -_-; )
  • OOP를 따르는 것보다 OOP의 목적을 성취하는 것이 더 중요하다.
  • 이를 위해서는 사용하는 언어가 얼마나 객체지향적인가 보다는 개발자가 얼마나 객체지향적으로 프로그래밍할 수 있는가가 중요하다.
  
 «이전 1  다음»