15. æµ®åå°æ°ç¹æ¼ç®ããã®åé¡ã¨å¶é¶
æµ®åå°æ°ç¹æ°ã¯ã³ã³ãã¥ã¼ã¿ã¼ã®ãã¼ãã¦ã§ã¢ä¸ã¯2鲿°(binary)ã®åæ°ã§è¡¨ããã¾ãã
ãã¨ãã°ã10鲿° ã®åæ°ã§ã¯ 0.625 㯠6/10 + 2/100 + 5/1000 ã¨ããå¤ãæã¡ã2鲿° ã®åæ°ã§ã¯ 0.101 㯠1/2 + 0/4 + 1/8 ã¨ããå¤ãæã¡ã¾ãã
ãã®2ã¤ã®åæ°ã¯ã¾ã£ããåãå¤ãæã¡ãå¯ä¸ç°ãªãç¹ã¯1ã¤ç®ã10鲿°ã®åæ°ã§æ¸ããã¦ããã2ã¤ç®ã¯2鲿°ã®åæ°ã§æ¸ããã¦ããã¨ãããã¨ã§ãã
æ®å¿µãªãã¨ã«ãã»ã¨ãã©ã®å°æ°ã¯ 2 鲿³ã®åæ°ã¨ãã¦æ£ç¢ºã«è¡¨ãããã¨ãã§ãã¾ããããã®çµæãä¸è¬ã«ãå ¥åãã 10 é²ã®æµ®åå°æ°ç¹æ°ã¯ã 2 鲿³ã®æµ®åå°æ°ç¹æ°ã§è¿ä¼¼ãããå¾ãå®éã«ãã·ã³ã«è¨æ¶ããã¾ãã
æåã¯åºæ° 10 ã使ãã¨åé¡ãç°¡åã«çè§£ã§ãã¾ããåæ° 1/3 ãèãã¦ã¿ã¾ããããåæ° 1/3 ã¯ãåºæ° 10 ã®åæ°ã¨ãã¦ã以ä¸ã®ããã«è¿ä¼¼ãããã¨ãã§ãã¾ã:
0.3
ããã«æ£ç¢ºãªè¿ä¼¼ã¯ã
0.33
ããã«æ£ç¢ºãªè¿ä¼¼ã¯ã
0.333
ã¨ãªãã以å¾åæ§ã§ããä½åæ¡æ°ãå¢ããã¦æ¸ããããçµæã¯æ±ºãã¦å³å¯ãª 1/3 ã«ã¯ãªãã¾ãããããããå°ãã¥ã¤æ£ç¢ºãªè¿ä¼¼ã«ã¯ãªã£ã¦ããã§ãããã
åæ§ã«ãåºæ°ã 2 ã¨ãã表ç¾ã§ä½æ¡ä½¿ããã¨ãã10 鲿°ã® 0.1 ã¯åºæ°ã 2 ã¨ããå°æ°ã§æ£ç¢ºã«è¡¨ç¾ãããã¨ã¯ã§ãã¾ãããåºæ° 2 ã§ã¯ã1/10 ã¯å¾ªç°å°æ° (repeating fraction) ã¨ãªãã¾ã
0.0001100110011001100110011001100110011001100110011...
ã©ããæéã®æ¡ã§æ¢ããã¨ãè¿ä¼¼å¤ãå¾ããã¨ã«ãªãã¾ããè¿å¹´ã®æ®ã©ã®ã³ã³ãã¥ã¼ã¿ã§ã¯ float åã¯ãæä¸ä½ãããããæ°ãã¦æåã® 53 ããããååã2 ã®åªä¹ã忝ã¨ãããäºé²å°æ°ã§è¿ä¼¼ããã¾ãã1/10 ã®å ´åã¯ãäºé²å°æ°ã¯ 3602879701896397 / 2 ** 55 ã¨ãªãã¾ããããã¯ã1/10 ã«è¿ãã§ãããå³å¯ã«åãå¤ã§ã¯ããã¾ããã
å¤ã表示ãããæ¹æ³ã®ããã«ãã»ã¨ãã©ã®ã¦ã¼ã¶ã¯ãè¿ä¼¼ã«æ°ã¥ãã¾ãããPython ã¯ãã·ã³ã«æ ¼ç´ããã¦ããäºé²è¿ä¼¼å¤ã®10é²å°æ°ã§ã®è¿ä¼¼å¤ã表示ããã®ã§ãæ ¼ç´ããã¦ããå¤ãå ã®10é²å°æ°ã®è¿ä¼¼å¤ã§ããç¡ããã¨ãå¿ããã¡ã§ããã»ã¨ãã©ã®ãã·ã³ã§ããã Python ã2鲿°ã§è¿ä¼¼ããã 0.1 ã®è¿ä¼¼å¤ããã®ã¾ã¾10鲿°ã§è¡¨ç¤ºãã¦ãããããã®çµæã¯æ¬¡ã®ããã«ãªã£ãã§ããã:
>>> 0.1
0.1000000000000000055511151231257827021181583404541015625
ããã¯ãã»ã¨ãã©ã®äººãå¿ è¦ã¨æãããããå¤ãããæ¡æ°ã§ãããªã®ã§ãPython ã¯ä¸¸ããå¤ã表示ãããã¨ã§ãæ¡æ°ãæ±ããããç¯å²ã«ã¨ã©ãã¾ã:
>>> 1 / 10
0.1
表示ãããçµæãæ£ç¢ºã« 1/10 ã§ããããã«è¦ããã¨ãã¦ããå®éã«æ ¼ç´ããã¦ããå¤ã¯æãè¿ã表ç¾ã§ããäºé²å°æ°ã§ããã¨ãããã¨ã ãã¯è¦ãã¦ããã¦ãã ããã
å¹¾ã¤ãã®ç°ãªã10鲿°ã®å¤ããåã2é²æçæ°ã®è¿ä¼¼å¤ãå
±æãã¦ãã¾ããä¾ãã°ã0.1 㨠0.10000000000000001 㨠0.1000000000000000055511151231257827021181583404541015625 ã¯ã©ãã 3602879701896397 / 2 ** 55 ã«è¿ä¼¼ããã¾ããåãè¿ä¼¼å¤ãå
±æãã¦ããã®ã§ãã©ã®10鲿°ã®å¤ã eval(repr(x)) == x ã¨ããæ¡ä»¶ãæºãããã¾ã¾åãããã«è¡¨ç¤ºããã¾ãã
æã® Python ã¯ãããã³ãã㨠repr() ãã«ãã¤ã³é¢æ°ã¯ 17 æ¡ã®æå¹æ°åãæã¤ 0.10000000000000001 ã®ãããª10鲿°ã®å¤ãé¸ãã§è¡¨ç¤ºãã¦ãã¾ããã Python 3.1 ããã¯ãã»ã¨ãã©ã®å ´é¢ã§ 0.1 ã®ãããªæãçãæ¡æ°ã®10鲿°ã®å¤ãé¸ã¶ããã«ãªãã¾ããã
ãã®åä½ã¯2鲿°ã®æµ®åå°æ°ç¹ã«ã¨ã£ã¦ã¯ããèªç¶ãªãã®ã§ãããã㯠Python ã®ãã°ã§ã¯ããã¾ããããããªãã®ã³ã¼ãã®ãã°ã§ãããã¾ããããã¼ãã¦ã§ã¢ã®æµ®åå°æ°ç¹æ¼ç®ããµãã¼ããã¦ããå ¨ã¦ã®è¨èªã§åã種é¡ã®åé¡ãè¦ã¤ãããã¨ãã§ãã¾ã (ããã¤ãã®è¨èªã§ã¯ããã©ã«ãã®ããããã¯ã©ã®åºåã¢ã¼ããé¸ãã§ãããã®å·®ã 表示 ããªãããããã¾ããã)ã
ããããåºåã®ããã«ãæååãã©ã¼ããããå©ç¨ãã¦æå¹æ¡æ°ãå¶éãã10鲿°è¡¨ç¾ãå¾ããã¨ãã§ãã¾ã:
>>> format(math.pi, '.12g') # give 12 significant digits
'3.14159265359'
>>> format(math.pi, '.2f') # give 2 digits after the point
'3.14'
>>> repr(math.pi)
'3.141592653589793'
ããããå®éã®ã³ã³ãã¥ã¼ã¿ã¼ä¸ã®å¤ã® 表示 ã丸ãã¦ããã ãã®ãããã°é¯è¦ã ã¨ãããã¨ãèªèãã¦ããã¦ãã ããã
ããä¸ã¤ã®é¯è¦ãç´¹ä»ãã¾ããä¾ãã°ã0.1 ãæ£ç¢ºã«ã¯ 1/10 ã§ã¯ãªãããã«ãããã3åè¶³ããå¤ãã¾ãæ£ç¢ºã«ã¯ 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
ãã®ããã«2鲿°ã®æµ®åå°æ°ç¹ã®æ¼ç®ã«ã¯å¤ãã®é©ããããã¾ããã0.1ãã®åé¡ã«ã¤ãã¦è©³ãã説æã¯ãã表ç¾ã¨ã©ã¼ãã»ã¯ã·ã§ã³ã§è¡ãã¾ãã2鲿°ã®æµ®åå°æ°ç¹ã®ä»çµã¿ã¨ãå®éã«ããééããåé¡å種ã«ã¤ãã¦ã®åãããããæ¦è¦ã¯ã Examples of Floating Point Problems ãåç §ãã¦ãã ããããã®ä»ããããé©ãã® ãã詳細ãªèª¬æã¯ The Perils of Floating Point ãåç §ãã¦ãã ããã
究極çã«ããã¨ã"容æãªçãã¯ããã¾ãã"ãã§ãããæµ®åå°æ°ç¹æ°ã®ãã¨ãé度ã«è¦æããªãã§ãã ããï¼ Python ã® float åæä½ã«ãããã¨ã©ã¼ã¯æµ®åå°æ°ç¹å¦çãã¼ãã¦ã§ã¢ããåãã¤ãããã®ã§ãããã»ã¨ãã©ã®ãã·ã³ä¸ã§ã¯ä¸ã¤ã®æ¼ç®ãããé«ã 2**53 åã® 1 ã§ãããã®èª¤å·®ã¯ã»ã¨ãã©ã®ä½æ¥ã§å å以ä¸ã®ãã®ã§ãããæµ®åå°æ°ç¹æ¼ç®ã¯ 10 é²ã®æ¼ç®ã§ã¯ãªããæµ®åå°æ°ç¹ã®æ¼ç®ãæ°ãã«è¡ãã¨ãæ°ããªä¸¸ã誤差ã®å½±é¿ãåãããã¨ãå¿ã«ã¨ã©ãã¦ããã¦ãã ããã
ç°å¸¸ãªã±ã¼ã¹ãåå¨ãã䏿¹ã§ãæ®æ®µã®æµ®åå°æ°ç¹æ¼ç®ã®å©ç¨ã§ã¯ãåã«æçµçãªçµæã®å¤ãå¿
è¦ãª 10 é²ã®æ¡æ°ã«ä¸¸ãã¦è¡¨ç¤ºããã®ãªããæçµçã«ã¯æå¾
éãã®çµæãå¾ããã¨ã«ãªãã§ããããããã¦ã¯ str() ã§ååã§ãããããç´°ããªå¶å¾¡ãããããã°ã æ¸å¼æå®æååã®ææ³ ã«ãã str.format() ã¡ã½ããã®ãã©ã¼ããã仿§ãåç
§ãã¦ãã ããã
æ£ç¢ºãª10鲿°è¡¨ç¾ãå¿
è¦ã¨ãªããããªå ´åã«ã¯ã decimal ã¢ã¸ã¥ã¼ã«ãå©ç¨ãã¦ã¿ã¦ãã ããããã®ã¢ã¸ã¥ã¼ã«ã¯ä¼è¨ã¢ããªã±ã¼ã·ã§ã³ãé«ç²¾åº¦ã®è¨ç®ãæ±ããããã¢ããªã±ã¼ã·ã§ã³ã«é©ããã10鲿°ã®è¨ç®ãå®è£
ãã¦ãã¾ãã
å¥ã®æ£ç¢ºãªè¨ç®æ¹æ³ã¨ãã¦ã fractions ã¢ã¸ã¥ã¼ã«ãæçæ°ã«åºã¥ãè¨ç®ãå®è£
ãã¦ãã¾ã (1/3 ã®ãããªæ°ãæ£ç¢ºã«è¡¨ããã¨ãã§ãã¾ã)ã
ããªããæµ®åå°æ°ç¹æ¼ç®ã®ããã¼ã¦ã¼ã¶ã¼ãªããSciPy ããã¸ã§ã¯ããæä¾ãã¦ãã NumPy ããã±ã¼ã¸ããã®ä»ã®æ°å¦ç¨ããã±ã¼ã¸ã調ã¹ã¦ã¿ãã¹ãã§ãã <https://scipy.org> ãåç §ãã¦ãã ããã
Python 㯠æ¬å½ã« float ã®æ£ç¢ºãªå¤ãå¿
è¦ãªã¬ã¢ã±ã¼ã¹ã«å¯¾å¿ããããã®ãã¼ã«ãæä¾ãã¦ãã¾ãã float.as_integer_ratio() ã¡ã½ãã㯠float ã®å¤ãæçæ°ã¨ãã¦è¡¨ç¾ãã¾ã:
>>> x = 3.14159
>>> x.as_integer_ratio()
(3537115888337719, 1125899906842624)
ãã®åæ°ã¯æ£ç¢ºãªã®ã§ãå ã®å¤ãå®å ¨ã«å¾©å ãããã¨ãã§ãã¾ã:
>>> x == 3537115888337719 / 1125899906842624
True
float.hex() ã¡ã½ãã㯠float ã®å¤ã16鲿°ã§è¡¨ç¾ãã¾ãããã®å¤ãã³ã³ãã¥ã¼ã¿ã¼ãæã£ã¦ããæ£ç¢ºãªå¤ã表ç¾ã§ãã¾ã:
>>> x.hex()
'0x1.921f9f01b866ep+1'
ãã®æ£ç¢ºãª16鲿°è¡¨ç¾ã¯ãã¨ã® float å¤ãæ£ç¢ºã«å¾©å ããããã«ä½¿ããã¨ãã§ãã¾ã:
>>> x == float.fromhex('0x1.921f9f01b866ep+1')
True
ãã®16鲿°è¡¨ç¾ã¯æ£ç¢ºãªã®ã§ãå¤ã (ãã©ãããã©ã¼ã ã«ãä¾åãã) ãã¼ã¸ã§ã³ã®ç°ãªãPython éã§ããåãããããä»ã®ãã®ãã©ã¼ãããããµãã¼ãããè¨èª (Java ã 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
The math.fsum() goes further and tracks all of the "lost digits"
as values are added onto a running total so that the result has only a
single rounding. This is slower than sum() but will be more
accurate in uncommon cases where large magnitude inputs mostly cancel
each other out leaving a final sum near zero:
>>> arr = [-0.10430216751806065, -266310978.67179024, 143401161448607.16,
... -143401161400469.7, 266262841.31058735, -0.003244936839808227]
>>> float(sum(map(Fraction, arr))) # Exact summation with single rounding
8.042173697819788e-13
>>> math.fsum(arr) # Single rounding
8.042173697819788e-13
>>> sum(arr) # Multiple roundings in extended precision
8.042178034628478e-13
>>> total = 0.0
>>> for x in arr:
... total += x # Multiple roundings in standard precision
...
>>> total # Straight addition has no correct digits!
-0.0051575902860057365
15.1. 表ç¾ã¨ã©ã¼Â¶
ãã®ç« ã§ã¯ã"0.1" ã®ä¾ã«ã¤ãã¦è©³ç´°ã«èª¬æãããã®ãããªã±ã¼ã¹ã«å¯¾ãã¦ã©ã®ããã«ããã°æ£ç¢ºãªåæãèªåã§è¡ãããã示ãã¾ããããã§ã¯ã 2 鲿³è¡¨ç¾ã®æµ®åå°æ°ç¹æ°ã«ã¤ãã¦ã®åºç¤çãªç¥èããããã®ã¨ãã¦è©±ãé²ãã¾ãã
表ç¾ã¨ã©ã¼(Representation error)ã¯ãããã¤ãã® (å®éã«ã¯ã»ã¨ãã©ã®) 10 é²ã®å°æ°ã 2 鲿³ (åºæ° 2)ã®åæ°ã¨ãã¦è¡¨ç¾ã§ããªãã¨ããäºå®ã«é¢ä¿ãã¦ãã¾ãããã㯠Python (ããã㯠Perl, C, C++, Java, Fortran. ããã³ãã®ä»å¤ã) ãæå¾ éãã®æ£ç¢ºãª 10 鲿°ã表示ã§ããªã主è¦ãªçç±ã§ãã
ãªããããªãã®ã§ãããï¼ 1/10 ã¯ï¼é²æ³ã®å°æ°ã§å³å¯ã«è¡¨ç¾ã§ãã¾ãããå°ãªãã¨ã2000年以éãã»ã¼ãã¹ã¦ã®ãã·ã³ã¯ IEEE 754 2鲿°ã®æµ®åå°æ°ç¹æ¼ç®ãç¨ãã¦ãããã»ã¼ãã¹ã¦ã®ãã©ãããã©ã¼ã ã§ã¯ Python ã®æµ®åå°æ°ç¹ã IEEE 754 binary64 "å精度 (double precision)" å¤ã«å¯¾å¿ä»ãã¾ãã 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
ååã¨åæ¯ã2ã§å²ã£ã¦åæ°ãå°ãããã¾ã:
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
ããã¯ãè¨ç®æ©ãè¨æ¶ãã¦ããæ£ç¢ºãªæ°å¤ãã10 鲿°å¤ 0.1000000000000000055511151231257827021181583404541015625 ã«ã»ã¼çããã¨ãããã¨ã§ããå¤ãã®è¨èª (å¤ããã¼ã¸ã§ã³ã® Python ãå«ã) ã§ã¯ãå®å ¨ãª 10 é²å¤ã表示ããã®ã§ã¯ãªããçµæãæå¹æ°å 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'