내가 전부터 이상한걸 느끼고 있던거지만,
새삼 각잡고 테스트 해보니 역시 이상함.
아래 코드는 어째서 결과가 다른거임???
일단 코드 쓰기전에 선요약 설명함.
부동소숫점 실수 자료형은 연산간에 오차가 생길 수 있음.
예를들어 1.00 + 1.22 = 2.22 이 수학적으로 맞는 숫자이나,
부동소숫점 자료형은 이 연산이 1.00 + 1.22 != 2.22 가 됨.
그런데 100.0 + 122.0 은 222.0과 같음.
간단하게
print((1.00 + 1.22) == 2.22) # False
print((100.0 + 122.0) == 222.0) # True
이렇게 됨.
(다른 언어들도 아마 다 마찬가지겠지. 안해봤지만...)
테스트 해본 코드는 아래와 같은데
위에서 말한대로 정수에 해당하는 실수는 전혀 에러로 나오는게 없는데
그냥 소숫점 아래 있는 실수는 1000번 돌리면 평균 200개는 에러임.
- 정수 -> 실수 테스트
1. 정수를 랜덤으로 고름.
2. 정수를 실수로 변환.
3. 그대로 정수 더하기와 실수 더하기를 비교해서 출력.
- 그냥 실수 테스트
1. 정수를 랜덤으로 고름.
2. 정수 합산은 1,000,000 으로 나눔
3. 실수쪽은 각항을 먼저 1,000,000.0 으로 나누고 합산하고 비교.
---------------------------------------------------------
# 파이썬 3 코드임.
import numpy as np
total_episodes = 10_000_000
# total_episodes = 1000
episode = 0
err_cnt = 0
# while True :
while episode < total_episodes :
# 정수 -> 실수(소숫점 아래 값 없음)
a = np.random.randint(10_000_000_000_000)
b = np.random.randint(10_000_000_000_000)
c = a + b
af = float(a)
bf = float(b)
cf = float(c)
# # 실수(소숫점 아래 값 만듬)
# a = np.random.randint(10_000_000_000_000)
# b = np.random.randint(10_000_000_000_000)
# c = (a + b) / 1_000_000
# af = float(a) / 1_000_000.0
# bf = float(b) / 1_000_000.0
# cf = float(c)
if (af + bf) != cf :
print(f"불일치 : {a}, {b}, {c} /// {af}, {bf}, {cf} /// {af + bf}")
err_cnt += 1
episode += 1
print(f"err_cnt : {err_cnt}")
float 연산 오류 뭐 이렇게 검색하면 나올걸
아니, 그건 아는데 본문 좀 자세히 좀 읽어봐줘. 설명능력이 부족해서 좀 복잡해 보일지 모르겠지만, float 연산 오류는 인지하고 있음. 근데 왜 소수부가 없을때는 안생기냐는 거임.
print((1.00 + 1.22) == 2.22) # False print((100.0 + 122.0) == 222.0) # True 이 예시는 틀렸을지 모르겠는데, 아래쪽의 코드로 했을때는 아무리 해도 정수형 실수는 에러가 전혀 안생김. 어떤 차이일까여?
https://docs.python.org/ko/3/tutorial/floatingpoint.html
잠깐 바람 쐬고 옴. 머리아파서. ㅠㅠ
이거 읽어보니 설명 잘 돼있네 이거 정독해바
솔직히 위 링크가 도움되는 내용도 많은데 이 문제에 대해 이해가 좀 어려웠음. ㅠㅠ
아래 링크보고 더 확실히 이해함.
https://makething.tistory.com/entry/20101018-%EC%8B%A4%EC%88%98-IEEE-754-%ED%91%9C%EC%A4%80-32bit-%EB%B6%80%EB%8F%99-%EC%86%8C%EC%88%98%EC%A0%90-%ED%91%9C%ED%98%84-%EB%B0%A9%EB%B2%95
그래도
위 링크의 fraction 쪽이나 decimal 쪽이 크게 도움됨. ㄳㄳ
장황히 질문해놨는데 소수점을 정확히 표현못하는 이유는 소수점 부분을 이진수로 나타내기 때문인데 - dc Cpp
소수부가 0이면 표시할게 그냥 0이자나? - dc Cpp
질문 대충읽었는데 좀더 심오한 내용이면 짜짐ㅈㅅ - dc Cpp
대충 읽어보니 맞는거같은데. 가령 0.5를 표시하려면 2의 -1승이니 소수점 표시하는 비트에서 하나 1로 표시하면 되겠지 - dc Cpp
또 0.75라면 0.5+0.25이므로 2의 -1승 + 2의 -2승이야. - dc Cpp
이런식으로 표현하다보니 10진수와 차이가 생기고 10진수로 나타낸 소수점을 정확히 표현할 수 없어지지 - dc Cpp
근데 소수부가 0이라면? 그냥 0으로 쫙~세팅. 소수부가 없을때 왜 에러가 안나느냐? 이건 소수부가 0.125일때 왜 오류가 안나느냐 하는 질문과 같음. 그냥 특수케이스라고 봐야한다 - dc Cpp
음... 난 내가 오해했던게 정수부 소수부 안나누고 한꺼번에 계산해서 가수부를 만들고 거기에 지수부를 적용하는건 줄 알았는데, 계산 법칙 자체가 정수부 소수부 따로 하는거였네 ㄳㄳ 근데 유효숫자는 한덩어리로 6자리 15자리 이러고 있으니 난 통으로 하는건줄 알았지. ㅠㅠ
ㅋㅋ. - dc Cpp
내가 아무래도 이해를 제대로 못한듯함. 설명 보고 아래 코드를 테스트 해봤는데, 10000번 하니 20번 정도 나올정도로 오류율은 줄어들지만, 그래도 나옴. ㅠㅠ 곱셈 나눗셈은 얘기가 다른가봐. ㅠㅠ
a = np.random.randint(10_000_000_000_000) b = np.random.randint(10_000_000_000_000) c = a + b af = float(a) / 1_000_000.0 bf = float(b) / 1_000_000.0 af = af * 1_000_000.0 bf = bf * 1_000_000.0 cf = float(c)
데시멀...쓰자...구웩 - dc Cpp
(정수) / (2^N) 꼴의 소수는 오차 없이 표현 가능
명심 해야겠음. 소수부 0문제만이 아니라 2^N꼴 소수부는 주의하겠음. ㅠㅠ