2015/02/04

Perl 6를 슬슬 써보자.

Perl창시자 Larry Wall이 FOSDEM 2015Get ready to party! 라는 세션에서 2015년 9월 자신의 생일까지 Perl6의 베타판 12월25일 크리스마스에 정식판을 내놓는다고 선언했다.

그동안 Perl6는 10년이 넘도록 정식안정 버젼이 나오지 않아 프로그래밍언어계의 duke nukem forever라는 조롱을 듣기도 하고 언제 나오나요?라는 물음에는 Larry Wall은 크리스마스(몇년도 크리스마스인지는 특정하지 않음)에 나옵니다. 하는 농담으로 넘어가곤 했는데. 이번에는 딱 찝어서 2015년 크리스마스에 정식버젼을 내놓는다고 선언을 함으로써 더 이상 미룰 수 없게 되었다. 그 배경에는 내부적으로 개발수준이 프로덕션레벨에 근접했다는 자신감이 있었기 때문이 아닌가 생각된다.

다가올 Perl6를 대비해서 슬슬 테스트해보면서 써보려면 다음과 같은 과정을 거치면 쉽다.

perlbrew 같이 perl버젼 메니저 역할을 해주는 rakudobrew를 다음과 같은 과정으로 설치한다.

$ git clone https://github.com/tadzik/rakudobrew ~/.rakudobrew

그리고 .bashrc 같은 쉘초기 설정 파일에 다음과 같은 라인을 추가하고 쉘을 재시작해준다.

export PATH=~/.rakudobrew/bin:$PATH

그 다음

$ rakudobrew build moar

로 moar VM기반으로 rakudo perl6를 설치한다.
(현재 Perl6의 기반VM은 최초의 구현체인 Parrot 말고도 JVM기반과 Perl6객체에
최적화된 moarvm 3종류가 지원되고 있다.)

그 다음 아래 명령으로 Perl6 모듈관리 명령인 panda를 설치한다.

$ rakudobrew build-panda

이제 Perl6를 사용할 준비가 되었다. 동작하는지 실행해보자!
$ perl6 -e 'say "Hello, World"'
Hello, World

$ perl6 -e '([+] 1..1000).say'
500500
 
잘된다! Perl6는 요즘 Node.js쪽에서도 HOT한 것 같은 Promise, Future같은것도 지원하니 아래의 링크들을 보면서 참고해서 테스트해 보면 될듯하다.



*Perl6 관련 볼만한 링크몇개

Learn Y in X Minutes post for Perl 6
http://learnxinyminutes.com/docs/perl6/

Getting beyond static vs. dynamic
http://jnthn.net/papers/2015-fosdem-static-dynamic.pdf

Adventures in Perl 6 Asynchrony
http://jnthn.net/papers/2014-yapceu-async.pdf

Perl 6 For Mere Mortals
http://www.slideshare.net/Ovid/perl-6-for-mere-mortals

2014/12/17

Perl과 Ruby, Python의 함수 호출과 함수 참조에 대한 차이

루비와 파이썬에서 함수 호출과 함수 참조에 대한 차이
라는 글을 보고 Perl에서는 어떤지 한번 정리해 봅니다. 우선 윗글에 있는 코드를 Perl식으로 바꾸면 아래와 같습니다.

#!/usr/bin/env perl

sub a {
    print 'a';
}

sub b {
    print 'b';
}

sub f {
    my ($arg1, $arg2) = @_;
    $arg1;
}

f(a,b);


Perl에서는 Ruby,Python과 달리 변수에는 sigil이라고 하는 $를 앞에 붙여서 변수를 만듭니다. 따라서 변수명과 함수명이 같아도 엄연히 다른것이며 충돌하거나 암묵적으로 호출될 일은 없습니다.
위의 f함수에서처럼 인자로 그냥 bareword를(여기서는 a b) 사용했을경우 선언된 함수이름이 존재하면 함수를 호출하게 됩니다. 따라서 f(a,b)는 a함수, b함수 가 호출된 결과가 들어가게 됩니다. 각 함수가 차례로 호출되면서 ab가 차례로 찍히고 Perl은 { }블록형태의 함수에서 return문으로 명시적으로 리턴하지 않으면 블록내에서 마지막으로 평가된 값이 리턴됩니다. 여기서는 print 문이 성공하면 참(1)값을 돌려주기 때문에 각 함수의 마지막 평가값은 1이 되어서 결과적으로는 f(1,1)이 호출되고 f함수에서 마지막 평가값인 $arg1의 값은 1이 되어 f함수의 리턴값은 1이 됩니다. 마츠가 루비를 만들때 Perl을 많이 참고로 해서 그런지는 모르겠지만 여기 까지는 Ruby와 비슷하게 동작하는 것 같네요.

그럼 Python과 같이 함수의 참조가 넘어가서 f함수 내부에서 넘겨받은 함수 참조를 통해 호출하려면 Perl에서는 어떻게 해야 할까요?

#!/usr/bin/env perl

my $a = sub { print 'a'; };

sub b {
   print 'b';
}

my $b = \&main::b;   # 같은 패키지 내부면 my $b = \&b; 로 해도 됨

sub f {
    my ($arg1, $arg2) = @_;
    $arg1->();
    &$arg2;
}

f($a,$b);


Perl에서 함수레퍼런스는 함수가 호출되는 메모리상의 주소값을 가진 스칼라 변수 입니다. $같은 sigil이 없는 Python이나 Ruby에서는 동일한 이름을 가진 변수와 함수의 식별자(identifier)가 때로는 값 혹은 호출로 때로는 값 혹은 참조로 암묵적으로 동작하게 되지만 Perl에서는 확실히 구별됩니다. 위 Perl코드의 $a는 익명함수의 주소값을 $a라는 변수에 넣은것이고 $b는 이미 Perl의 기본 네임스페이스인 main패키지에 선언되어 심볼테이블에 기록된 b함수의 주소값을 $b변수에 넣은것입니다. 이제 두가지 방법으로 스칼라변수 $a, $b에 저장된 함수레퍼런스를 f함수에 넣어 호출하게 되면 f함수 내부에서 넘겨받은 함수 레퍼런스를 통해 함수를 호출 할때는 $arg1->() 처럼 뒤에 ->()를 붙여서 호출할 수도 있고 &$arg2 처럼 앞에 &를 붙여서도 호출 가능합니다.  Perl이 레퍼런스를 다루고 호출하는 문법을 보면 C나 Javascript 와 유사한 느낌적인 느낌이 들지 않나요?

