15. ë¶ë ììì ì°ì : 문ì ì ë° íê³Â¶
ë¶ë ììì ì«ìë ì»´í¨í° íëì¨ì´ìì ë°(base)ì´ 2ì¸(ì´ì§) ììë¡ ííë©ëë¤. ì를 ë¤ì´, ìì§ ìì 0.625ë ê° 6/10 + 2/100 + 5/1000 를 ê°ì§ë©°, ê°ì ë°©ìì¼ë¡ ì´ì§ ìì 0.101 ë ê° 1/2 + 0/4 + 1/8 ì ê°ì§ëë¤. ì´ ë ììë ê°ì ê°ì ê°ì§ë©°, ì ì¼í ì°¨ì´ì ì 첫 ë²ì§¸ê° ë°ì´ 10ì¸ ë¶ì í기ë²ì¼ë¡ ìì±ëìê³ ë ë²ì§¸ë ë°ì´ 2ë¼ë ê²ì
ëë¤.
ë¶ííë, ëë¶ë¶ì ìì§ ììë ì ííê² ì´ì§ ììë¡ ííë ì ììµëë¤. ê²°ê³¼ì ì¼ë¡, ì¼ë°ì ì¼ë¡ ì ë ¥íë ìì§ ë¶ë ììì ì«ìê° ì¤ì ë¡ ê¸°ê³ì ì ì¥ë ëë ì´ì§ ë¶ë ììì ìë¡ ê·¼ì¬ ë ë¿ì ëë¤.
ì´ ë¬¸ì ë 먼ì ë° 10ìì ë°ì ¸ë³´ë ê²ì´ ì´í´í기 ì½ìµëë¤. ë¶ì 1/3ì ìê°í´ë´ ìë¤. ì´ ê°ì ìì§ ììë¡ ê·¼ì¬í ì ììµëë¤:
0.3
ëë, ë ì ííê²,
0.33
ëë, ë ì ííê²,
0.333
ë±ë±. ì무리 ë§ì ì릿ì를 ì ì´ë ê²°ê³¼ê° ì ííê² 1/3ì´ ë ì ìì§ë§, ì ì ë 1/3ì ê°ê¹ì´ ê·¼ì¬ì¹ê° ë©ëë¤.
ê°ì ë°©ìì¼ë¡, ì무리 ë§ì ì릿ìì ì«ì를 ì¬ì©í´ë, ìì§ì 0.1ì ì´ì§ ììë¡ ì ííê² ííë ì ììµëë¤. ì´ì§ë²ìì, 1/10ì 무íí ë°ë³µëë ììì ëë¤
0.0001100110011001100110011001100110011001100110011...
ì í í ë¹í¸ ììì ë©ì¶ë©´, ê·¼ì¿ê°ì ì»ê² ë©ëë¤. ì¤ëë ëë¶ë¶ 기ê³ìì, floatë ì´ì§ ë¶ìë¡ ê·¼ì¬ ëë ë°, ìµìì ë¹í¸ë¡ë¶í° ììíë 53ë¹í¸ë¥¼ ë¶ìë¡ ì¬ì©íê³ , 2ì ê±°ëì ê³± ì를 ë¶ëª¨ë¡ ì¬ì©í©ëë¤. 1/10ì ê²½ì°, ì´ì§ ë¶ìë 3602879701896397 / 2 ** 55 ì¸ë°, ì¤ì ê° 1/10ê³¼ ê±°ì ê°ì§ë§ ì íí ê°ì§ë ììµëë¤.
ë§ì ì¬ì©ìë ê°ì´ íìëë ë°©ì ë문ì ê·¼ì¬ë¥¼ ì¸ìíì§ ëª»í©ëë¤. íì´ì¬ì 기ê³ì ì ì¥ë ì´ì§ ê·¼ì¿ê°ì ì§ì§ ìì§ ê°ì ëí ìì§ ê·¼ì¿ê°ì ì¸ìí ë¿ì ëë¤. ëë¶ë¶ 기ê³ìì, ë§ì½ íì´ì¬ì´ 0.1ë¡ ì ì¥ë ì´ì§ ê·¼ì¿ê°ì ì§ì§ ìì§ ê°ì ì¶ë ¥íë¤ë©´ ë¤ìê³¼ ê°ì´ íìí´ì¼ í©ëë¤:
>>> 0.1
0.1000000000000000055511151231257827021181583404541015625
ì´ê²ì ëë¶ë¶ ì¬ëì´ ì ì©íë¤ê³ ìê°íë ê²ë³´ë¤ ë§ì ì«ìì´ë¯ë¡, íì´ì¬ì ë°ì¬ë¦¼ë ê°ì ëì íìíì¬ ì«ì를 ë¤ë£°ë§íê² ë§ëëë¤:
>>> 1 / 10
0.1
ì¸ìë ê²°ê³¼ê° ì íí 1/10ì¸ ê²ì²ë¼ ë³´ì¬ë, ì¤ì ì ì¥ë ê°ì ê°ì¥ ê°ê¹ì´ íí ê°ë¥í ì´ì§ ìììì 기ìµíì¸ì.
í¥ë¯¸ë¡ê²ë, ê°ì¥ ê°ê¹ì´ ê·¼ì¬ ì´ì§ ìì를 ê³µì íë ì¬ë¬ ë¤ë¥¸ ìì§ìê° ììµëë¤. ì를 ë¤ì´, 0.1 ê³¼ 0.10000000000000001 ë° 0.1000000000000000055511151231257827021181583404541015625 ë 모ë 3602879701896397 / 2 ** 55 ë¡ ê·¼ì¬ ë©ëë¤. ì´ ìì§ ê°ë¤ì´ 모ë ê°ì ê·¼ì¿ê°ì ê³µì í기 ë문ì eval(repr(x)) == x ë¶ë³ì ê·¸ëë¡ ì ì§íë©´ì ê·¸ì¤ íë를 íìí ì ììµëë¤.
ìì¬ì ì¼ë¡, íì´ì¬ í롬íí¸ì ë´ì¥ repr() í¨ìë ì í¨ ì«ì 17ê°ì ì«ìì¸ 0.10000000000000001 ì ì íí©ëë¤. íì´ì¬ 3.1ë¶í°, ì´ì íì´ì¬(ëë¶ë¶ ìì¤í
ìì)ì´ ê°ì¥ ì§§ì ê²ì ì íí ì ìì¼ë©°, ë¨ìí 0.1 ë§ íìí©ëë¤.
ì´ê²ì´ ì´ì§ ë¶ë ììì ì 본ì§ìì 주목íì¸ì: íì´ì¬ì ë²ê·¸ë ìëë©°, ì¬ë¬ë¶ì ì½ëì ìë ë²ê·¸ë ìëëë¤. íëì¨ì´ì ë¶ë ììì ì°ì ì ì§ìíë 모ë ì¸ì´ìì ê°ì ì¢ ë¥ì ê²ì ë³¼ ì ììµëë¤ (ì¼ë¶ ì¸ì´ë 기본ì ì¼ë¡ í¹ì 모ë ì¶ë ¥ 모ëìì ì°¨ì´ë¥¼ íìíì§ ìì ì ìì§ë§).
ì¢ ë ë§ì¡±ì¤ë¬ì´ 결과를 ì»ì¼ë ¤ë©´, 문ìì´ í¬ë§¤í ì ì¬ì©íì¬ ì íë ìì ì í¨ ì«ì를 ìì±í ì ììµëë¤:
>>> format(math.pi, '.12g') # 12ì리 ì í¨ì«ì
'3.14159265359'
>>> format(math.pi, '.2f') # ììì ë¤ë¡ 2ì리
'3.14'
>>> repr(math.pi)
'3.141592653589793'
ì´ê²ì´, ì§ì í ì미ìì, íììì 깨ë«ë ê²ì´ ì¤ìí©ëë¤: ì¬ë¬ë¶ì ë¨ìí ì§ì§ 기ê³ê°ì íì 를 ë°ì¬ë¦¼íê³ ììµëë¤.
íëì íìì ë¤ë¥¸ íìì ë³ì ì ììµëë¤. ì를 ë¤ì´, 0.1ì ì íí 1/10ì´ ìëë¯ë¡, 0.1ì ì¸ ê°ë¥¼ í©í ê² ìì ì íí 0.3ì´ ìëëë¤:
>>> 0.1 + 0.1 + 0.1 == 0.3
False
ëí, 0.1ì 1/10ì ì íí ê°ì ë ê°ê¹ìì§ ì ìê³ , 0.3ë 3/10ì ì íí ê°ì ë ê°ê¹ìì§ ì ìì¼ë¯ë¡, round() í¨ìë¡ ë¯¸ë¦¬ ë°ì¬ë¦¼íë ê²ì ëìì´ ëì§ ììµëë¤:
>>> round(0.1, 1) + round(0.1, 1) + round(0.1, 1) == round(0.3, 1)
False
ì«ì를 ìëí ì íí ê°ì ë ê°ê¹ê² ë§ë¤ ìë ìì§ë§, math.isclose() í¨ìë ë¶ì íí ê°ì ë¹êµí ë ì ì©í ì ììµëë¤:
>>> math.isclose(0.1 + 0.1 + 0.1, 0.3)
True
ëë, round() í¨ì를 ì¬ì©íì¬ ëëµì ì¸ ê·¼ì¬ì¹ë¥¼ ë¹êµí ì ììµëë¤:
>>> round(math.pi, ndigits=2) == round(22 / 7, ndigits=2)
True
ì´ì§ ë¶ë ììì ì°ì ì ì´ì²ë¼ ë§ì ëë¼ìì ì겨ì¤ëë¤. â0.1âì 문ì ë ìëì âíí ì¤ë¥â ì¹ì ìì ìì¸íê² ì¤ëª í©ëë¤. ì´ì§ ë¶ë ììì ì ìë ë°©ìê³¼ ì¤ë¬´ìì íí ë°ìíë 문ì ì íì ëí ì¬ë¯¸ìë ìì½ì ë¶ë ììì 문ì ì ì를 참조íì¸ì. ëí ë¤ë¥¸ ì¼ë°ì ì¸ ëë¼ìì ëí ë ìì í ì¤ëª ì ë¶ë ììì ì ìíì 참조íì¸ì.
ëì´ ê°ê¹ì´ ì¤ë©´ ë§íë¯ì´, âì¬ì´ ëµì ììµëë¤.â ìì§, ë¶ë ììì ì를 ì§ëì¹ê² ê²½ê³í íìë ììµëë¤! íì´ì¬ float ì°ì°ì ìë¬ë ë¶ë ììì íëì¨ì´ìì ììë ê²ì´ê³ , ëë¶ë¶ 기ê³ììë ì°ì°ë¹ 2**53ë¶ì 1ì ëì§ ìë ê·ëª¨ì ëë¤. ì´ê²ì ëë¶ë¶ ìì ìì íìí ìì¤ ì´ìì ëë¤. íì§ë§, ìì§ ì°ì ì´ ìëë©° 모ë float ì°ì°ì ìë¡ì´ ë°ì¬ë¦¼ ìë¬ê° ë°ìí ì ìë¤ë ì ì ëª ì¬í´ì¼ í©ëë¤.
ë³ë¦¬íì ê²½ì°ê° ì¡´ì¬íì§ë§, 무ì¬í ë¶ë ììì ì°ì ì ì¬ì©íë ëë¶ë¶ì, ë¨ìí ìµì¢
결과를 기ëíë ì릿ìë¡ ë°ì¬ë¦¼í´ì íìíë©´ 기ëíë 결과를 ë³´ê² ë ê²ì
ëë¤. ë³´íµ str() ë§ì¼ë¡ë ì¶©ë¶íë©°, ë ì¸ë°íê² ì ì´íë ¤ë©´ Format string syntax ìì str.format() ë©ìëì í¬ë§· ì§ì ì를 ë³´ì¸ì.
ì íí ìì§ ííì´ íìí ì¬ì© ì¬ë¡ì ê²½ì°, íê³ ìì© íë¡ê·¸ë¨ ë° ê³ ì ë° ìì© íë¡ê·¸ë¨ì ì í©í ìì§ ì°ì ì 구ííë decimal 모ëì ì¬ì©í´ë³´ì¸ì.
ì íí ì°ì ì ë ë¤ë¥¸ ííë ì 리ì를 기ë°ì¼ë¡ ì°ì ì 구ííë fractions 모ëì ìí´ ì§ìë©ëë¤ (ë°ë¼ì 1/3ê³¼ ê°ì ì«ìë ì ííê² ëíë¼ ì ììµëë¤).
ë¶ë ììì ì°ì°ì ë§ì´ íë ì¬ì©ìë©´ NumPy í¨í¤ì§ì SciPy íë¡ì í¸ìì ì ê³µíë ìí ë° íµê³ ì°ì°ì ìí ë¤ë¥¸ ë§ì í¨í¤ì§ë¥¼ ì´í´ë´ì¼ í©ëë¤. <https://scipy.org> 를 ë³´ì¸ì.
íì´ì¬ì ì¬ë¬ë¶ì´ floatì ì íí ê°ì ì§ì§ë¡ ììì¼ íë ë문 ê²½ì°ë¥¼ ì§ìí ì ìë ë구ë¤ì ì ê³µí©ëë¤. float.as_integer_ratio() ë©ìëë floatì ê°ì ë¶ìë¡ ííí©ëë¤:
>>> x = 3.14159
>>> x.as_integer_ratio()
(3537115888337719, 1125899906842624)
ë¹ì¨ì ì íí ê°ì´ê¸° ë문ì, ìë ê°ì ìì¤ ìì´ ë¤ì ë§ëë ë° ì¬ì©í ì ììµëë¤:
>>> x == 3537115888337719 / 1125899906842624
True
float.hex() ë©ìëë float를 16ì§ì(ë°ì´ 16ì´ë¤)ë¡ íííëë°, ì»´í¨í°ì ì ì¥ë ì íí ê°ì ì¤ëë¤:
>>> x.hex()
'0x1.921f9f01b866ep+1'
ì´ ì íí 16ì§ì ííì float ê°ì ì ííê² ì¬êµ¬ì±íë ë° ì¬ì©í ì ììµëë¤:
>>> x == float.fromhex('0x1.921f9f01b866ep+1')
True
ííì´ ì ííë¯ë¡, íì´ì¬ì ë¤ë¥¸ ë²ì ì ê±¸ì³ ê°ì ì ë¢°ì± ìê² ì´ìíê³ (íë«í¼ ë 립ì±), ê°ì íìì ì§ìíë ë¤ë¥¸ ì¸ì´(ìë°ë C99 ê°ì)ì ë°ì´í°ë¥¼ êµííë ë° ì ì©í©ëë¤.
ë ë¤ë¥¸ ì ì©í ë구ë sum() í¨ìì
ëë¤. ì´ í¨ìë í©ì°íë ëì ì ë°ë ìì¤ì ìíí©ëë¤. ê°ì´ ëê³ì ëí´ì§ ë ì¤ê° ë°ì¬ë¦¼ ë¨ê³ìì íì¥ ì ë°ë를 ì¬ì©í©ëë¤. ìµì¢
í©ê³ì ìí¥ì 주ë ì§ì ê¹ì§ ìë¬ê° ëì ëì§ ììì ì ì²´ì ì¸ ì íëì ì°¨ì´ë¥¼ ë§ë¤ ì ììµëë¤:
>>> 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 == 1.0
False
>>> sum([0.1] * 10) == 1.0
True
math.fsum()ì ë ëìê°, ëê³ì ê°ì´ ëí´ì§ ë 모ë âìì´ë²ë¦° ì«ìë¤âì ì¶ì íì¬, ê²°ê³¼ê° í ë²ë§ ë°ì¬ë¦¼ëëë¡ í©ëë¤. ì´ë sum()ë³´ë¤ ë리ì§ë§, í° ê°ì ì
ë ¥ì´ ëë¶ë¶ ìë¡ ììëì´, ìµì¢
í©ì´ 0ì ê°ê¹ìì§ë ë문 ê²½ì°ì ë ì íí©ëë¤:
>>> arr = [-0.10430216751806065, -266310978.67179024, 143401161448607.16,
... -143401161400469.7, 266262841.31058735, -0.003244936839808227]
>>> float(sum(map(Fraction, arr))) # ì íí í¨ê³ì ë¨ì¼ ë°ì¬ë¦¼
8.042173697819788e-13
>>> math.fsum(arr) # ë¨ì¼ ë°ì¬ë¦¼
8.042173697819788e-13
>>> sum(arr) # íì¥ ì ë°ëë¡ ë¤ì¤ ë°ì¬ë¦¼
8.042178034628478e-13
>>> total = 0.0
>>> for x in arr:
... total += x # íì¤ ì ë°ëë¡ ë¤ì¤ ë°ì¬ë¦¼
...
>>> total # ë¨ì í©ì°ì ì¬ë°ë¥¸ 결과를 ì£¼ì§ ììµëë¤!
-0.0051575902860057365
15.1. íí ì¤ë¥Â¶
ì´ ì¹ì ììë â0.1â ìì 를 ìì¸í ì¤ëª íê³ , ì´ë¬í ì¬ë¡ì ëí ì íí ë¶ìì ì¬ë¬ë¶ì´ ì§ì ìííë ë°©ë²ì ë³´ì¬ì¤ëë¤. ì´ì§ ë¶ë ììì ííì ëí 기본 ì§ìì´ ìë¤ê³ ê°ì í©ëë¤.
íí ì¤ë¥ (Representation error) ë ì¼ë¶ (ì¤ì ë¡ë, ëë¶ë¶ì) ìì§ ììê° ì´ì§(ë° 2) ììë¡ ì ííê² ííë ì ìë¤ë ì¬ì¤ì ëíë ëë¤. ì´ê²ì´ íì´ì¬(ëë í, C, C++, ìë°, í¬í¸ë ë° ê¸°í ì¬ë¬ ì¸ì´)ì´ ì¢ ì¢ ì¬ë¬ë¶ì´ 기ëíë ì íí ìì§ì를 íìíì§ ìë 주ë ì´ì ì ëë¤.
ì ê·¸ë´ê¹? 1/10ì ì´ì§ ììë¡ ì íí ííí ì ììµëë¤. ì ì´ë 2000ë ì´í, ê±°ì 모ë 기ê³ë IEEE 754 ì´ì§ ë¶ë ììì ì°ì ì ì¬ì©íê³ , ê±°ì 모ë íë«í¼ì íì´ì¬ float를 IEEE 754 binary64 âë°°ì ë°ëâì 매íí©ëë¤. IEEE 754 binary64 ê°ì 53ë¹í¸ì ì ë°ëê° í¬í¨ëì´ ìì´ì, ì ë ¥ ì ì»´í¨í°ë 0.1ì J/2**N ííì ê°ì¥ ê°ê¹ì´ ë¶ìë¡ ë³ííë ¤ê³ ë ¸ë ¥í©ëë¤. ì¬ê¸°ì J ë ì íí 53ë¹í¸ë¥¼ í¬í¨íë ì ìì ëë¤.:
1 / 10 ~= J / (2**N)
를
J ~= 2**N / 10
ë¡ ë¤ì ì°ê³ , J ê° ì íí 53 ë¹í¸(>= 2**52 ì´ì§ë§ < 2**53 ì
ëë¤)ìì ê³ ë ¤íë©´, N ì ìµì ê°ì 56ì
ëë¤:
>>> 2**52 <= 2**56 // 10 < 2**53
True
ì¦, 56ì J ê° ì íí 53ë¹í¸ê° ëëë¡ ë§ëë N ì ì ì¼í ê°ì ëë¤. J ì ê°ë¥í ê° ì¤ ê°ì¥ ì¢ì ê²ì ë°ì¬ë¦¼í 몫ì ëë¤:
>>> q, r = divmod(2**56, 10)
>>> r
6
ë머ì§ê° 10ì ì ë°ë³´ë¤ í¬ë¯ë¡, ê°ì¥ ê°ê¹ì´ ê·¼ì¿ê°ì ì¬ë¦¼ í´ì ì»ì´ì§ëë¤:
>>> q+1
7205759403792794
ë°ë¼ì IEEE 754 ë°°ì ë°ëë¡ 1/10 ì ê°ì¥ ê°ê¹ì´ ê·¼ì¿ê°ì ë¤ìê³¼ ê°ìµëë¤:
7205759403792794 / 2 ** 56
ë¶ìì ë¶ëª¨ë¥¼ ëë¡ ëëë©´ ë¤ìê³¼ ê°ì´ ì½ë¶ë©ëë¤:
3602879701896397 / 2 ** 55
ì¬ë¦¼ì í기 ë문ì, ì´ê²ì ì¤ì ë¡ 1/10 ë³´ë¤ ì½ê° í¬ë¤ë ê²ì ì ìíì¸ì; ë´ë¦¼ì íë¤ë©´, ëª«ì´ 1/10 ë³´ë¤ ì½ê° ììì¡ì ê²ì ëë¤. ê·¸ë¬ë ì´ë¤ ê²½ì°ìë ì ííê² 1/10ì¼ ìë ììµëë¤!
ë°ë¼ì ì»´í¨í°ë ê²°ì½ 1/10ì âë³´ì§â 못í©ëë¤: ë³¼ ì ìë ê²ì ììì 주ì´ì§ ì íí ë¶ì, ì»ì ì ìë ìµì ì IEEE 754 ë°°ì ë°ë ê·¼ì¿ê°ì ëë¤:
>>> 0.1 * 2 ** 55
3602879701896397.0
ê·¸ ë¶ìì 10**55를 ê³±íë©´, 55ê°ì ìì§ ì«ì를 ë³¼ ì ììµëë¤:
>>> 3602879701896397 * 10 ** 55 // 2 ** 55
1000000000000000055511151231257827021181583404541015625
ì´ë ì»´í¨í°ì ì ì¥ë ì íí ì«ìê° ìì§ì 0.1000000000000000055511151231257827021181583404541015625ì ê°ìì ì미í©ëë¤. ì ì²´ ìì§ë² ê°ì íìíë ëì , ë§ì ì¸ì´(ì´ì ë²ì ì íì´ì¬ í¬í¨)ë 결과를 17ê°ì ì í¨ì«ìë¡ ë°ì¬ë¦¼í©ëë¤:
>>> format(0.1, '.17f')
'0.10000000000000001'
fractions ì decimal 모ëì ì´ ê³ì°ì ì½ê² ë§ëëë¤:
>>> from decimal import Decimal
>>> from fractions import Fraction
>>> Fraction.from_float(0.1)
Fraction(3602879701896397, 36028797018963968)
>>> (0.1).as_integer_ratio()
(3602879701896397, 36028797018963968)
>>> Decimal.from_float(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> format(Decimal.from_float(0.1), '.17')
'0.10000000000000001'