Float
Float
부동소수점 수를 다루는 함수들을 제공하는 모듈이에요. 부동소수점 위에서의 수학 연산이 필요하다면 Erlang의 :math 모듈을 참고하면 돼요.
출처: Float
본문
Kernel 함수
부동소수점과 관련된 함수는 Kernel 모듈에도 있어요. 목록은 다음과 같아요.
Kernel.round/1— 숫자를 가장 가까운 정수로 반올림해요.Kernel.trunc/1— 숫자의 정수 부분을 돌려줘요.
알려진 문제점 (Known issues)
부동소수점과 산술에는 아주 잘 알려진 문제가 몇 가지 있어요. 대부분의 십진 분수는 이진 부동소수점으로 표현할 수 없고, 대부분의 연산도 정확하지 않아서 근삿값으로 동작하기 때문이에요. 이 문제는 Elixir만의 문제가 아니라 부동소수점 표현 자체의 속성이에요.
예를 들어 0.1과 0.01은 그런 수 중 두 가지예요. 즉 0.1을 제곱해도 0.01이 나오지 않고, 0.01에 가장 가까운 표현 가능한 수도 아니에요. 이 경우 실제로 벌어지는 일을 정리하면 이래요.
0.1에 가장 가까운 표현 가능한 수는0.1000000014예요.0.01에 가장 가까운 표현 가능한 수는0.0099999997이에요.0.1 * 0.1은0.01을 돌려줘야 하지만,0.1이 실제로0.1000000014이므로 결과는0.010000000000000002예요. 그리고 이 값은0.01에 가장 가까운 표현 가능한 수가 아니기 때문에 이 연산의 결과가 틀리게 나와요.
내림이나 반올림과 관련된 다른 알려진 문제도 있어요. 자세한 내용은 round/2와 floor/2 문서를 보면 돼요. 부동소수점 산술에 대해 더 배우고 싶다면 다음 자료를 보세요.
precision_range 타입
정밀도를 나타내는 타입으로, 0..15 범위예요.
@type precision_range() :: 0..15
함수들
ceil/2 — 숫자 이상인 가장 작은 float로 올림해요. ceil/2는 0..15 사이의 임의의 소수 자릿수로 올림할 정밀도도 받아요. 연산은 이진 부동소수점 위에서 수행되고 십진으로 변환하지 않아요. ceil/2의 동작이 놀라울 수 있는데, 예를 들면 이래요.
iex> Float.ceil(-12.52, 2)
-12.51
-12.52로 올림될 거라고 기대할 수도 있어요. 이건 버그가 아니에요. 대부분의 십진 분수는 이진 부동소수점으로 표현할 수 없어서, 위 숫자는 내부적으로 -12.51999999로 표현되기 때문에 이런 동작이 나와요. 이 함수는 항상 float를 돌려줘요. 결과를 정수로 잘라내고 싶다면 Kernel.trunc/1을 쓰면 돼요.
iex> Float.ceil(34.25)
35.0
iex> Float.ceil(-56.5)
-56.0
iex> Float.ceil(34.251, 2)
34.26
iex> Float.ceil(-0.01)
-0.0
floor/2 — 숫자 이하인 가장 큰 float로 내림해요. floor/2도 0..15 사이의 소수 자릿수 정밀도를 받을 수 있어요. 마찬가지로 부동소수점의 표현 특성 때문에 동작이 놀라울 수 있어요.
iex> Float.floor(12.52, 2)
12.51
12.52로 내림될 거라 기대할 수 있는데, 내부적으로 12.51999999로 표현되기 때문이에요. 이 함수는 항상 float를 돌려주고, 정수로 자르려면 Kernel.trunc/1을 쓰면 돼요.
iex> Float.floor(34.25)
34.0
iex> Float.floor(-56.5)
-57.0
iex> Float.floor(34.259, 2)
34.25
max_finite/0 — float의 최대 유한 값을 돌려줘요. 1.7976931348623157e308이에요.
min_finite/0 — float의 최소 유한 값을 돌려줘요. -1.7976931348623157e308이에요.
parse/1 — 바이너리를 float로 파싱해요. 성공하면 {float, remainder_of_binary} 튜플을 돌려주고, 바이너리가 유효한 float로 변환될 수 없으면 :error를 돌려줘요. float의 크기가 최대 크기 1.7976931348623157e+308을 초과하면, 텍스트 표현 자체가 잘 형성되어 있어도 :error를 돌려줘요. 문자열 형태의 float를 바로 float로 변환하고 싶다면 String.to_float/1을 쓰면 돼요.
iex> Float.parse("34")
{34.0, ""}
iex> Float.parse("34.25")
{34.25, ""}
iex> Float.parse("56.5xyz")
{56.5, "xyz"}
iex> Float.parse(".12")
:error
iex> Float.parse("pi")
:error
iex> Float.parse("1.7976931348623159e+308")
:error
pow/2 — base의 exponent 거듭제곱을 계산해요. base는 float여야 하고 exponent는 아무 숫자든 될 수 있어요. 하지만 음수 밑과 분수 지수가 주어지면 ArithmeticError를 던져요. 항상 float를 돌려줘요. 정수를 돌려주는 거듭제곱이 필요하다면 Integer.pow/2를 보세요.
iex> Float.pow(2.0, 10)
1024.0
iex> Float.pow(2.0, -1)
0.5
iex> Float.pow(3.0, 1.5)
5.196152422706632
iex> Float.pow(-2.0, 4)
16.0
iex> Float.pow(-1.0, 0.5)
** (ArithmeticError) bad argument in arithmetic expression
ratio/1 — 원래 float와 정확히 같은 비율이면서 분모가 양수인 정수쌍을 돌려줘요.
iex> Float.ratio(3.14)
{7070651414971679, 2251799813685248}
iex> Float.ratio(1.5)
{3, 2}
iex> Float.ratio(16.0)
{16, 1}
round/2 — 부동소수점 값을 임의의 소수 자릿수(0~15)로 반올림해요. 반올림 방향은 항상 half up(0.5 이상 올림)으로 맞춰져요. 연산은 이진 부동소수점 위에서 수행되고 십진으로 변환하지 않아요. 이 함수는 float만 받고 항상 float를 돌려줘요. float와 정수 모두 받아 항상 정수를 돌려주는 함수가 필요하다면 Kernel.round/1을 쓰세요.
round/2의 동작도 놀라울 수 있어요.
iex> Float.round(5.5675, 3)
5.567
half up 방식으로 5.568이 될 거라 기대할 수 있어요. 이건 버그가 아니에요. 위 숫자는 내부적으로 5.567499999로 표현되기 때문이에요. 십진수에 대한 정확한 반올림이 필요하다면 decimal 라이브러리를 써야 해요.
iex> Float.round(12.5)
13.0
iex> Float.round(5.5675, 3)
5.567
iex> Float.round(-5.5675)
-6.0
to_charlist/1 — 주어진 float의 가장 짧은 텍스트 표현에 해당하는 charlist를 돌려줘요. "Ryū: fast float-to-string conversion"(PLDI 2018)에 제시된 알고리즘을 사용해요. 설정 가능한 표현이 필요하면 :erlang.float_to_list/2를 쓰세요. 컴파일러가 인라인해요.
iex> Float.to_charlist(7.0)
~c"7.0"
to_string/1 — 주어진 float의 가장 짧은 텍스트 표현에 해당하는 바이너리를 돌려줘요. 내부 알고리즘은 Erlang/OTP 버전에 따라 달라져요. OTP >= 24에서는 "Ryū: fast float-to-string conversion"(PLDI 2018)을, OTP < 24에서는 "Printing Floating-Point Numbers Quickly and Accurately"(PLDI 1996)를 사용해요. 설정 가능한 표현이 필요하면 :erlang.float_to_binary/2를 쓰세요. 컴파일러가 인라인해요.
iex> Float.to_string(7.0)
"7.0"
더 알아보기
Kernel.round/1과Kernel.trunc/1을 함께 보면 정수 변환의 흐름이 분명해져요.- 부동소수점 위의 수학 함수는 Erlang의
:math모듈을 참고해 보세요. - 정수 거듭제곱은
Integer.pow/2에서 확인할 수 있어요.