비트(Bit) 단위로 생각하기 (비트 연산)

거의 대부분의 프로그래밍 언어를 학습하다보면 나오는 비트 연산은 이진 파일 포맷 분석, 해시, 암호화 등이 아닐 경우 거의 사용되지 않는다. 그래서인지, 관련 내용을 그냥 눈으로만 보고 이해하거나, 그냥 넘기는 경우가 다반사인데.. 그러다보니 비트연산에 대한 깊이 있는 이해가 수반될 일이 없어 더욱더 비트 연산을 쓸일이 없게 된다.

사실 비트 연산은 매우 최적화된 연산이고, 모든 기능들.. 즉 그 모든 복잡한 기능들을 구성하는 가장 최소 단위라고 할 수 있다. 일단 최적화된 연산이라는 관점에서 그 활용처를 생각해보면, 상태값을 담아두기 위해 저장소로 활용될 수 있는데.. 만약 8개의 상태가 필요할 경우 총 8개의 boolean 타입이 필요하다. 언어에 따라 다르지만 boolean 타입의 변수를 위해 할당하는 메모리의 양은 비트연산을 통해 동일한 기능을 수행하는 것에 비해 엄청난 양의 메모리를 사용하며 그 속도 또한 엄청나게 느리다.

여기서 8개의 상태값을 담아 두는 비트연산 기능을 코드로 들어, 필자 스스로를 위한 비트 연산의 이해를 다져 본다.

8개의 상태값을 담기 위해 부호가 없는 8비트의 정수 변수인 states를 정의하였다. 즉 8개의 상태 값을 저장하기 위해 단 1바이트만을 사용하고 있다. 코드는 이 states 변수의 2번째와 4번째 그리고 7번째를 On으로 하고 나머지는 Off로 상태로 설정하는 코드이다.

var states uint8 = 1 << 1 | 1 << 3 | 1 << 6

이제 이 상태 변수를 통해 4번째의 상태를 파악하기 위해 다음의 코드가 필요하다.

if states&(1<<3) != 0 {
    fmt.Println("index 4 is ON")
}

그리고 상태에서 4번째만을 ON으로 하는 코드는 아래와 같다.

states = states | (1 << 3)

그리고 상태에서 4번째만을 OFF으로 하는 코드는 아래와 같다.

states = states &^ (1 << 3)

끝으로 4번째 상태를 토글(Toggle), 즉 ON이면 OFF로.. OFF면 ON으로 설정하는 코드는 아래와 같다.

states = states &^ (1 << 3)

[Go] fogleman의 Go Graphics 라이브러리