Perl의 sigil이 코드를 noisy하게 보인다고 까는 사람도 있지만 저는 코드의 앞뒤를 뒤져보지 않아도 바로 이 코드의 의도를 명확하게 구별하고 알려주는 효자 같은 존재라고 봅니다.


PS: Perl 문법이 더 궁금한 분은 https://github.com/aero/perl_docs 을 참고하세요~

2014/08/15

Windows에서 특정 디렉토리 이하 모든 파일 및 디렉토리 지우기

Linux/Unix 계열에서 특정 디렉토리아래의 모든 디렉토리 파일을 지우려면 다음과 같이 하면 된다.

현재 디렉토리 아래의 some_directory 밑의 모든 파일 및 디렉토리 지움

rm -rf ./some_directory/*

이런 작업을 윈도우에서 하려면 어떻게 하면 될까?

del 명령과 rmdir 명령을 아무리 조합해도 한번에 만족할 만한 결과를 얻기 힘들다.
파일은 다 지워지는데 빈 디렉토리는 남아있다던가 특정 디렉토리 아래의 모든 것을 지우고 싶은데 그 특정 디렉토리도 지우지 않고는 안되는... 그래서 다 지우고 또 그 디렉토리를 만들어 주는 등등.

https://www.google.co.kr/search?q=dos+cmd+completely+delete+sub+director&ie=utf-8&oe=utf-8

위 검색결과를 보면 알겠지만 깔끔하고 만족스러운 방법이 없다.

그래서 Perl을 항상 깔아 쓰는 나는 이럴때 그냥 Perl로 하기로 했다.
Perl one-liner 를 써서 File::Path 모듈을 이용해서 하면

perl -MFile::Path=remove_tree -e "remove_tree('.\some_directory', { keep_root=>1 })"

2014/04/07

Perl의 다단계 deep hash와 autovivification

Perl에서 autovivification은 어떤때는 아주 강력한 장점이 되기도 하지만 잘 모르고 쓰다가는 찾기 힘든 버그를 만들 수 도 있다.

autovivification은 Perl의 해시구조에서 해시키가 존재하지 않을 경우 자동으로 생성해주는 기능으로 잘 활용하면 다음과 같은 집계작업을 아주 쉽게 끝낼 수 있다.

* 과일을 색깔별로 몇개씩 있는지 집계하는 코드

use strict;
use Data::Dumper;
my %h;
while (<DATA>) {
    chomp;
    my ($color, $fruit) = split;
    $h{$color}{$fruit}++;
}
print Dumper(\%h);

__DATA__
green apple
red apple
red strawberry
green banana
green apple
yellow banana
red apple
green apple
yellow apple
green strawberry

* 결과

$VAR1 = {
          'red' => {
                     'apple' => 2,
                     'strawberry' => 1
                   },
          'yellow' => {
                        'banana' => 1,
                        'apple' => 1
                      },
          'green' => {
                       'strawberry' => 1,
                       'banana' => 1,
                       'apple' => 3
                     }
        };


하지만 다단계 hash를 사용할때 가장 실수하기 쉬운 것은 만약에 hash키의 존재로 판단해야 하는 작업시 exists로 해당 해시키가 존재하는지 채크하게 되는데

if (exists $h{a}{b}) { say "exists"; }

처럼 $h{a} 즉 a키가 존재하지 않는데 이런식으로 하위 키에 대해 바로 존재여부를 채크하게 되면 중간 단계 a가 autovivification 기능에 의해 예기치 않게 생성되어 버린다. 그래도 문제 없을 경우도 있겠지만 만약에 첫 단계 해시키의 존재유무로 어떤 작업하는 로직이 같은 프로그램 안에 있다면 언제 용이 튀어 나올지 모른다. 그래서 이런 동작을 방지하려면

if (exists $h{a} && exists $h{a}{b}) { say "exists"; }

처럼 단계적으로 채크해 들어가야 한다.  그런데 여러단계면 이런식으로 계속적으로 채크 코드를 나열하는건 손가락이 아픈 일이라 생각되어 예전에 언뜻 본 autovivification 여부를 조정할 수 있는 autovivification 모듈을 사용하면 편하지 않을까 싶어 한 번 테스트를 해보았다.

아래 코드는 if 문의 판단부분에 do블럭으로 autovivification으로 비활성화 시키고 해시키 여부 판단코드를 쓴것과 다단계 채크 방식의 속도를 비교했고, 추가로 매번 if문 안에서 비활성화 시키지 않고 기본으로 비활성화 시킨상태에서 비교한 것이다.


#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use autovivification;
use Benchmark qw/cmpthese/;

cmpthese(1000000, {
    step => sub {
        my %h;
        if (exists $h{a} && exists $h{a}{b}) { say "exists"; }
    },
    autovivification => sub { 
        my %h;
        if (do { no autovivification; exists $h{a}{b} }) { say "exists"; }
    },
});
no autovivification;
# 이 이하는 autovivification 비활성화
cmpthese(1000000, {
    step2 => sub {
        my %h;
        if (exists $h{a} && exists $h{a}{b}) { say "exists"; }
    },
    autovivification2 => sub { 
        my %h;
        if (exists $h{a}{b}) { say "exists"; }
    },
});
.

벤치마크 결과는 다음과 같다.

            (warning: too few iterations for a reliable count)
                      Rate autovivification             step
autovivification  265957/s               --             -92%
step             3194888/s            1101%               --
            (warning: too few iterations for a reliable count)
                       Rate autovivification2             step2
autovivification2  348432/s                --              -89%
step2             3194888/s              817%                --


다단계로 채크해 들어가는게 autovivification 모듈을 사용하는 것 보다 10배 가까이 빠른 속도를 보여준다.

결론:
 속도가 중요하다면 손가락이 아파도 해시키의 존재 여부는 다단계로 채크하자.

2013/12/03

2013년 Advent calendar들


올해도 어김없이 찾아온 Perl Korea Advent Calendar 2013

http://advent.perl.kr/2013/

전 세계적으로도 다른 Perl관련 Advent Calendar들이 시작되었음

Perl Advent Calendar
http://www.perladvent.org/2013/

Perl6 Advent Calendar
http://perl6advent.wordpress.com/

Catalyst Advent Calendar
http://www.catalystframework.org/calendar/

Dancer Advent Calendar
http://advent.perldancer.org/2013

Future Advent Calendar
http://leonerds-code.blogspot.co.uk/search/label/advent

일본 Perl Advent Calendar
http://qiita.com/advent-calendar/2013/perl

일본 Mojolicious Advent Calendar
http://qiita.com/advent-calendar/2013/mojolicious


그외에도 
Sysadmin Advent Calendar
http://sysadvent.blogspot.kr/

일본에서는 오픈소스 커뮤니티에 Advent Calendar 열풍이 불어서
Dog이나 Cow나 Advent Calendar를 만들고 있음
http://qiita.com/advent-calendar/2013



2013/06/21

PERL_NEW_COPY_ON_WRITE on Windows Perl.

I've found PERL_NEW_COPY_ON_WRITE option at https://metacpan.org/module/DAGOLDEN/perl-5.19.1/pod/perldelta.pod#Performance-Enhancements

This feature was already available in 5.18.0, but wasn't enabled by default.

So I recompiled Perl 5.18.0 with PERL_NEW_COPY_ON_WRITE option on Windows and compared with Non-PERL_NEW_COPY_ON_WRITE Strawberry Perl 5.18.0.

This is the result.


<Test code>

perl -MBenchmark=cmpthese -e "sub A {my ($s) = @_; length($s) } sub B { my ($s) = @_; $s .= 'B'; length($s) } cmpthese(10000, { test1 => sub { my $s = 'A'x1000000; A($s) }, test2 => sub { my $s = 'A'x1000000; B($s) } })"

"sub A" doesn't modify the input string but "sub B" modfies the input string.

* Strawberry Perl 5.18.0

test1  3374/s    --   -2%
test2 3428/s    2%    --

* PERL_NEW_COPY_ON_WRITE version

test1  8905/s  539%    --
test2 1393/s    --  -84%




PERL_NEW_COPY_ON_WRITE option accelerates "sub A" but slows down "sub B".
I'm wondering why "sub B" is much slower in PERL_NEW_COPY_ON_WRITE option.


2013/06/17

Hooking MS windows messages on Wx Perl.

Sometimes you may need to catch a Windows message that is not already handled by wxWidgets, so there is no Wx::Event for it. With a bit of help from the WIN32::API modules it is possible to hook into the WndProc chain for a wxWindow and watch for the message you are interested in.

The magic is in the SetWindowLong function. When used with the GWL_WNDPROC flag it causes a new WndProc to be set for the window, and returns the old one. This lets you write a function in Perl that can get first crack at all the Windows messages being sent to the window, and if you are not interested in them then pass them on to the original wxWidgets WndProc.

#!/usr/bin/env perl
use strict;
use Win32::API;
use Win32::API::Callback;
use Wx;

# Perl port of Python Code: http://wiki.wxpython.org/HookingTheWndProc

{

    package MyFrame;
    use base 'Wx::Frame';

    use constant GWL_WNDPROC => -4;

    # LONG  SetWindowLong(HWND hWnd, int nIndex, LONG dwNewLong);
    Win32::API->Import('user32', 'SetWindowLongW', 'NIK', 'N');
    # LRESULT CallWindowProc(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
    Win32::API->Import('user32', 'CallWindowProcW', 'NNIII', 'N');

    sub new {
        my $ref = shift;
        my $self = $ref->SUPER::new( undef,           # parent window
            -1,              # ID -1 means any
            'wxPerl rules',  # title
            [-1, -1],        # default position
            [150, 100],      # size
        );
        # controls should not be placed directly inside
        # a frame, use a Wx::Panel instead
        my $panel = Wx::Panel->new( $self,            # parent window
            -1,               # ID
        );
        # create a button
        my $button = Wx::Button->new( $panel,         # parent window
            -1,             # ID
            'Click me!',    # label
            [30, 20],       # position
            [-1, -1],       # default size
        );
        $self->{newWndProc} = Win32::API::Callback->new(sub { $self->_MyWndProc(@_) }, 'NIII', 'N');
        $self->{oldWndProc} = SetWindowLongW( $self->GetHandle(), GWL_WNDPROC, $self->{newWndProc} );

        return $self;
    }
    
    sub _MyWndProc {
        my ($self, $hWnd, $msg, $wParam, $lParam) = @_;
        # You can process MS Windows messages here.
        print join (',',@_),"\n";
        CallWindowProcW($self->{oldWndProc}, $hWnd, $msg, $wParam, $lParam);
    }

}

{

    package MyApp;
    use base 'Wx::App';

    sub OnInit {
        my $frame = MyFrame->new;
        $frame->Show( 1 );
    }

}

my $app = MyApp->new;
$app->MainLoop;



2013/05/19

Perl 5.18.0 출시

2013년 5월 18일 Perl 5.18.0 버젼이 출시되었다. 5.18은 우리 현대사에서도 의미 있는 날인데 Perl 5.18.0 버젼을 5월 18일에 내놓는 센스를 발휘하다니...

Perl 5.18.0 에서 바뀐 내용들은 https://metacpan.org/module/RJBS/perl-5.18.0/pod/perldelta.pod 에 잘 정리되어 있다.

5.18.0버젼은 5.16.0 버젼이후 1년동안의 개발기간 동안 113명의 개발자에 의해 2100개의 파일, 400000라인의 수정/추가가 이루어 졌다고 한다.

중요한 점만 짚어 보자면..

Unicode 6.2를 지원.

예전에는 암묵적으로 허용되었던 foreach my $item qw/A B C/ { ... } 같은 코드는 ( )를 명시적으로 싸서 foreach my $item (qw/A B C/)  { ... } 처럼 해 주지 않으면 에러가 난다.  

given ~ when 구문과 ~~스마트매치 연산자가 실험적기능(experimental)으로 빠졌다. 그동안 너무 복잡하고 설계에 문제점이 있다고 말이 많았는데 이 기회에 일단 빼놓고 다시 검토할 계획인가 보다. 5.18에서는 해당 문법을 쓰면 경고가 난다.
 참고: https://metacpan.org/module/RJBS/perl-5.18.0/pod/perldelta.pod#The-smartmatch-family-of-features-are-now-experimental

그리고  encoding, Archive::Extract, CPANPLUS 등 코어모듈에서 제외된 모듈들이 제법 있다.
 참고: https://metacpan.org/module/RJBS/perl-5.18.0/pod/perldelta.pod#Module-removals

또 hash의 취약점 공격을 막기 위해 hash에서 값을 뽑아낼때 마다 랜덤하도록 바뀌었다. 이 때문에 테스트에서 에러가 나는 모듈이 종종 있다.  특히 많이 쓰는 JSON::XS모듈도 그 중 하나인데 패치 되기전에 일단 cpan -T JSON::XS 나 cpanm -n JSON::XS 명령으로 테스트과정을 생략하고 설치해서 쓰도록 하면 된다고 한다.(JSON::XS 모듈은 2.34버젼에서 고쳐졌음)
 참고: http://blog.twoshortplanks.com/2013/05/20/5-18-hash-keys/


마지막으로 Perl 5.18.0 버젼은 안타깝게도 우리 곁을 일찍 떠나버린 @am0c 군을 추모하는 글( https://metacpan.org/module/RJBS/perl-5.18.0/pod/perldelta.pod#Obituary ) 이 포함되어 더욱 뜻깊은 버젼이기도 하다.

2013/04/12

How to use ActiveState Perl's unique features in Strawberry Perl

ActiveState Perl supports unique features like PerlScript ActiveX control and new Tcl and  Tkx module.
But they are close-sourced products, So strawberry perl can't provide those features and can't install through CPAN.

I will show you how to steal the features from ActiveState Perl.

1. 
Install Strawberry perl

2.
Get the same version of ActiveState Perl .zip file format from http://downloads.activestate.com/ActivePerl/releases/ and unzip it.

3. PerlScript
Copy ActivePerl-OOOOOO-MSWin32-OOOOO\perl\bin\PerlSE.dll to C:\strawberry\perl\bin
Run cmd.exe as administrator
cd C:\strawberry\perl\bin
Execute "regsvr32 PerlSE.dll" command. (You can uninstall it with "regsvr32 /u PerlSE.dll" command.)

* Open editor and save the following code as "test.wsf" file

<job id="test">
<script language=PerlScript>
    $WScript->Echo("Hello World!");
</script>
</job>

Execute "cscript test.wsf" or double-click "test.wsf" to check to see if PerlScript works or not.

4. Tkx

Copy
ActivePerl-OOOOOO-MSWin32-OOOOO\perl\lib\Tcl.pm
ActivePerl-OOOOOO-MSWin32-OOOOO\perl\lib\Tcl\*

ActivePerl-OOOOOO-MSWin32-OOOOO\perl\lib\Tkx.pm
ActivePerl-OOOOOO-MSWin32-OOOOO\perl\lib\Tkx\*

ActivePerl-OOOOOO-MSWin32-OOOOO\perl\lib\auto\Tcl\*

ActivePerl-OOOOOO-MSWin32-OOOOO\perl\lib\auto\Tkx\*
files and the same folder structure to C:\strawberry\perl\site\lib folder.

ActivePerl-OOOOOO-MSWin32-OOOOO\perl\bin\tkx-ed
ActivePerl-OOOOOO-MSWin32-OOOOO\perl\bin\tkx-ed.bat
ActivePerl-OOOOOO-MSWin32-OOOOO\perl\bin\tkx-prove
ActivePerl-OOOOOO-MSWin32-OOOOO\perl\bin\tkx-prove.bat
files to C:\strawberry\perl\site\bin folder.

Run tkx-ed to check to see if Tkx works or not.



WARNING:
USE AT YOUR OWN RISK. :)

2013/03/13

perlbrew 의 새로운 기능

Perl을 root권한 없이 로컬계정에 설치 및 여러 버젼을 번갈아가면서 쓸 수 있게 해주는 perlbrew 에 upgrade-perl 이라는 새로운 기능이 추가됐다.

perl은 5.16.2 처럼 3단계 버젼번호체계를 가지는데 중간버젼간(예를 들면 5.16.2, 5.16.3)에는 모듈의 바이너리 호환성이 보장되기 때문에 C코드등이 포함되어 네이티브하게 컴파일되는 XS모듈 같은 경우 재설치하지 않아도 그대로 사용 가능 하다. 하지만 맨 마지막 점 아래의 마이너 버젼이 바뀌었을때 perlbrew로 새로 마이너 버젼 업그레이드된 perl을 설치하면 예전 쓰던 모듈을 쓰기 위해서는 이전에 깔았던 모듈목록을 뽑아서 다 다시 설치해주는 번거로움이 있었다.

upgrade-perl을 쓰면 다음과 같이 가능하다.

<perl-5.16.3 버젼을 perl-5.16으로 설치한다. 본인의 경우 verbose -v옵션 스레드사용 -D=usethreads 추가>
$ perlbrew -v install perl-5.16.3 --as perl-5.16 -D=usethreads

(위에서 mod_perl이나 pgsql perl플러그인등 기타 어플리케이션에서 동적Perl라이브러를 연동시키려면 -Duseshrplib 을 추가하고 Dtrace를 사용하려면 -D=usedtrace 추가한다. 그 이외의 옵션은 사용자가 굳이 지정하지 않아도 가장 최적의 옵션을 자동으로 선택하므로 굳이 신경쓸 필요가 없다.)

<버젼을 스위치 한다.>
$ perlbrew switch perl-5.16


<설치된 perl목록보기>
$ perlbrew list
* perl-5.16 (5.16.3)
^-괄호안에 5.16 이름으로 실제 설치된 버젼명이 표시된다.

나중에 5.16.4 버젼이 나왔다고 하면

$ perlbrew upgrade-perl

이라고 하면 위의 경우에는 현재 사용하는 Perl의 바이너리 호환이 되는 버젼(5.16.x)의 최신 버젼이 설치되며 기존에 설치해놓았던 모듈을 그대로 사용가능하다.

더 자세한 내용은 아래링크 참고

https://metacpan.org/module/GUGOD/App-perlbrew-0.59/bin/perlbrew#COMMAND:-UPGRADE-PERL

http://jptrans.naver.net/j2k_frame.php/korean/blog.64p.org/entry/2013/03/13/150202

http://www.modernperlbooks.com/mt/2013/03/upgrade-in-place-with-perlbrew.html

2012/12/03

2012/10/17

PDL, PDL::Stats 예제 t분포

t-분포정규분포와 유사한 확률분포이며, 모집단의 표준편차를 알지 못하며(표본의 표준편차로 모집단의 표준편차를 대용) 표본의 크기가 작을 때(n<30) 주로 이용한다. 자유도(n-1)가 낮을수록 봉이 낮아지고 꼬리가 높아지며 자유도가 높을수록 정규분포에 가까워진다.

#!/usr/bin/env perl
use 5.010;
use PDL;
use PDL::Stats;
use PDL::GSL::CDF;
use PDL::Graphics::PGPLOT::Window;
use Math::GSL::Randist qw/gsl_ran_tdist_pdf/;

# t 분포
my $win = pgwin();
my $x = zeroes(100)->xlinvals(-4, 4);
$win->env(-4,4,0,1,{Title=>'t distribution'});
$win->hold();
#CDF
$win->line($x, gsl_cdf_tdist_P($x, 29),{COLOR=>'RED'});
$win->line($x, gsl_cdf_tdist_P($x, 4),{COLOR=>'MAGENTA'});
#PDF
$win->line($x, [ map { gsl_ran_tdist_pdf($_, 29) } $x->list ],{COLOR=>'BLUE'});
$win->line($x, [ map { gsl_ran_tdist_pdf($_, 4) } $x->list ],{COLOR=>'CYAN'});

# t분포 자유도10, 우측꼬리확률 0.05일때 t확률변수 값은?
say gsl_cdf_tdist_Pinv(1-0.05, 10);
# t분포 자유도10, 양측꼬리확률 0.05일때 t확률변수 값은?
say gsl_cdf_tdist_Pinv(pdl(0.05/2, 1-0.05/2), 10);


1.81246112281168
[-2.2281389  2.2281389]

자유도29(표본수 30), 자유도4(표본수 5)에 대해서 PDF그래프를 보면 자유도가 낮을수록 펑퍼짐하며 높을수록 봉이 높아지며  정규분포에 가까워짐을 볼 수 있다. 분포가 펑퍼짐하다는 것은 표본수가 작을 수록 불확실성이 크기때문에 양쪽으로 치우칠 확률이 더 높다는 것을 의미한다.

2012/10/12

PDL, PDL::Stats 예제 정규분포

정규분포(가우스분포)는 앞서 올린 이항분포의 n이 아주 커질 경우 근사적으로 따르게되는 확률분포이며(참고) 통계학에서 기본이 되는 연속확률변수 이다. 평균과 표준편차가 다른 많은 정규분포가 존재할 수 있으나 z점수를 통해 평균 0, 표준편차 1 인 표준정규분포로 변환해서 계산가능하다. 계산기 및 컴퓨터가 발달하지 않았던 옛날에는 주로 미리 계산된 표를 통해서 계산했지만 요즘에서는 굳이 그럴 필요없이 컴퓨터에 미리정의된 함수를 활용하면 간단하다.

다음은 표준정규분포의 확률밀도함수(PDF)누적분포함수(CDF)를 그리고 정규분포을 이용해서 몇가지 예에 대해 계산하는 코드이다.

#!/usr/bin/env perl
use 5.010;
use PDL;
use PDL::Stats;
use PDL::GSL::CDF;
use PDL::Graphics::PGPLOT::Window;
use Math::GSL::Randist qw/gsl_ran_gaussian_pdf/;

# 정규분포
my $win = pgwin();
my $x = zeroes(100)->xlinvals(-4, 4);
$win->env(-4,4,0,1,{Title=>'standard normal(gaussian) distribution'});
$win->hold();
#CDF
$win->line($x, gsl_cdf_gaussian_P($x,1), {COLOR=>'RED'});
#PDF
$win->line($x, [ map { gsl_ran_gaussian_pdf($_, 1) } $x->list ], {COLOR=>'BLUE'});
# PDL::Stats::Distr의 pdf_gaussian 함수 사용시
#$win->line($x, $x->pdf_gaussian(0, 1), {COLOR=>'BLUE'});

# 시험결과 학생들의 성적이 평균이 63점 분산이 100인 정규분포를 따른다고 하면
# 50점 미만의 학생은 몇 %인가 ?
# Z = (50-63)/sqrt(100) 이므로
say gsl_cdf_gaussian_P((50-63)/sqrt(100), 1)*100, " %";

# 상위 10%에게 A를 주면 A를 받기 위해서 몇점 이상이 되어야 하는가?
my $Z = gsl_cdf_gaussian_Pinv(0.9, 1); # 표준정규분포에서 하위(100-10)=90% 위치의 Z값
# Z = (X-63)/sqrt(100) 이므로 점수X는
say $Z*sqrt(100)+63


<결과>
9.68004845856103 %
75.815515655446


그래프에서 파란색이 PDF, 빨간색이 CDF의 그래프이다. 표준정규분포의 확률변수구간은 음의무한대에서 양의 무한대 까지이나 -4~4구간만 그렸으며 PDF아래의 면적이1 CDF는 PDF를 구간별로 적분한 값으로 0에서 1에 수렴한다.

2012/10/11

PDL, PDL::Stats 예제 이항분포

앞서 올린 PDL, PDL::Stats 로 기본 통계량 계산하기 에 이어 이항분포에 대한 예를 들어보면 다음과 같다.

이항분포는  연속된 n번의 독립적 시행에서 각 시행이 확률 p를 가질 때의 확률분포를 말하는데 말로 하는 것 보다 다음 그림을 보면 그 의미가 명확해진다.

위 틀의 꼭대기에서 구슬을 떨어뜨리면 각 층에서 좌우로 갈 확률p는 반반(1/2)으로 각층을 통과 하며(독립시행) 구슬이 제각각의 칸으로 떨어지게 되는데 아래 구슬이 쌓인 모양이 바로 이항분포가 되는 것이다.

 그러면 n=30, p=0.5 일때 이항분포의 확률질량함수 PMF[Probability Mass Function](연속확률변수의 PDF에 해당), 누적분포함수 CDF[Cumulative Distribution Function] 의 예를 코딩해 보면 다음과 같다.

#!/usr/bin/env perl
use 5.010;
use PDL;
use PDL::Stats;
use PDL::GSL::CDF;
use Math::GSL::Randist qw/gsl_ran_binomial_pdf/;
use PDL::Graphics::PGPLOT::Window;

my $win1 = pgwin();
my $x = sequence(30);
$win1->env(0,30,0,1,{Title=>'binomial distribution'});
$win1->hold();

#CDF
# gsl_cdf_binomial_P는 PDL::Stats에 포함된 PDL::GSL::CDF 모듈의 함수
$win1->bin($x, gsl_cdf_binomial_P($x, 0.5, 30),{COLOR=>'RED'});

#PMF
# Math::GSL::Randist의 gsl_ran_binomial_pdf 함수를 사용
# PDL용 함수가 아니라서 piddle을 계산하지 못하므로 map으로 piddle $x내부의 값을
# map 함수를 사용하여 리스트를 순회하며 적용
$win1->bin($x, [ map { gsl_ran_binomial_pdf($_, 0.5, 30) } $x->list ], {COLOR=>'BLUE'});
# PDL::Stats::Distr의 pmf_binomial 함수를 사용할 시
# $win1->bin($x, $x->pmf_binomial(30, 0.5), {COLOR=>'BLUE'}); 

#동전을 30번 던졌을때 12번 앞면이 나올 확률
# PMF 그래프 가로축 12일때 세로축의 값
say gsl_ran_binomial_pdf(12, 0.5, 30) * 100, " %";
#say piddle(12)->pmf_binomial(30, 0.5) * 100, " %"; # pmf_binmoial 함수를 사용할 시
#동전을 30번 던졌을때 12번 이하로 앞면이 나올 확률
# CDF 그래프 가로축 12일때 세로축의 값
# 결론적으로 12까지의 PMF그래프 값을 누적한(적분) 것
say gsl_cdf_binomial_P(12, 0.5, 30) * 100, " %";


<결과>


8.05530929937956 %
18.0797304026779 %

위 그래프에서 파란색이 PMF이고 빨간색이 CDF이다. PMF그래프 아래의 면적을 구하면 1이 되고 CDF는 0에서 시작하여 1까지 증가한다는 사실을 보면 확률의 분포와 누적확률이 시각적으로 느껴질 것이라고 본다.

2012/10/10

PDL, PDL::Stats 로 기본 통계량 계산하기

Perl에는 Matlab같은 PDL이란 것이 있다.

여기에 PDL::Stats 모듈을 같이 사용하면 오픈소스 통계패키지인 R같이 여러가지 통계계산도 할 수 있다.

다음은 어떤 데이터의 평균, 분산, 표준편차, 어떤 두 데이터간의 공분산상관계수를 구하는 예제 코드이다.

#!/usr/bin/env perl
use 5.010;
use PDL;
use PDL::Stats;
use PDL::Graphics::PGPLOT::Window;

my $data = pdl( [1,1,5,6,7,3,3,9,4,10,8,6,6,2,6,15] );
say "data: ",$data;
say "average: ",$data->average;
say "variance: ",$data->var;
say "standard deviation: ",$data->stdv;

my $x = pdl( [1,2,3,4,5,6] );
my $y = pdl( [1,1.5,2,2.25,2.5,3] );
my $y2 = pdl( [6,5,4,3,2,1] );

say "x:", $x;
say "y:", $y;
say "y2:", $y2;
say "covariance x,y: ",$x->cov($y);
say "correlation x,y: ",$x->corr($y);
                  
say "covariance x,y2: ",$x->cov($y2);
say "correlation: x,y2: ",$x->corr($y2);

my $win = pgwin();
$win->hold();
$win->env(0,10,0,10);
$win->points($x,$y, {SYMBOL=>'SQUARE', COLOR=>'BLUE'});
$win->points($x,$y2, {SYMBOL=>'PLUS', COLOR=>'CYAN'});

<결과>

data: [1 1 5 6 7 3 3 9 4 10 8 6 6 2 6 15]
average: 5.75
variance: 12.4375
standard deviation: 3.52668399491647
x:[1 2 3 4 5 6]
y:[1 1.5 2 2.25 2.5 3]
y2:[6 5 4 3 2 1]
covariance x,y: 1.10416666666667
correlation x,y: 0.991332701357794
covariance x,y2: -2.91666666666667
correlation: x,y2: -1

















차후에는 여러가지 확률분포에 대해 테스트해보고자 한다.

2012/08/29

문제로 풀어보는 알고리즘 0.3 생각해보기 풀이

심심해서 풀어본 알고리듬 문제
http://www.insightbook.co.kr/post/3814 에 나와 있는 문제 풀이

Perl의 문법중에 배열 slice문법을 사용해서 한방에 여러 요소들을 치환하는 테크닉을 썼음

#!/usr/bin/env perl

my @arr = 1..8;
print "before @arr\n";
rotate(\@arr, 2, 6, 7);
print "after  @arr\n";

sub rotate {
    my ($a, $s, $t, $k) = @_;
    $k %= ($t-$s+1);
    @$a[$s+$k..$t, $s..$s+$k-1] = @$a[$s..$t];
}


결과
before 1 2 3 4 5 6 7 8
after 1 2 6 7 3 4 5 8

2012/05/20

석가탄신일 달력 2012 기고 "Inline모듈을 사용하여 Perl의 성능 극복하기 - 몬테카를로 시뮬레이션"

JEEN군이

[ 부처님오신날 기념 달력 이벤트 ] 펄 커뮤니티에 올리는 제안


와 같은 취지로 부처님오신날 기념 달력도 만들어 보자고 분위기를 띄우길래
"Inline모듈을 사용하여 Perl의 성능 극복하기 - 몬테카를로 시뮬레이션" 이라는
제목으로 하나 적어봤습니다.

perl-kr 부처님오신날 기념 달력 2012 의 메인 페이지는 -> 여기

달력의 디자인과 와꾸를 만드는데 신경써주신 JEEN군과 pung96님에게 감사를...

2011/12/26

윈도우에서 Perl어플리케이션 배포

윈도우즈에서 Perl어플리케이션을 만들어 배포하는 방법에는 PAR::Packer 모듈을 쓰는 방법 상용 패키징 툴인 Activestate사의 PerlApp등을 쓰는 방법이 있다. 하지만 패키징시 필요없는 것을 너무 많이넣어 용량이 커지거나 초기실행시 내부적인 압축해제절차에 의해 속도가 느리거나 등등 단지 하나의 실행파일을 만들지 않을 것이면 패키징 하기위해 갖추어야 하는 노력이나 비용등에서 너무 오버인거 아닌가 하는 생각이 들곤한다.

예전 부터 생각하던 패키징 방식은 필요한 Perl관련 파일만을 추려서 디렉토리구조를 그대로 가져가고 간단한 .exe형태의 launcher를 만들어 그것을 실행하면 주변 환경변수라든지 모듈경로라든지 등등을 알아서 세팅한 다음 프로그램을 실행시키는 구조이다. http://perl-node-interface.blogspot.com/2011/03/deploy-perl-application-on-windows.html 에서 설명하는 방식이 그런 방식인데 저기서도 꼭 필요한 파일만 어떻게 정확하게 추려낼 것인가에 대한 방법은 완벽하지 않다.

그러면 꼭 필요한 파일을 어떻게 추려낼것인가? 를 고민하다 Windows에서 LINUX의 strace같은 프로그램이 있다면 특정 Perl스크립트를 실행시켰을때 파일을 접근하는 시스템콜을 모두 추적하면 정말 필요한 파일만 골라낼 수 있지 않을까는 생각에 Windows에서 strace같은 기능을 하는 프로그램들을 검색해보고 일일히 테스트해 보았는데 http://www.howzatt.demon.co.uk/NtTrace/ 라는 프로그램이 제일 원하는 대로 동작을 했다. 우선 패키징 작업전에 해당 싸이트에서 적절한 바이너리를 받는다.( 본인은 Windows 7 x64를 쓰기 때문에 64bit 버젼으로 받았다.)

패키징을 테스트하기 위해서 GUI면서 적절한 의존 모듈을 포함한 Perl프로그램이 좋겠다 싶어 Win32::GUI와 OpenGL에 의존성을 가진 스크립트를 선정했다. 해당 소스는 http://www.mail-archive.com/perl-win32-gui-users@lists.sourceforge.net/msg05673.html 에 있다. 일단 패키징할 Perl스크립트를 win32_opengl.pl 파일이라고 하겠다.

이제 win32_opengl.pl 파일이 실행될때 필요로 하는 Perl관련 파일들은 뽑아내보자. Nttrace 프로그램을 이용해서

NtTrace -filter File perl win32_opengl.pl > out.txt

처럼 명령을 내리면 perl win32_opengl.pl 파일이 실행되면서 접근하는 모든 파일관련 시스템콜들이 out.txt에 저장된다.
프로그램이 떠서 잘 돌아갈때 까지 기다렸다가 접근할 파일이 이제 더 이상 없겠다싶으면 그냥 종료하면 된다. (만약에 동적으로 모듈을 로딩하거나 하는 기능이 있으면 그런 것도 추적되도록 모든 기능을 시험적으로 사용후 종료하길 추천)

이제 out.txt 파일 안을 열어 보면 다음과 같이 온갖 다양한 시스템콜들이 기록되어 있다.

NtCreateFile( FileHandle=0x8e2e8 [0x78], DesiredAccess=SYNCHRONIZE|GENERIC_READ|0x80, ObjectAttributes="\??\C:\Windows\Globalization\Sorting\sortdefault.nls", IoStatusBlock=0x8e300 [0/1], AllocationSize=null, FileAttributes=0x80, ShareAccess=1, CreateDisposition=0x1, CreateOptions=0x60, EaBuffer=null, EaLength=0 ) => 0
NtQueryAttributesFile( ObjectAttributes="\??\C:\strawberry-perl-5.12.3.0-portable\perl\site\5.12.3\lib", Attributes=0x8e308 ) => 0xc000003a [3 '지정된 경로를 찾을 수 없습니다.']
NtQueryAttributesFile( ObjectAttributes="\??\C:\strawberry-perl-5.12.3.0-portable\perl\site\lib", Attributes=0x8e308 [DIRECTORY] ) => 0
NtQueryAttributesFile( ObjectAttributes="\??\C:\strawberry-perl-5.12.3.0-portable\perl\site\5.12.3\lib", Attributes=0x8e308 ) => 0xc000003a [3 '지정된 경로를 찾을 수 없습니다.']
NtQueryAttributesFile( ObjectAttributes="\??\C:\strawberry-perl-5.12.3.0-portable\perl\site\lib", Attributes=0x8e308 [DIRECTORY] ) => 0

이제 여기서 필요한 것들은 자기가 쓰고있는 Perl의 base경로를 포함한 파일들이다. 시스템콜 추적 로그파일인 out.txt 에서 필요한 파일을 현재 디렉토리 아래의 dist란 디렉토리를 만들어 뽑아내는 make_dist.pl Perl스크립트를 만들어 보면 다음과 같다.

#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;

my $perl_path = qr/C:\\strawberry-perl-5.12.3.0-portable\\perl\\/;
my %files;
open my $fh , '<', 'out.txt' or die;
while (my $line = <$fh>) {
    $files{$1}=1 if $line =~ m{($perl_path.*?)".*?=> 0$};
}   

foreach my $file (sort keys %files) {
    next if -d $file;
    my $dest = $file;
    $dest =~ s/$perl_path//;
    say "$file -> $dest";
    system(qq{echo f | xcopy /C "$file" .\\dist\\"$dest"});
}

위에서 $perl_path 변수를 자기 환경에 맞게 바꾸면 된다.

perl make_dist.pl

이라고 명령을 내리면 현재 디렉토리 아래 dist란 디렉토리가 생기면서 strawberry perl이면

bin, lib , site, vendor 같은 디렉토리구조 안에 필요한 파일들만 추려져서 뽑혀져 있을 것이다.( Win32, OpenGL을 사용하는 간단한 GUI어플의 경우 4MB가 약간 넘는 양으로, PAR나 PerlApp들이 패키징하는 용량에 비하면 아주 필요한 파일만 슬림하게 뽑혀졌음을 알 수 있다.)
이 까지 작업이 끝나면 메인 스크립트인 win32_opengl.pl 과 dist\bin 과 dist\site\bin 디렉토리의 안의 모든 파일은 dist 디렉토리로 옮기자. (빈 bin 디렉토리들은 지워도 상관없음)


이제 .exe 형태의 launcher를 만들 차례다. 하지만 .exe 형태의 launcher가 필요하지 않다면 그냥 dist디렉토리에 launch.bat 이란 적절한 batch파일로 다음과 같은 내용으로 만들고 실행하면 깔끔하게 실행된다.

set PATH=.;%PATH%
perl win32_opengl.pl

그렇지만 .exe 형태로 아이콘모양도 넣고 제공해야 뭔가 일을 제대로 하는 것 같다면 약간 험난한 길을 더 걸어야 한다. 아래와 같은 명령을 내리면 perlxsi.c 라는 파일이 만들어진다. (이 작업은 dist디렉토리에서 하면 추려진 perl로 동작하므로 dist 디렉토리에서 하지 말것!)


perl -MExtUtils::Embed -e xsinit

만들어진 perlxsi.c 파일을 열어서 상단에 #include <windows.h> 와 메인 스크립트 이름을 넣는 부분과 /* Appended code */ 아랫부분을 아래와 같이 추가하고 저장한다음
( #define SRC_NAME "win32_opengl.pl" 라인이 자기의 메인 스크립트 이름을 지정하는 것)

#include <EXTERN.h>
#include <perl.h>
#include <windows.h>

/* main script name */
#define SRC_NAME "win32_opengl.pl"

EXTERN_C void xs_init (pTHX);

EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
EXTERN_C void boot_Win32CORE (pTHX_ CV* cv);

EXTERN_C void
xs_init(pTHX)
{
 char *file = __FILE__;
 dXSUB_SYS;

 /* DynaLoader is a special case */
 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
 newXS("Win32CORE::bootstrap", boot_Win32CORE, file);
}

/* Appended code */
static PerlInterpreter *my_perl; /*** The Perl interpreter ***/
int main(int argc, char **argv, char **env)
{
    char bin_path[MAX_PATH];
    char *pos; // work string.
    int n;
    /* unshift argv for reserving the original arguments */
    argv[argc] = strdup(argv[argc-1]);
    for(n=argc; n>1; n--) {
        argv[n] = argv[n-1];
    }

    if (!GetModuleFileName(NULL, bin_path, MAX_PATH)) return 1;
    pos = strrchr(bin_path, '\\'); /* the last occurrence of '\\' */
    if (!pos) return 2;            /* not found */
    pos[0] = '\\';
    pos[1] = '\0';
    /* check for MAX_PATH limit overflow */
    if ( strlen(bin_path)+strlen(SRC_NAME)+1 > MAX_PATH ) return 3;

    strcpy(pos + 1, SRC_NAME);

    argv[1] = bin_path;
    argc++;
 
    PERL_SYS_INIT3(&argc,&argv,&env);
    my_perl = perl_alloc();
    perl_construct(my_perl);
    PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
    perl_parse(my_perl, xs_init, argc, argv, (char **)NULL);
    perl_run(my_perl);
    perl_destruct(my_perl);
    perl_free(my_perl);
    PERL_SYS_TERM();
}


이제 이 c소스를 컴파일 해보자.(strawberry perl이면 gcc가 기본으로 포함되어 있고 Activestate Perl이면 ppm install MingGW 명령으로 gcc를 설치할 수 있다.)

gcc -Wall -mwindows -o launch.exe perlxsi.c [이 뒤에는 아래 명령에 의해 나오는 출력결과(컴파일 옵션)들을 각각 긁어 붙인다.

perl -MExtUtils::Embed -e ccopts
perl -MExtUtils::Embed -e ldopts


본인의 경우 컴파일 명령은 다음과 같았다.(실행파일명은 -o 옵션뒤에 원하는 이름으로 하면 됨)

gcc -Wall -mwindows -o launch.exe perlxsi.c -s -O2 -DWIN32 -DHAVE_DES_FCRYPT  -DUSE_SITECUSTOMIZE -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -fno-strict-aliasing -mms-bitfields -DPERL_MSVCRT_READFIX  -I"C:\strawberry-perl-5.12.3.0-portable\perl\lib\CORE" -s -L"C:\strawberry-perl-5.12.3.0-portable\perl\lib\CORE" -L"C:\strawberry-perl-5.12.3.0-portable\c\lib"  C:\strawberry-perl-5.12.3.0-portable\perl\lib\CORE\libperl512.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libmoldname.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libkernel32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libuser32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libgdi32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libwinspool.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libcomdlg32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libadvapi32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libshell32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libole32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\liboleaut32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libnetapi32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libuuid.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libws2_32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libmpr.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libwinmm.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libversion.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libodbc32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libodbccp32.a C:\strawberry-perl-5.12.3.0-portable\c\i686-w64-mingw32\lib\libcomctl32.a

컴파일 결과로 launch.exe 가 생성되면 해당 파일을 dist 디렉토리로 옮긴다. 이제 launch.exe를 실행해 보자.



짠! 잘 실행된다.



만약 launch.exe에 특정 icon을 넣고 싶으면 http://perl-node-interface.blogspot.com/2011/03/deploy-perl-application-on-windows.html 의 설명대로 적절한 리소스 .rc파일을 만들어서 windres 명령으로 오브젝트 파일로 만든다음 컴파일시 추가하여 해도 되고 그것이 귀찮으면 원하는ico파일을 Win32::Exe 모듈을 깐다음 exe_update(  https://metacpan.org/module/exe_update.pl )을 써서

exe_update --icon=my.ico launch.exe

명령을 통해 쉽게 추가할 수 있다.

이제 모든게 끝났다. 이제 배포는 dist 디렉토리이름을 적절하게 바꾼다음 zip으로 묶어서 배포하고 사용자는 그냥 zip파일을 풀고 .exe파일만 실행시키면 그만이다.

<작업이 끝난 디렉토리 내부 모양>


추가 참고사항:

* dist디렉토리안의 perl.exe는 위에서 batch 파일을 통한 실행시는 필요하지만 별도로 만든 .exe 실행파일형태의 launcher를 통해 실행시키면 직접 perl dll을 로딩하여 사용하기 때문에 지워도 상관없다.
* 위 절차로 만들어진 .exe파일은 기본적으로 명령 콘솔을 사용하지 않는다. 만약 콘솔을 보이게 하려면 위에서 말한 exe_update 명령으로
  exe_update -c launch.exe 로 콘솔창이 보이게 exe_update -g launch.exe 로 콘솔창이 안보이게 바꿀 수 있다.
* 다 쓰고 생각해보니 launch.exe는 메인스크립트 이름을 main.pl 정도로 통일하면 아이콘이랑 실행파일 이름은 임의로 바꿔서 계속 재사용 할 수 있을듯.

2011/12/14

Perl, Python, Ruby, PHP, C, C++, Lua, tcl, javascript, Java 성능비교

각종언어에 대한 벤치마크 비교

포커스가 문자열을 얼마나 빠르고 메모리 효율적으로 처리하느냐에 맞춰져 있는데..

이렇게 비교를 한 이유가 대부분의 현대적 어플리케이션의 주작업은 문자열을 다루는 것이며
수치계산은 하드웨어 의존적인 면이 있고 컴파일된 native한 코드가 아닌경우 어떤 언어라도
많은 계산을 하기에는 충분히 성능이 나지 않기 때문에 빠른 계산이 필요하다면 컴파일된
native한 코드를 쓰던지 써드파티 수치계산 라이브러리를 각 언어에 붙여 쓰게 되는데
그렇게 하면 언어간 비교가 아니라 수치계산라이브러리의 성능비교가 되기 때문에
의미가 없다.... 뭐 이렇다고 함

성능비교뿐만 아니라 끝부분에 각 언어에 대한 비평도 읽어볼만 함..

http://onlyjob.blogspot.com/2011/03/perl5-python-ruby-php-c-c-lua-tcl.html

속도에서는 스크립트 언어인 Perl이 C/C++보다 더 빠르다는게 신기..
Java는 의외로 실망스런수준이고(아마도 Buffered String을 쓰면 그나마 나아지리라 생각하지만....)

* 제일 빠른 Perl속도를 1로 했을때 언어별 상대적 속도 비교표(숫자가 작을수록 빠름)

Line size KibPerl5PHPRubyPythonC++ (g++)C (gcc)Javascript (V8)Javascript (sm)Python3tclLuaJava (openJDK)Java (Sun)Java (gcj)
Average:13.845.215.593.891.233.2319.6613.9221.3534.3631.1631.12247.32