본문 바로가기

Programming/NEON

[NEON] 수학, 이항, 스칼라 연산

1. 수학연산

NEON에서는 수학 함수로 역수와 역수 제곱근에 관련된 함수를 제공한다. (제곱근 함수는 지원하지 않는다.)


1.1 역수 함수

벡터의 각 레인에 대해서 역수를 계산한다.


float32x4_t r = vrecpeq_f32(float32x4_t a)


1을 레인의 값으로 나누고 그 결과를 저장한다.


1.2 역수 제곱근 함수

벡터의 각 레인에 대해서 제곱근의 역수 값을 계산한다.

float32x4_t r = vrsqrteq_f32(float32x4_t a)

레인의 제곱근 값으로 나누고 그 결과를 저장한다. 수식으로 풀면 r = 1/sqrt(a)


1.3 역수 확장 함수

2에서 두 벡터의 레인 사이의 곱하기 연산 결과를 뺀다. 이를 식으로 나타내면 r = 2 - (a * b)와 같다.

 float32x2_t vrecps_f32(float32x2_t a, float32x2_t b) - 실수 32bit 2개

 float32x4_t vrecps_f32(float32x4_t a, float32x4_t b) - 실수 32bit 4개


1.4 역수 제곱근 확장 함수

3에서 두 벡터의 레인 사이의 곱하기 연산 결과를 빼고, 그 결과를 2로 나누어 저장한다.

이를 식으로 나타내면 r = (3 - (a*b)))/2

 float32x2_t vrsqrts_f32(float32x2_t a, float32x2_t b) - 실수 32bit 2개

 float32x4_t vrsqrts_f32(float32x4_t a, float32x4_t b) - 실수 32bit 4개


NEON의 역수 확장 함수를 이용하면 Newton-Raphson 알고리즘을 구현 할수 있다.


1.5 역수를 이용한 나누기 연산

역수를 이용하면 나누기를 구현할수 있다.


X / N = X (1 / N)


X / N의 결과는 X * (1 / N) 과 같으므로 X / N = X * (1 / N)이 성립한다.

이 공식을 이용하면 곱하기와 역수로 나누기를 구할수 있다.

10나누기 2를 이 공식으로 나타내면 다음과 같다.


2. NEON 이항 연산

2.1 벡터 교환 함수

단일 벡터 사이에 레인 값을 교환하고 복수 벡터에 결과를 저장한다.


int8x8_t r = vtrn_s8(int8x8_t a, int8x8_t b)


2.2 인터리브와 디인터리브

인터리브와 디인터리브를 이해하면 앞에서 다룬 복수 벡터의 로드와 저장 연산 방식을 이해 할수 있게 된다. 복수 벡터로 메모리 데이터를 로드할 때는 인터리브(Interleave)가 적용되고, 메모리 데이터에 복수 벡터를 저장할 때는 디인터리브(De-Interleave)가 자동으로 적용된다. 여기에서 메모리 데이터는 배열을 의미한다.

예를 들어 RGB 이미지 메모리를 uint8x8x3_t 형식의 복수 벡터에 로드하면 R, G, B 데이터가 val[0], val[1], val[2]에 각각 로드된다. 이렇게 메모리가 벡터에 분할되어 로드되는 것을 인터리브라고 한다.

반대로 uint8x8x3_t 형식의 벡터를 메모리로 저장하는 경우 val[0], val[1], val[2]에 포함된 R, G, B데이터가 메모리에 각각 저장되는 것을 인터리브라고 한다. 디인터리브는 인터리브의 반대이다.

RGB 데이터는 이미지 데이터 포맷으로 멀티미디어에 사용되는데, NEON은 이와 같은 연산을 지원하여 멀티미디어를 처리하는 데 최적화되어 있으므로, 개발자가 이미지 데이터를 처리하는 애플리케이션을 제작하기 수월하다.


벡터 인터리브

두개의 벡터를 하나의 복수 벡터에 저장한다.


int8x8x2_t r = vzip_s8(int8x8_t a, int8x8_t b)

두 개의 메모리 데이터가 복수 벡터에 대입될 때 1개 레인을 건너가며 저장된다.


벡터 디 인터리브

디인터리브는 인터리브와 마찬가지로 두 개의 단일 벡터를 하나의 복수 벡터에 저장하지만, 저장하는 방식이 다르다.

int8x8x2_t r = vuzp_s8(int8x8_t a, int8x8_t b)


두 개의 벡터가 복수 벡터에 대입될 때 val[0]과 val[1]에 교대로 저장된다. 

현재까지 NEON의 벡터 인터리브와 벡터 디 인터리브는 2개의 단일 벡터만 연산이 가능하다.


3. NEON 스칼라 연산

NEON에서 스칼라(Scalar)는 벡터에 포함된 여러 레인 중에서 하나의 레인만을 참조하거나 하나의 일반 변수를 이용하여 벡터의 여러 레인을 참조하는 것을 말한다. 스칼라에 사용되는 값은 16비트 또는 32비트, 64비트 값이 될 수 있다. NEON에는 여러 가지 스칼라 연산이 있지만 대부분 곱하기 연산에 특화되어 있다.


3.1 스칼라 곱하기

벡터의 모든 레인을 하나의 값으로 곱한다.

int16x4_t r = vmul_n_s16(int16x4_t a, int16_t b)


3.2 스칼라 벡터 Long 곱하기

두 개의 벡터에서 특정 레인을 이용한 곱하기 연산이다.


int32x4_t r = vmull_lane_s16(int16x4_t a, int16x4_t b, __constrange(0, 3) int c)

일반 변수 c로 벡터 b의 레인 중에서 하나의 레인을 선택한다. 

선택된 레인으로 벡터 a의 각레인을 곱하여 결과를 쿼드 워드 벡터 r에 저장한다.


3.3 스칼라 곱하기 누계

스칼라 곱하기 연산 결과에 벡터 더하기 연산을 실행


int16x4_t r = vmla_n_s16(int16x4_t a, int16x4_t b, int16_t c)


b 벡터의 각 레인에 c를 곱한뒤 벡터 a와 각 레인을 더해 벡터 r에 저장한다.(r = (b * c) + a)


3.4 스칼라 벡터 곱하기 누계

스칼라 벡터 곱하기 연산 결과에 벡터 더하기 연산을 실행한다.


int16x4_t r = vmla_lane_s16(int16x4_t a, int16x4_t b, int16x4_t v, __constrange(0, 3) int l)


벡터 b와 v에 스칼라 벡터 곱하기 연산을 실행한다.

벡터 b의 각 레인에 벡터 v의 l번째 값과 곱한뒤 벡터 a의 각 레인값과 더한뒤 벡터 r에 저장

'Programming > NEON' 카테고리의 다른 글

[NEON] 변환 연산  (0) 2016.09.23
[NEON] 비교 연산과 절대값  (0) 2016.09.23
[NEON] 비트와 시프트 연산  (0) 2016.09.23
[NEON] 레인 설정과 조회  (0) 2016.09.23
[NEON 산술 연산과 확장  (0) 2016.09.23