Menu

R의 숫자: numeric, integer와 수학 함수

R에서 숫자를 다루는 방법입니다. numeric과 integer의 차이, 반올림 함수들, sqrt와 log, %% 나머지 연산자, 그리고 특수값 Inf와 NaN을 다룹니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

numeric과 integer: R의 두 가지 숫자 타입

R은 숫자를 두 가지 방식으로 저장합니다. numeric(배정밀도 부동소수점으로 저장)이 기본값이라, 따로 지정하지 않는 한 여러분이 입력하는 모든 숫자는 double입니다. integerL 접미사로 요청하는 별도의 정확한 정수 타입입니다.

실무에서는 신경 쓸 일이 드뭅니다. R이 조용히 둘 사이를 변환해 주고 is.numeric()은 둘 다에 대해 TRUE이기 때문입니다(전체 타입 체계는 데이터 타입 참고). 이 구분이 드러나는 한 곳은 나눗셈입니다. /는 정수 둘 사이에서도 항상 double을 돌려줍니다.

정수는 주로 세는 함수(length(), seq_len(), nrow())의 출력과 인덱스 값으로 나타납니다. 정수 나눗셈이 필요하다면 R에는 전용 연산자가 있으며, 아래에서 다룹니다.

반올림 함수들

R은 숫자를 다듬는 다섯 가지 방법을 제공하며, 각각 의미가 다릅니다.

  • round(x, digits) - 지정한 소수 자릿수로 반올림합니다(기본값 0).
  • floor(x) - 가장 가까운 정수로 내리되, 항상 음의 무한대 방향입니다.
  • ceiling(x) - 올리되, 항상 양의 무한대 방향입니다.
  • trunc(x) - 소수를 잘라 내되, 항상 0 방향입니다. 음수에서 차이가 납니다. trunc(-2.7)-2이지만 floor(-2.7)-3입니다.
  • signif(x, digits) - 소수 자릿수가 아니라 유효숫자 개수에 맞춥니다. signif(123456, 2)120000입니다.

그리고 유명한 놀라움이 하나 있습니다. round()는 IEEE 754 표준에 따라 정확히 절반인 값에 짝수로 반올림(은행가 반올림)을 적용합니다.

출력은 0 2 2 4입니다. 각 절반이 가장 가까운 짝수로 반올림됩니다. 버그가 아닙니다. 반올림한 값을 많이 합할 때 체계적으로 위로 치우치는 것을 막아 줍니다. 보고서에 학교식 반올림이 필요하다면 아주 작은 값을 더하거나 표현 계층에서 형식을 지정하세요.

일상적인 수학 함수

기본적인 것들은 예상 그대로 동작합니다.

sqrt()는 제곱근, abs()는 절댓값, ^는 거듭제곱, exp(x)ex제곱입니다. 그래서 exp(1)은 오일러 수, 약 2.718282입니다.

사람들이 걸려 넘어지는 함수는 log()입니다. R에서 log()는 밑이 10이 아니라 자연로그(밑이 e)입니다.

첫 줄은 약 4.60517을 출력합니다. 밑 10을 기대한 사람이 예상하는 2가 아닙니다. 그 밑들을 의도한다면 log10()log2()를 쓰거나 base =를 명시적으로 전달하세요. (이 관례는 자연로그가 기본인 통계학 전반의 표준입니다.)

나머지 %%와 정수 나눗셈 %/%

두 연산자가 나머지 산술을 담당합니다.

%%나머지입니다. 17을 5로 나누면 몫이 3이고 나머지가 2입니다. %/%정수 나눗셈으로, 17 안에 5가 몇 번 온전히 들어가는지를 알려 줍니다. 둘은 함께 x == (x %/% y) * y + (x %% y)를 만족합니다.

%%의 고전적인 용도는 나누어떨어지는지 확인하는 것입니다.

음수에서 미묘한 점이 하나 있습니다. R의 %%는 (C와 달리 Python처럼) 제수의 부호를 따릅니다.

결과는 -1이 아니라 2입니다. R은 "3의 배수에 무엇을 더하면 -7에 도달하는가?"에 답하며, 제수가 양수이면 결과를 0..2 범위에 유지합니다. 인덱스를 순환시킬 때 유용하지만, C나 Java에서 왔다면 놀랄 수 있습니다.

특수값: Inf, -Inf, NaN

R의 숫자는 IEEE 754를 따르므로 어떤 연산은 오류 대신 특수값을 만들어 냅니다.

