수치 계산으로 빠지기 쉬운 포인트~부동 소수점~
후배의 질문 「히스토그램을 잘 그릴 수 없다」
후배로부터 질문이 왔습니다.
「히스토그램이 잘 그릴 수 없다」라는 것이었습니다.
그래프 작성 라이브러리 matplotlib에서 히스토그램을 작성하려고 하면 실패한 것 같습니다.
후배가 그리려고 했던 히스토그램이 이쪽.
import matplotlib.pyplot as plt
import numpy as np
s = np.array([0, 1, 1, 1, 2, 2, 2, 3])
mins = s.min()
maxs = s.max()
plt.hist(s, bins=int(maxs - mins + 1), range=(mins, maxs+1), alpha=0.3, color='deepskyblue', ec='deepskyblue', align='left')
plt.xticks(np.arange(mins, maxs+1, step=1))
산출:
이것은 잘 그려진 예입니다.
평소에는 이런 방식으로 그릴 수 있었지만 오늘은 잘 그릴 수 없었기 때문에 저에게 질문에 온 것 같습니다.
그 예가 이쪽.
import matplotlib.pyplot as plt
import numpy as np
s = np.array([0, 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.3])
mins = s.min()
maxs = s.max()
plt.hist(s, bins=int((maxs-mins)*10 + 1), range=(mins, maxs+0.1), alpha=0.3, color='deepskyblue', ec='deepskyblue', align='left')
plt.xticks(np.arange(mins, maxs+0.1, step=0.1))
산출:
기본적으로, 스케일이 다른 점 이외는, 최초의 예와 같습니다.
변수의 값을 print 해 보았습니다만, 언뜻보기에 이상한 곳은 발견되지 않았습니다.
print(s) # data
print(int((maxs-mins)*10 + 1)) # bin
print(mins) # range
print(maxs+0.1) # range
print(maxs)
산출:
[0. 0.1 0.1 0.1 0.2 0.2 0.2 0.3]
4
0.0
0.4
0.3
이 결과를 보면서 저도 "왜?"라고 생각했습니다.
그리고 좀 더 조사해보기로 했습니다.
대답 「부동 소수점」
한층 더 돌진해 변수의 내용을 살펴보면, 변수 maxs는, 일견 0.3의 값이 정확하게 들어 있는 것처럼 보이지만, 실은 엄밀하게는 0.3과는 다른 값이 들어가 있는 것을 알았습니다.
그 증거가 여기
print(maxs)
print(type(maxs))
print(maxs/3.0)
산출:
0.3
클래스 'numpy.float64'
0.099999999999999999
s = np.array([0, 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.3])에 대해 s.max()로 최대값을 취한 값을 3으로 나누어도 0.1이 된다. 그렇지 않습니다.
이것은 s의 최대치, maxs가 numpy.float64형이라고 하는, 64bit의 부동 소수점으로 나타내고 있기 (위해)때문에입니다. 표시상은, maxs에 정확하게 0.3의 값이 들어 있는 것처럼 보였지만, 머신 내부에서는, 2진수의 근사치로 보관 유지되고 있어 엄밀하게는 0.3과 다른 값이 들어가 있었던 것 입니다.
※ 파이썬의 부동 소수점 처리에 대한 자세한 내용은 여기
이번 예에서는 0.3인지 0.29999999999999999인지 미묘한 차이가 영향을 받고 잘 히스토그램을 그릴 수 없었다는 것을 알았습니다.
앞으로의 교훈
수치 계산의 프로그램을 쓰고 있으면, 역치 판정으로 처리를 분기한다고 하는 경우도 있을까 생각합니다. 그 때, 부동 소수점의 문제를 의식하지 않고 코딩하면, 생각지도 못한 결과가 될 것 같습니다.
float형에서의 연산을 반복한 후에, 경계치로 역치 판정을 실시하는 것은 위험, 이라고 하는 것을 재인식했습니다.
참고
15. 부동 소수점 연산, 그 문제와 제한
Reference
이 문제에 관하여(수치 계산으로 빠지기 쉬운 포인트~부동 소수점~), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/pocket_kyoto/items/e9aae9683bf510ad6340
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
import matplotlib.pyplot as plt
import numpy as np
s = np.array([0, 1, 1, 1, 2, 2, 2, 3])
mins = s.min()
maxs = s.max()
plt.hist(s, bins=int(maxs - mins + 1), range=(mins, maxs+1), alpha=0.3, color='deepskyblue', ec='deepskyblue', align='left')
plt.xticks(np.arange(mins, maxs+1, step=1))
import matplotlib.pyplot as plt
import numpy as np
s = np.array([0, 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.3])
mins = s.min()
maxs = s.max()
plt.hist(s, bins=int((maxs-mins)*10 + 1), range=(mins, maxs+0.1), alpha=0.3, color='deepskyblue', ec='deepskyblue', align='left')
plt.xticks(np.arange(mins, maxs+0.1, step=0.1))
print(s) # data
print(int((maxs-mins)*10 + 1)) # bin
print(mins) # range
print(maxs+0.1) # range
print(maxs)
한층 더 돌진해 변수의 내용을 살펴보면, 변수 maxs는, 일견 0.3의 값이 정확하게 들어 있는 것처럼 보이지만, 실은 엄밀하게는 0.3과는 다른 값이 들어가 있는 것을 알았습니다.
그 증거가 여기
print(maxs)
print(type(maxs))
print(maxs/3.0)
산출:
0.3
클래스 'numpy.float64'
0.099999999999999999
s = np.array([0, 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.3])에 대해 s.max()로 최대값을 취한 값을 3으로 나누어도 0.1이 된다. 그렇지 않습니다.
이것은 s의 최대치, maxs가 numpy.float64형이라고 하는, 64bit의 부동 소수점으로 나타내고 있기 (위해)때문에입니다. 표시상은, maxs에 정확하게 0.3의 값이 들어 있는 것처럼 보였지만, 머신 내부에서는, 2진수의 근사치로 보관 유지되고 있어 엄밀하게는 0.3과 다른 값이 들어가 있었던 것 입니다.
※ 파이썬의 부동 소수점 처리에 대한 자세한 내용은 여기
이번 예에서는 0.3인지 0.29999999999999999인지 미묘한 차이가 영향을 받고 잘 히스토그램을 그릴 수 없었다는 것을 알았습니다.
앞으로의 교훈
수치 계산의 프로그램을 쓰고 있으면, 역치 판정으로 처리를 분기한다고 하는 경우도 있을까 생각합니다. 그 때, 부동 소수점의 문제를 의식하지 않고 코딩하면, 생각지도 못한 결과가 될 것 같습니다.
float형에서의 연산을 반복한 후에, 경계치로 역치 판정을 실시하는 것은 위험, 이라고 하는 것을 재인식했습니다.
참고
15. 부동 소수점 연산, 그 문제와 제한
Reference
이 문제에 관하여(수치 계산으로 빠지기 쉬운 포인트~부동 소수점~), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/pocket_kyoto/items/e9aae9683bf510ad6340
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
15. 부동 소수점 연산, 그 문제와 제한
Reference
이 문제에 관하여(수치 계산으로 빠지기 쉬운 포인트~부동 소수점~), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/pocket_kyoto/items/e9aae9683bf510ad6340텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)