오랜만에 코딩

과제 시즌이 끝나자마자 code는 온데간데 없고 talk만 남아버린 코톡의 밸런스를 맞추기 위해 혜성처럼 등장한 최저 학력 완장 바보털입니다.

요즘은 Rust와 통계를 좀 보고있어서, Rust로 학습한 내용들을 구현해 보고 있습니다. 일단 간단한 것부터…

type Real = f64;
type Matrix< T > = Vec< Vec< T > >;

struct Nya {
    size: usize,
    count: usize,
    e1: Vec< Real >,
    e2: Matrix< Real >
}

impl Nya {
    pub fn new(size: usize) -> Self {
        Nya {
            size,
            count: 0,
            e1: vec![0.0; size],
            e2: vec![vec![0.0; size]; size]
        }
    }

    fn put(&mut self, val: &[Real]) -> &mut Self {
        for i in 0..self.size {
            self.e1[ i ] += val[ i ];

            for j in 0..self.size {
                self.e2[ i ][ j ] += val[ i ] * val[ j ];
            }
        }

        self.count += 1;
        self
    }

    fn mean(&self, val: usize) -> Real {
        self.e1[ val ] / self.count as Real
    }

    fn cov(&self, v1: usize, v2: usize) -> Real {
        (self.e2[ v1 ][ v2 ] - self.e1[ v1 ] * self.e1[ v2 ] / self.count as Real) / self.count as Real
    }

    fn cov_matrix(&self) -> Matrix< Real > {
        let mut ret = vec![vec![0.0; self.size]; self.size];

        for i in 0..self.size {
            for j in 0..self.size {
                ret[ i ][ j ] = self.cov(i, j);
            }
        }

        ret
    }

    fn cor(&self, v1: usize, v2: usize) -> Real {
        self.cov(v1, v2) / (self.var(v1) * self.var(v2)).sqrt()
    }

    fn var(&self, val: usize) -> Real {
        self.cov(val, val)
    }

    fn std(&self, val: usize) -> Real {
        self.var(val).sqrt()
    }
}

fn main() {
    let mut nya = Nya::new(2);

    nya.put(&[- 6.0, - 7.0])
       .put(&[  8.0, - 5.0])
       .put(&[- 4.0,   7.0])
       .put(&[ 10.0,   9.0]);

    println!("E(X1) = {}", nya.mean(0));
    println!("V(X1) = {}", nya.var(0));
    println!("E(X2) = {}", nya.mean(1));
    println!("V(X2) = {}", nya.var(1));
    println!("COV(X1, X2) = {}", nya.cov(0, 1));
    println!("COR(X1, X2) = {}", nya.cor(0, 1));

    for i in 0..nya.size {
        for j in 0..nya.size {
            print!("{} ", nya.cov_matrix()[ i ][ j ]);
        }

        print!("\n");
    }
}

출력:

E(X1) = 2
V(X1) = 50
E(X2) = 1
V(X2) = 50
COV(X1, X2) = 14
COR(X1, X2) = 0.28
50 14 
14 50

  • 느낀점 1

짜고 보니 어디서 많이 본 느낌이다 싶었는데,


어쨌든 다른거임.


  • 느낀점 2

딱히 Rust의 장점을 살리는 구현은 아닌 것 같으나, 그렇다고 해서 Rust의 장점을 살릴 여지가 있던 것 같지는 않았던 것 같습니다. 이 부분은 아직 제가 러린이라 그런 것일 수도 있으니, 고수분들께서 피드백해 주시면 정말 감사하겠습니다ㅠㅠ


  • 느낀점 3

소유권의 난이도에 대한 악명은 다소 과장되었다고 생각합니다. 다만, 라이프타임 명시는 쓰면 쓸수록 미궁에 빠지는 느낌입니다. 익숙해질 필요가 있겠습니다.


  • 느낀점 4

같은 동작을 하는 코드에 대해 Rust는 C++보다 장황합니다. 문법적 설탕의 많고 적음을 떠나, Rust는 C++보다 많은 것을 명시하도록 강제합니다. mut, 명시적 형변환, 라이프타임, 변수 선언 등… 이는 컴파일 타임에 최대한 많은 에러를 캐치하기 위함이라는데, C++처럼 프로그래머를 전적으로 신뢰하는 언어에 익숙해져 있다면, Rust에 적응하는 내내 답답한 기분이 들 것입니다.


  • 느낀점 5

반면 구문과 표현식의 개념, 열거형, match 등은 C++보다 훨씬 낫습니다. 값을 복사할 때도 명시적으로 clone 메서드를 호출하는 것이 기본 동작인데, 이는 자원이 어디서 새는지 쉽게 추적 및 수정할 수 있게 해줍니다.


  • 느낀점 6

Rust는 C++을 대체하는 언어가 아닙니다. 아직 컴파일러 최적화의 정도도 미숙하고, 컴파일 타임에 할 수 있는 작업도 다소 한정적입니다. 캐시 히트를 비교 분석한 글도 있던데… 물론 나중에는 상황이 어떻게 바뀔지 모릅니다.


  • 느낀점 7

사실 비선형(다항식) 최소제곱법 회귀도 구현하고 싶었는데, 야코비안과 뉴턴 방법으로 연립 방정식을 푸는 건… 나중에 기회가 되면 해보겠습니다. 배보다 배꼽이 더 큰 느낌입니다.


  • 느낀점 8

내일 8시에 면접인데 이러고 있는 내 인생이 레전드다!!!

7 Likes

C++도 프로그래머 좀 못믿지 않나영?

식고자요

흠… 처음보는 구문들이 대충 읽히는것이
아주 변태스러운 문법은 아니네요.요새 러스트 잘 나가고 있는데, 저한텐 아직 필요가 없군요.

@hahaahha
C보다야 그렇겠지만 Rust에 비할 바는 못된다고 생각합니다.

@sh
고것은 제가 원시 자료형만 써서 그렇읍니다. 홀홀…