1/0Inf(무한대), -1/0-Inf, 그리고 진짜로 정의되지 않은 양인 0/0은 "숫자가 아님"을 뜻하는 NaN입니다. 이 구분은 중요합니다. Inf는 답("무엇보다도 크다")이고 NaN은 답이 없음입니다. == NaN은 결코 동작하지 않으므로 전용 함수로 검사합니다.

마지막 줄을 눈여겨보세요. NaNNA로 취급되므로 is.na()가 이를 잡아냅니다. is.na()가 "이 값이 쓸 수 없는가?"를 확인하는 표준 방법인 또 하나의 이유입니다(결측값에서 더 다룹니다).

R은 지수 표기법도 그대로 읽고 씁니다. 2.5e3은 2500이고, 아주 작거나 큰 수는 기본적으로 e 표기로 출력됩니다.

보고서에 일반 소수 표기가 필요하다면 format(x, scientific = FALSE)(또는 scipen 옵션)를 사용하세요.

부동소수점의 놀라움

소수를 이진법으로 저장하는 모든 언어가 공유하는 문제이고, R도 예외가 아닙니다.

FALSE입니다. 0.1 + 0.2가 실제로는 0.30000000000000004이기 때문입니다. 0.1도 0.2도 정확한 이진 표현이 없고, 아주 작은 오차가 쌓입니다. R의 기본 출력은 유효숫자 7자리만 보여 주기 때문에 이 문제를 감추고, 그래서 == 비교가 실패하기 전까지는 보이지 않는 것처럼 느껴집니다.

규칙은 이것입니다. 계산된 소수를 ==로 비교하지 마세요. 합리적인 허용 오차 안에서 비교하는 all.equal()을 사용하세요.

isTRUE()로 감싸는 이유는 값이 다를 때 all.equal()FALSE가 아니라 차이에 대한 설명을 돌려주기 때문입니다. 정확성이 중요한 정수 작업이라면, 정수는 약 21억까지 정확합니다. 세는 코드가 정수 타입을 쓰는 또 하나의 이유입니다.

핵심 정리

  • 입력하는 모든 숫자는 double입니다. 42L은 정수를 만들고, /는 어느 경우든 double을 돌려줍니다.
  • round()는 절반을 짝수로 반올림하고, floor/ceiling/trunc/signif는 각각 다르게 다듬습니다. 어느 것을 의도하는지 알고 쓰세요.
  • log()자연로그입니다. 다른 밑에는 log10(), log2(), 또는 base =를 쓰세요.
  • %%는 나머지를(부호는 제수를 따릅니다), %/%는 정수 몫을 줍니다.
  • 1/0Inf, 0/0NaN이고 0.1 + 0.2 != 0.3입니다. 소수는 ==가 아니라 all.equal()로 비교하세요.

다음 순서는 일상 데이터의 나머지 절반인 문자열, 그리고 이를 만들고 서식화하고 검색하기 위해 R이 제공하는 함수들입니다.

자주 묻는 질문

R에서 numeric과 integer의 차이는 무엇인가요?

numeric(double)은 여러분이 입력하는 모든 숫자의 기본값입니다. 42는 정수처럼 보여도 double입니다. integer는 L 접미사로 요청하는 별도의 저장 타입입니다(42L). 일반 나눗셈은 정수끼리라도 항상 double을 돌려주므로, 정수 나눗셈에는 %/%를 쓰세요.

R의 log()는 자연로그인가요?

네. R의 log(x)는 밑이 10이 아니라 자연로그(밑이 e)입니다. 밑 10에는 log10(), 밑 2에는 log2(), 임의의 밑에는 log(x, base = b)를 쓰세요. log(100)은 2가 아니라 약 4.605입니다.

R에서 round()는 어떻게 동작하나요?

round(x, digits)는 지정한 소수 자릿수로 반올림하지만, 정확히 절반인 값에는 "짝수로 반올림"(은행가 반올림)을 적용합니다. round(2.5)2이고 round(3.5)4입니다. IEEE 754 표준을 따르며 반올림한 값을 합할 때 편향을 줄여 주지만, 학교에서 배운 반올림을 기대한 사람에게는 놀랍게 느껴집니다.

R에서 0.1 + 0.2가 왜 0.3과 같지 않나요?

double은 이진법으로 저장되는데 0.1, 0.2, 0.3은 정확한 이진 표현이 없습니다. 그래서 0.1 + 0.2는 실제로 0.30000000000000004입니다. 계산된 소수를 ==로 비교하지 마세요. isTRUE(all.equal(x, y))를 쓰거나 abs(x - y) < 1e-9을 확인하세요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기