Go는 그 목적이 시스템 및 서버 프로그래밍에 있음으로 그리기(Draw) API는 지원하지 않는다. 그러나 Go 언어에는 이러한 부족한 부분을 채워줄 매우 많은 그래픽 라이브러리 존재하는데, 그 중에 하나가 fogleman이 개발한 Go Graphic 라이브러(https://github.com/fogleman/gg)이다.

아래의 코드는 이 라이브러리를 이용해 필자가 작성한 테스트 코드이다. (사실 이글은 Go 마스터하기 라는 책을 다 보고, 다시 한번 더 볼 요량으로 파일을 정리하던 중에 코드를 이 블로그에 저장하기 위한 목적을 갖는다.)

package main

import "github.com/fogleman/gg"

func main() {
	const S = 256

	dc := gg.NewContext(S, S)

	dc.SetRGB(1, 1, 1)
	dc.Clear()

	if err := dc.LoadFontFace("font.ttf", 36); err != nil {
		panic(err)
	}

	dc.SetRGB(0, 0, 0)

	s := "한글ABC"
	n := 3 // "stroke" size

	for dy := -n; dy <= n; dy++ {
		for dx := -n; dx <= n; dx++ {
			if dx*dx+dy*dy >= n*n {
				// give it rounded corners
				continue
			}
			x := S/2 + float64(dx)
			y := S/2 + float64(dy)
			dc.DrawStringAnchored(s, x, y, 0.5, 0.5)
		}
	}
	dc.SetRGB(1, 1, 0)
	dc.DrawStringAnchored(s, S/2, S/2, 0.5, 0.5)

	dc.SavePNG("out.png")
}

결과는 아래와 같은 out.png 파일을 생성한다는 것이다. 파일로 생성하는 것은 필자의 목적에 맞기 때문인데, 이렇게 생성한 이미지를 네트워크를 타고 클라이언트에 전송되는 것이 목적이다. 또는 캐쉬 되거나…

위의 결과 외에도 이 라이브러리의 개발자가 언급한, 표현 가능한 결과물은 아래와 같으니 참고 바란다.

내용 정리 끝냈으니, 관련 소스 파일은 삭제 .. !

[Go] 슬라이스의 정렬(Slice Sort)

나는 중학교 시절, 마이컴이라는 컴퓨터 잡지에서 동일한 기능을 수행하는 코드를 Basic, Pascal, C, Fortran, Cobol이란 프로그래밍 언어를 통해 비교해서 보여주는 글을 본적이 있다. 수십년전의 기억이지만, 나는 그때 그 짧은 소스코드를 보고 느꼈던 설레임을 아직도 기억한다. (노래 가사가 맞구요;) Go라는 언어가 생생했던 그 설레임을 다시 생동감있게 되살려 준다.

Go에서 대표적인 자료 구조로써 배열과 매우 유사하지만, 그 길이를 동적으로 변경할 수 있다는 이점을 갖는 Slice라는 타입이 있다. 이 슬라이스를 통해 여러개의 데이터를 담아둘 수 있고, 담아둔 데이터들을 목적에 맞게 활용하는데.. 담아둔 여러개의 데이터를 어떤 기준에 맞게 정렬을 해야 할 때가 있다. 이때를 위한 예제 코드를 정리해 본다.

package main

import (
    "fmt"
    "sort"
)

type myDataType struct {
    name string
    age  int
}

func main() {
    mySlice := make([]myDataType, 0)
    mySlice = append(mySlice, myDataType{"김형준", 42})
    mySlice = append(mySlice, myDataType{"홍길동", 28})
    mySlice = append(mySlice, myDataType{"임꺽정", 38})

    fmt.Println(mySlice)

    sort.Slice(mySlice, func(i, j int) bool {
        return mySlice[i].age < mySlice[j].age
    })

    fmt.Println(mySlice)
}

결과는 아래와 같다.

C:/Go/bin/go.exe build [D:/__Working__/tstGo]
Success: process exited with code 0.
D:/__Working__/tstGo/tstGo.exe [D:/__Working__/tstGo]
[{김형준 42} {홍길동 28} {임꺽정 38}]
[{홍길동 28} {임꺽정 38} {김형준 42}]
Success: process exited with code 0.

복합 데이터의 묶음 타입인 구조체를 정의하고 구조체를 정의하는 필드값을 기준으로, 여기서는 나이를 의미하는 age를 통해 오름차순으로 정의하기 위해 익명함수를 사용했다. 코드는 짧지만 곰곰히 코드를 되짚어 볼만한 예제이다.

[golang] 배열을 포인터로 전달하는 함수

Go는 배열을 함수로 전달할때 배열의 전체를 복사한 값 형식으로 함수에 전달합니다. 결국 함수 안에서 해당 배열의 요소를 변경하여도 파라메터로 전달되어진 그 원래의 배열에 변경이 생기지 않습니다. 그러나 이 배열을 포인터로 전달하면 함수 내부에서 변경되는 대상이 원본이므로 변경 내용을 유지됩니다. 아래는 배열을 포인터 타입으로 함수에 전달하는 예제입니다.

package main

import "fmt"

func f(a *[3]int) {
	a[1] = 100
}

func main() {
	a := [3]int{1, 2, 3}

	f(&a)

	fmt.Println(a[1])
}