연산자
- Golang
- 2021년 5월 28일
1. 산술 연산자
구분 | 연산자 | 연산 | 피연산자 타입 |
---|---|---|---|
사칙 연산과 나머지 | + | 덧셈 | 정수, 실수, 복소수, 문자열 |
- | 뺄셈 | 정수, 실수, 복소수 | |
* | 곱셈 | 정수, 실수, 복소수 | |
/ | 나눗셈 | 정수, 실수, 복소수 | |
% | 나머지 | 정수, 실수, 복소수 | |
비트 연산 | & | AND 비트연산 | 정수 |
| | OR비트 연산 | 정수 | |
^ | XOR비트 연산 | 정수 | |
&^ | 비트 클리어 | 정수 | |
시프트 연산 | « | 왼쪽 시프트 | 정수 « 양의 정수 |
» | 오른쪽 시프트 | 정수 » 양의 정수 |
산술 연산은 다른 언어의 연산과 별로 다를 것이 없으며 go는 강타입 언어이기 때문에 반드시 피연산자들끼리의 타입이 같아야만 에러가 발생하지 않는다.
1) ^
a := uint8(1)
fmt.Printf("%08b",a) //00000001
fmt.Printf("%08b",^a) //11111110
비트 연산중에 **^(XOR)**은 혼자쓰이면 비트 반전(1의 보수,NOT)으로 사용될 수 있다.
2) &^
a := uint8(255)
fmt.Printf("%08b \n",a) //11111111
fmt.Printf("%08b \n",a&^2) //11111101
fmt.Printf("%08b \n",a&^8) //11110111
&^ 연산은 비트 클리어연산으로 우측 피연산자를 ^(NOT) 으로 사용된 후 양쪽 피연산자에 대해 & 를 수행한 것으로 왼쪽 피연산자 비트에서 오른족 피연산자의 1의 값을 갖는 위치의 비트를 0으로 바꾸고 싶을 때 사용한다.
3) 시프트 연산
a := uint8(1) //00000001
b := int8(-1) //11111111
fmt.Printf("%08b \n",a<<4) //00010000
fmt.Printf("%08b \n",uint8(b<<4)) //11110000
fmt.Printf("%08b \n",a>>1) //00000000
fmt.Printf("%08b \n",uint8(b>>4)) //11111111
« 연산은 비트를 왼쪽으로 밀고 새로 채우는 비트는 무조건 0으로 채운다.
» 연산은 왼쪽피연산자의 부호에 따라 새로 채우는 비트의 값이 달라지며, 부호가 없는 정수라면 0, 음수라면 1로 채워진다.
2. 비교 연산
연산자 | 설명 |
---|---|
== | 같다 |
!= | 같지 않다 |
< | 작다 |
> | 크다 |
<= | 작거나 같다 |
>= | 크거나 같다 |
1) 실수 비교
a := 0.1
b := 0.2
c := 0.3
d := a+b
fmt.Println(c == d) //false
fmt.Println("c : "+ strconv.FormatFloat(c,'f',-1,64)) //0.3
fmt.Println("d : "+ strconv.FormatFloat(d,'f',-1,64)) //0.30000000000000004
실수 계산시 부동소수점 방식은 오차가 발생할 수 있어 원하는 결과값을 도출해내지 못할 수 있기때문에 특정 범위까지의 오차를 지정해 무시하거나 패키지를 이용해서 정밀하게 연산을 수행하는 방법을 택해야 한다.
특정 범위 지정
const floatRange = 0.000001
func equal(a,b float64) bool{
if a>b{
if a-b > floatRange{
return false;
}
return true;
}else{
if b-a > floatRange {
return false;
}
return true;
}
}
func main() {
a := 0.1
b := 0.2
c := 0.3
d := a+b
fmt.Println(equal(c,d)) //true
}
오차를 허용할 범위를 상수로 선언을 한 후에 별도의 함수를 만들어 비교하는 방법을 이용할 수 있다.
Float객체
import (
"fmt"
"math/big"
)
func main() {
a, _ := new(big.Float).SetString("0.1")
b,_ := new(big.Float).SetString("0.2")
c,_ := new(big.Float).SetString("0.3")
d := new(big.Float).Add(a,b)
fmt.Println(c == d) //false
fmt.Println(c.Cmp(d)) //0
}
big의 Float객체를 이용해서 소수를 표현하고 산술/비교연산을 수행하면 정밀한 오차까지 계산을 수행할 수 있으며, 해당 변수는 객체이기 때문에 == 연산은 false가 되고 값 비교는 Cmp() 메서드를 이용하면 되고 Java의 compareTo와 비슷하게 주체가 크면 1, 작으면 -1, 같으면 0을 반환한다.
3. 논리 연산
종류 | 연산자 | 항 개수 | 설명 |
---|---|---|---|
논리 | && | 다항 연산자 | 양변 모두 true면 true |
| | | 다항 연산자 | 양변 중 하나라도 true면 true | |
! | 단항 연산자 | true이면 false, false이면 true |
func setD(d *int) int{
*d= 3
return *d
}
func main() {
c := 3
d := 0
fmt.Println( true || setD(&d) == c) //true
fmt.Println(d) //0
fmt.Println( false || setD(&d) == c) //true
fmt.Println(d) //3
}
논리 연산시 단락 회로 평가(쇼트 서킷) 로 왼쪽 피연산자가 true나 false조건이 만족한다면 오른쪽 피연산자를 참조하지 않고 바로 return하게 된다.
예를 들어 && 연산을 수행할때 왼쪽 피연산자가 false라면 오른쪽 피연산자의 결과에 상관없이 false를, || 연산은 왼쪽이 true라면 바로 true를 리턴하게 된다.
4. 대입 연산
var a int
var b int
a = b = 1 //error
/*success*/
a = 1
b = 1
대입 연산은 다른 언어들과 거의 동일하며 복합 대입연산자도 지원을 하지만 특정 문법의 제약이 강해 위와 같은 방법으로 대입은 불가능하다.
Reference
『Tucker의 Go 언어 프로그래밍』 스터디 요약 노트