실수를 표현하는 방식
컴퓨터는 기본적으로 2진수를 사용하는 기계이다.
정수(ex. 1,2,3) 를 표현하는데에는 무리없이 표현할 수 있지만 소수를 표현할 때에는 무한한 2진수로 표현이 된다.
즉, 소수점 0.1을 2진수로 표현한다면 무한 소수로 표현이 된다는 말과 같다.
Float
Float은 부동 소수점을 사용하는 타입으로, 소수점의 위치가 데이터의 형태에 따라 언제든지 바뀔 수 있으며 실제로 소수점을 사용하다보면 float은 소수점 외, 많은 소수점을 가지고 있는 것을 볼 수 있을것이다.
즉, float은 decimal과 달리, 이진수 기반의 연산을 지니고 있으며 십진수를 이진수로 변환시킬때 이진소수인 형태를 띄고 정확히 맞아 떨어지지 않는 값들에 대해선 무한소수가 되어 정확하게는 그 값에 근사값이 될 확률이 높다.
z = 1.0 + 2.2
c = 1.1 + 2.2
print('certain:',z, 'not_certain:',c)
Decimal
Decimal은 고정 소수점을 사용하는 실수형 변수이다.
128 비트가 있는 실수형 변수로, 소수점 위치가 고정되어있는 '고정소수점' 방식을 사용하고 있다.
이 고정소수점 방식은 정수와 소수가 나뉘어져있는 방식이며 Decimal은 소수점 이하로 자리수가 많은 수를 정확하게 표현을 할 수 있다.
Ptyhon에서 decimal 모듈을 import해서 decimal.Decimal(‘0.1’)이라고 하면 0.1을 온전히 표현할 수 있다.
그러나 문자열이 아닌 0.1이라는 숫자를 넣게 된다면 아래 사진과 같이(y는) float처럼 많은 소수점을 가진다는 단점이 있다.
import decimal
x= decimal.Decimal('3.15')
y= decimal.Decimal(3.15)
print('string_decimal:',x,'num_decimal:',y)
이러한 차이에 대해서 잘 모르고 bronze는 string타입이여서 max값을 찾아오고, silver 또한 decimal이기 때문에 silver에도 max만 추출했으면 됐다.
데이터 타입에 맞춰 for문과 if문을 타다보니, 다른 데이터 형식들과 통일성을 맞추다가 일어난 실수였로 decimal에도 trim을 했기에 문자열로 변환이 됐고, trim 후 min,max,sum을 구했을때 값들이 달라져 검증 값들이 False로 나와 이들의 차이를 찾아볼 수 있었다.
select trim(max(column1)) as a
from dev.bronze.bz_table
--43573.324
union all
select max(trim(column1))
from dev.silver.sl_table
--9992.90
trim이라는 것은 말그대로 공백을 제거하는 함수인데, 공백을 제거하니 문자열로 변환이 되었고, max로 하니 9가 max로 잡힐 수 밖에 없었다. 이 같은 실수들은 소수점의 정밀도가 떨어지거나 값이 다르게 변경될 수도 있기 때문에, 로직을 잘 확인한 뒤, 첫번째 순서를 명확히 해야할 필요성을 느꼈다.
++
sql에서 string타입이여도 이를 더할 때 더해지는 것을 확인할 수 있었다.
찾아보니, sql 엔진에서 이를 자동변환해주기 때문에 sum이 가능하다는 것을 찾을 수 있었다.
select sum(a)
from (
select '10' as a
union all
select '20' as a
)
--30
참고 자료