特に心配だったのが浮動小数点演算である。(中略)浮動小数点演算がなければ、まともな月面着陸ゲームはつくれない。『ビル・ゲイツ自伝I』(早川書房, 2025)

昭和60年代前半,当時小学生だったタロウ少年は,円周率を小数第16位3.1415926535897932 まで覚えました.覚える桁数はそれでよかったのか,という話です.

書影

拙著『コンピュータでとく数学』について,こんな質問がありました.

p.29 に倍精度での $\pi$ の近似値は $884279719003555/281474976710656$ とありますが,$245850922/78256779$ でよいのではないでしょうか.

良い質問です.というか,そんなに丁寧に読んでもらえるとは思わなかったというのが正直なところです.

木村良夫『パソコンで遊ぶ数学』(講談社, 1986)が国立国会図書館デジタルコレクションで公開されていたので,それを参照する形に書き直しました(参照:調査のメモ).タロウ少年が知りたかっただろうことは,おそらく全部書きました.


短い回答

次の2種類の近似があります.

  1. 数を浮動小数点数で近似すること
  2. $\pi$ を有理数で近似すること

『コンピュータでとく数学』で重要なのは 1 です.数 $x$ を浮動小数点数で表すときの,『コンピュータでとく数学』の式 (2.10) の意味での厳密値を $f(x)$ とします.

\[A:=\dfrac{884279719003555}{281474976710656}=\dfrac{884279719003555}{2^{48}},\qquad B:=\dfrac{245850922}{78256779}\]

とすると

\[f(A)=f(B)=f(π)=A≠B\]

です.つまり,$A, B, \pi$ は浮動小数点数にすると全て同じ値になりますが,その値と等しいのは $A$ だということです.

$f(B)=f(\pi)$ は自明ではないので,興味深いのは $B$ なのですが,『コンピュータでとく数学』の「2.5.1 浮動小数点数」で扱っているのは $A$ です($B$ の見つけ方は後述).


長い回答(話)

上記の2「$\pi$ を有理数で近似すること」についての話は長くなります.

今日標準的に使われる浮動小数点数(IEEE 754 の binary64)で表現できる,$\pi$ の最良の近似値は,$s=0, e=10000000000_2, f=1001001000011111101101010100010001000010110100011000_2$ として,

\[(-1)^s (1 + 2^{-52}f) 2^{(e - 1023)}=A=3.141592653589793115997963468544185161590576171875\]

です.

科学技術の現場で使われる $\pi$ の近似値としてよく挙げられる $3.141592653589793$ はおそらくこれの $\pi$ と一致する部分のことです(『コンピュータでとく数学』).

入出力に10進数を使う場合は,見た目と本当の値が異なることがあって紛らわしいです.例えば,3.141592653589793 というリテラルが 3.141592653589793115997963468544185161590576171875 全体と一致します.

import math
from decimal import Decimal

print(math.pi.as_integer_ratio())
# (884279719003555, 281474976710656)

print(Decimal.from_float(math.pi))
# 3.141592653589793115997963468544185161590576171875

print(math.pi == 3.141592653589793)
# True

というわけで,$\pi$ の10進表記を覚えておくなら3.141592653589793(小数第16位まで)です.「だけどもう,それだけじゃ足りないんだ」


$\pi$ を有理数で近似するというのはよくやられていることです.有限桁の10進数で表すというのも,$3.14=\dfrac{314}{100}$,$3.1415=\dfrac{31415}{10000}$ ですから,有理数による近似です.

私が $\pi$ の有理数による近似を最初に楽しんだのは,ブルーバックスの木村良夫『パソコンで遊ぶ数学』(講談社, 1986)(以下,木村本)でのことです.国会図書館デジタルコレクションで読めます.

まず,以下で使用するシステムと結果をまとめます.

機種 BASIC 規格 10進リテラルでの入力 $\pi$ の最良の近似値 浮動小数点数では等しくなるもの メモ
MSX2 MSX-BASIC BCD $\dfrac{31415926535898}{10^{13}}$ $\dfrac{10838702}{3450066}$ タロウ少年の友達 S の家にあった.
PC-8001 N-BASIC MBF 不可 $\dfrac{28296951008113761}{2^{53}}$ $\dfrac{657408909}{209259755}$ タロウ少年の家にあった.
FM-11 F-BASIC MBF 同上 同上 同上 木村本で使われた(木村本 p.58).

表の「浮動小数点数では等しくなるもの」を求めます.

話の流れは次のとおりです.

  ラベル 概要
木村本(素朴な方法) MSX-BASIC ではうまく行く.
木村本(倍精度) 改善しない.
タロウ少年(10進リテラル+バイト操作) 10進リテラルは信用できない(MSX-BASICは例外).
木村本(マチンの公式+マクローリン展開) 木村本の誤り?
木村本(連分数) これで解決?
木村本(読者への宿題) MSX-BASIC ではうまく行かない.

① 木村本(素朴な方法)

$\pi$ の最良の近似値 $A$ を,有理数 $\dfrac{M}{N}$ で近似するとしましょう.仮に分母 $N$ を定めます.$\dfrac{\lfloor AN\rfloor}{N}$ と $\dfrac{\lfloor AN\rfloor+1}{N}$ のうちで $A$ から遠くない方の分子を $M$ とすればよさそうです($L=AN, M=\lfloor L\rfloor$ として,$\dfrac{M+1}{N}-A<A-\dfrac{M}{N}$ なら $M$ を $1$ 増やす).$N=1$ から始めて,$N$ を増やしながら $\pi$ に近い $\dfrac{M}{N}$ を探します.

木村本の図3.1 のコードです(LPRINTPRINT に変更し,欲しいものが見つかったら止まるように 185 を追加しています).

100 REM ***** Fraction.1986.8.29
110  A=4*ATN(1)
120  N=1:D=1
130  L=A*N
140  M=INT(L)
150  IF M+1-L<L-M THEN M=M+1
160  E=ABS(A-M/N)
170  IF E>=D GOTO 200
180  PRINT M;"/";N,M/N
185  IF E=0 THEN END
190  D=E
200  N=N+1
210  GOTO 130

110 で 目標となる $\pi$ の最良の近似値を設定しようとしています.ATN は $\arctan$ つまり $\tan$ の逆関数で,$\tan\left(\dfrac{\pi}{4}\right)=1$ の両辺の $\arctan$ をとると,$\arctan\left(\tan\left(\dfrac{\pi}{4}\right)\right)=\dfrac{\pi}{4}=\arctan(1)$ なので,$\pi=4\arctan(1)$ です.小中学生へ:角 $B$ が直角の三角形 $ABC$ において,$\tan\left(\dfrac{\pi\angle BAC}{180}\right)=\dfrac{AB}{BC}$ と定めます.$ABC$ が直角二等辺三角形,つまり $a=45^\circ$ のとき,$\tan\left(\dfrac{45\pi}{180}\right)=\tan\left(\dfrac{\pi}{4}\right)=\dfrac{AB}{BC}=\dfrac{1}{1}=1$ です.

このコード,N-BASIC と F-BASIC ではうまく行きませんが,MSX-BASIC ではうまく行きます.

昭和のある日,高性能な MSX2 を持っていた友人 S に,このコードを電話で読み上げて伝えて,実行してもらおうとしました(付き合ってくれる S がすごいですね.何て頼んだんだろう).コードが誤って伝わり,正しく実行できなかったのを,S のお父さんが直してくれて,結果をプリンタで出力してくれたことに驚愕しました.(インターネットのメールはなく,家庭用のプリンタも珍しかった時代です.)

子供には心の支えになる大人の存在が必要ですから.

MSX のエミュレータ の Emulation Speed を 1000% にして試しました(途中で停止したい場合はCtrl-PageUp).WebMSX(ブラウザで動くエミュレータ)でも試せるかもしれません.再現しやすいように,上のコードを保存したディスクイメージを作りました(参考:プログラムのロード方法).ディスクをセットして,LOAD "PI.BAS" で読み込んで RUN です.

MSXで実行している様子(WIDTH 80)

プログラムは最終的に 10838702 / 3450066 3.1415926535898 を出力して停止します.かなり時間がかかるので,当時はそこまでは行かなかったと思います.そこまで行っていれば,これを約分した $\dfrac{5419351}{1725033}$ の値(3.1415926535897)が異なることに驚いたかもしれません.

MSX-BASIC で採用された浮動小数点数の規格 BCD では,10進数をそのまま格納するので,3.1415926535898 は格納されている値と厳密に一致します.これは,BCD での $\pi$ の最良の近似値です(小数第13位まで一致する 3.1415926535897 より $\pi$ に近い).

② 木村本(倍精度)

木村本 p.58 では次に,105 DEFDBL A-Z として数を8バイトで表す倍精度にすることが試みられています.木村本に書かれているとおり,この試みはうまく行きません.FM-11 のBASICの ATN が数を4バイトで表す単精度なので,4*ATN(1) の結果が $\pi$ の最良の近似値にならないのです.N-BASICも同様です.

③ タロウ少年(10進リテラル+バイト操作)

タロウ少年はおそらく,110 A=4*ATN(1) の代わりに 110 A=3.1415926535897932 を試したはずです.桁数をこれより多くしてもPRINT の結果は変わらないから大丈夫,と思ったかもしれません.

ここに罠がありました.

N-BASIC の浮動小数点数で表せる $\pi$ の最良の近似値と,リテラルの 3.1415926535897932 が表す値は異なるのです.違いを表にまとめます.リテラルの桁数を増やしても結果は変わりません.

MBF PRINT の結果 10進表記 16進表記
$\pi$ の最良の近似値 3.1415926535897932 3.141592653589793227020265931059839203953742980957 $0.\mathrm{C90FDAA22168C2}_{16}\times 2^2$
リテラル 3.1415926535897932 同上 3.1415926535897933380425683935754932463169097900391 $0.\mathrm{C90FDAA22168C4}_{16}\times 2^2$

N-BASIC では,10進リテラルを使って $\pi$ の最良の近似値を入力しようとするときは,POKE VARPTR(A),&HC2 として,バイト C4C2 に書き替えなければなりません.(F-BASIC ではバイトの並びが逆なので,POKE VARPTR(A)+7,&HC2 とします.)

105  DEFDBL A-Z
110  A=3.1415926535897932:POKE VARPTR(A),&HC2
120  N=1:D=1
130  L=A*N
140  M=INT(L)
150  IF M+1-L<L-M THEN M=M+1
160  E=ABS(A-M/N)
170  IF E>=D GOTO 200
180  PRINT M;"/";N,M/N
185  IF E=0 THEN END
190  D=E
200  N=N+1
210  GOTO 130

このように修正して実行すれば,プログラムは長時間の計算の後,657408909 / 209259755 3.141592653589793 を出力して停止します(PC-8801 のエミュレータ M88 の N mode の「全力駆動」で試しました.途中で停止したい場合は F11).これは,MBF での $\pi$ の最良の近似値です.

PC-8001で実行している様子(WIDTH 80)

因みに,注目している1バイトが,B4 から C7 の場合は全て,PRINT の結果は 3.141592653589793 になるので,PRINT で区別することはできません.次のコードで確認できます.

10 DEFDBL A
20 A=3.141592653589793
30 FOR B=&HB3 TO &HC8
40   POKE VARPTR(A),B
50   PRINT HEX$(B);A
60 NEXT B

実行結果を示します.C2 以外でも 3.141592653589793 と表示されるものはたくさんあります.

B3 3.141592653589792
B4 3.141592653589793
(省略)
C2 3.141592653589793
(省略)
C7 3.141592653589793
C8 3.141592653589794

④ 木村本(マチンの公式+マクローリン展開)

木村本 p.60 では,(名前は出てきませんが)マチンの公式と $\arctan$ のマクローリン展開を使って $\pi$ の最良の近似値を求めることが試みられます.小中学生と高校生へ:これは大学レベルです.例えば,高木貞治『解析概論』の§52で解説されています.因みに,タロウ少年が塾の先生に勧められて買った『解析概論』改訂第3版の人名索引には Machin(メイチン) とありました.

\[\frac{\pi}{4}=4\arctan\left(\frac{1}{5}\right)-\arctan\left(\frac{1}{239}\right)\qquad\text{(マチンの公式)}\] \[\arctan x=x-\frac{x^3}{3}+\frac{x^5}{5}-\frac{x^7}{7}+\frac{x^9}{9}-\cdots\qquad\text{(マクローリン展開)}\]

最初に掲載されるコードには問題があり,最終的に,次のようなコードが使われることになります(バイト列を確認するために,181-184 を追加しました).

100 REM ***** PAI 1986.9.1
110  DEFDBL X,Y,Z
120  K=11
130  X=.2#
140  GOSUB 190
150  Z=Y
160  X=.00418410041841#
170  GOSUB 190
180  PRINT 16*Z-4*Y
181  DEFDBL A:A=16*Z-4*Y:P=VARPTR(A)
182  FOR I=0 TO 7
183    PRINT RIGHT$("0"+HEX$(PEEK(P+I)),2);" ";
184  NEXT
185  END
190 REM *** arctan
200  Y=0
210  FOR I=1 TO K
220    J=2*I-1
222    IF I MOD 2 =0 GOTO 235
230    Y=Y+X^J/J:GOTO 240
235    Y=Y-X^J/J
240  NEXT I
250 RETURN

F-BASIC での実行結果を示します.

3.141592653589793
82 49 0F DA A2 21 68 C7

3.141592653589793 なので良さそうに見えますが,バイト列を見ると,C2 になるべきところが C7 になっているので,これは $\pi$ の最良の近似値ではありません.ですから,この結果を使うコード(木村本の図3.7)は誤りなのですが,木村本の図3.8 に掲載されている分の結果は正しいです(誤りが顕在化するのはもっと先).

次の修正が必要です.

120  K=12
160  X=1/239#
210  FOR I=K TO 1 STEP -1

修正後の実行結果を示します.

3.141592653589793
82 49 0F DA A2 21 68 C2

こんどは最後が C2 なので,$\pi$ の最良の近似値を得たことがわかります.値自体は異なりますが,MSX-BASIC でもうまく行きます.N-BASIC は,べき乗を計算する ^ が単精度なので,うまく行きません.べき乗をループで代替してもおそらくダメです.因みに,FM-7 の F-BASIC は N-BASIC と同様 ^ が単精度なのですが,ループで代替すればうまく行きます.

⑤ 木村本(連分数)

木村本 p.68 に掲載されている結果(図3.8)を,③で示したコードで再現します(最後の3行は筆者の追記).このあたりでは,$\pi$ の近似値の1バイトの違いの影響はありません.

3 / 1         3
13 / 4        3.25
16 / 5        3.2
19 / 6        3.166666666666667
22 / 7        3.142857142857143
179 / 57      3.140350877192982
201 / 64      3.140625
223 / 71      3.140845070422535
245 / 78      3.141025641025641
267 / 85      3.141176470588235
289 / 92      3.141304347826087
311 / 99      3.141414141414141
333 / 106     3.141509433962264
355 / 113     3.141592920353982
52163 / 16604               3.141592387376536
52518 / 16717               3.141592390979243
52873 / 16830               3.141592394533571
53228 / 16943               3.141592398040489
(省略)
103993 / 33102              3.141592653011903
104348 / 33215              3.141592653921421

木村本では,分母が $113$ から $16604$ に飛んでる理由が,次のような $\pi$ の連分数展開にもとづいて考察されています.

\[\pi = 3 + \cfrac{1}{7 + \cfrac{1}{15 + \cfrac{1}{1 + \cfrac{1}{292 + \cfrac{1}{1 + \ddots}}}}}\]

スペースの節約のために,この連分数を $[3; 7, 15, 1, 292, 1, \cdots]$ と表すような記法を採用します.

連分数は,「整数部分をとり,残りの逆数を求める」という作業を繰り返すことで得られます.

少し計算してみましょう.$\pi=3.14159\cdots$ なので,まず整数部分を取って $3$ を得ます.次に小数部分 $0.14159\cdots$ の逆数を取ると $7.0625\cdots$,その整数部分は $7$ です.その小数部分 $0.0625\cdots$ の逆数を取ると $15.996\cdots$,その整数部分は $15$ です.というわけで,$\pi$ の連分数展開は最初が $3,7,15,\cdots$ となります.

Wolfram言語での例を示します(Wolfram言語には,連分数を求める ContinuedFraction がありますが).

Reap[Nest[(Sow[IntegerPart[#]]; 1/FractionalPart[#]) &, Pi, 6]][[2, 1]]
(* {3, 7, 15, 1, 292, 1} *)

連分数展開を途中で打ち切って $\pi$ の有理数近似を得ようとすると,$292$ という比較的大きな数が現れるため,その前後で分母が大きく変わる,ということなのでしょう.第6項までの結果をまとめます.

打ち切り 連分数 有理数 10進近似
第1項 $[3]$ $3$ $3$
第2項 $[3;7]$ $22/7$ $3.142857142857\cdots$
第3項 $[3;7,15]$ $333/106$ $3.141509433962\cdots$
第4項 $[3;7,15,1]$ $355/113$ $3.141592920353\cdots$
第5項 $[3;7,15,1,292]$ $103993/33102$ $3.1415926530119\cdots$
第6項 $[3;7,15,1,292,1]$ $104348/33215$ $3.1415926539214\cdots$

確かに $292$ が現れたところで分母は大きく変わりますが,その結果は $16604$ ではなく $33012$ です.③で示したコードで $33012$ が現れるのはかなり先です.

$\dfrac{52163}{16604}$ の出自は木村本ではよくわかりませんが,$[3;7,15]=\dfrac{333}{106},\;[3;7,15,1]=\dfrac{355}{113}$ の次に $[3;7,15,1,k]=\dfrac{k355+133}{k113+106}\;(1\le k<292)$ を想定し,$k=146$ とすると現れます.

連分数展開を使えば $\pi$ の有理数近似が簡単に得られるのでは,と思うところですが,木村本では話がここで終わってしまいます.

こういう連分数への展開をコンピュータに計算させるプログラムをつくることもおもしろいテーマだとは思いますが,今回は,$\dfrac{52163}{16604}$ が発見されたところで終わりにしておきましょう。(木村本 p.64

「短い回答」への補足

IEEE 754 の binary64 における,$\pi$ の最良の近似値 $A:=884279719003555/2^{48}$ の連分数展開を示します(WolframAlpha).

\[A=[3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 3, 3, 2, 1, 3, 3, 7, 2, 1, 1, 3, 2, 42, 2]\]

この最初の $k$ 個を使ってできる有理数 $M/N$ を浮動小数点数で表した結果と $A$ との差の絶対値をまとめます.$k:=14, B:=245850922/78256779$ 以降は $A$ と等しいことがわかります.

k M N abs(float(M/N) - A)
1 3 1 1.41592653589793116e-01
2 22 7 1.26448926734967770e-03
3 333 106 8.32196275291074983e-05
4 355 113 2.66764189404966601e-07
5 103993 33102 5.77890624242627382e-10
6 104348 33215 3.31628058347632759e-10
7 208341 66317 1.22356347276308952e-10
8 312689 99532 2.91433543964103592e-11
9 833719 265381 8.71525074330747884e-12
10 1146408 364913 1.61071156412617711e-12
11 4272943 1360120 4.04121180963556981e-13
12 5419351 1725033 2.22044604925031308e-14
13 80143857 25510582 4.44089209850062616e-16
14 245850922 78256779 0.00000000000000000e+00
15 817696623 260280919 0.00000000000000000e+00
16 1881244168 598818617 0.00000000000000000e+00
17 2698940791 859099536 0.00000000000000000e+00
18 9978066541 3176117225 0.00000000000000000e+00
19 32633140414 10387451211 0.00000000000000000e+00
20 238410049439 75888275702 0.00000000000000000e+00
21 509453239292 162164002615 0.00000000000000000e+00
22 747863288731 238052278317 0.00000000000000000e+00
23 1257316528023 400216280932 0.00000000000000000e+00
24 4519812872800 1438701121113 0.00000000000000000e+00
25 10296942273623 3277618523158 0.00000000000000000e+00
26 436991388364966 139098679093749 0.00000000000000000e+00
27 884279719003555 281474976710656 0.00000000000000000e+00

因みに,$\pi$ の連分数展開は次のとおりです(WolframAlpha, OEIS A001203).

\[\pi=[3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, 1, 84, 2, 1, 1, 15, 3, \cdots]\]

$A$ と $\pi$ の連分数展開で共通なのは13番目($14$)までですが,$3=2+\dfrac{1}{1}$ なので,$A$ は あと1個,$\pi$ はあと2個取って作る有理数が等しくなります.$B$ はそこに現れます(OEIS A002485).

⑥ 木村本(読者への宿題)

MBF での $\pi$ の最良の近似値は次のとおりです(WolframAlpha).

\[\dfrac{28296951008113761}{2^{53}}=[3;7,15,1,292,1,1,1,2,1,3,1,14,2,1,1,1,3,2,2,274,2,1,1,5,4,2,1,1,1,7]\]

浮動小数点数の計算は厳密ではないので,連分数展開を途中で打ち切っても,値は同じになるかもしれません.それを調べます.

100 REM ***** Fraction by continued fraction.
110  DEFDBL A-H,N-X
120  U=9007199254740992#
130  T=28296951008113761#
140  A=T/U:N=T:D=U:K=32
150  P0=0:P1=1:Q0=1:Q1=0
160  FOR I=0 TO K
170    B=0:R=N
180    IF R<D THEN 220
190    R=R-D:B=B+1
200    GOTO 180
210    REM
220    P=B*P1+P0
230    Q=B*Q1+Q0
240    PRINT P;"/";Q,P/Q
250    IF A=P/Q THEN END
260    IF R=0 THEN END
270    N=D:D=R
280    P0=P1:P1=P:Q0=Q1:Q1=Q
290  NEXT I
300  END

N-BASIC と F-BASIC での結果は次のとおりで,$[3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 1]$ (17個)が $\pi$ の最良の近似値と等しくなります.

3 / 1         3
22 / 7        3.142857142857143
333 / 106     3.141509433962264
355 / 113     3.141592920353982
103993 / 33102              3.141592653011903
104348 / 33215              3.141592653921421
208341 / 66317              3.141592653467437
312689 / 99532              3.141592653618937
833719 / 265381             3.141592653581078
1146408 / 364913            3.141592653591404
4272943 / 1360120           3.141592653589389
5419351 / 1725033           3.141592653589815
80143857 / 25510582         3.141592653589793
165707065 / 52746197        3.141592653589793
245850922 / 78256779        3.141592653589793
411557987 / 131002976       3.141592653589793
657408909 / 209259755       3.141592653589793

③より圧倒的に早く $657408909/209259755$ が得られるわけですが,これがいつも有効かというと,そういうわけではありません.

MSX-BASIC でうまく行かないのです.$31415926535898/10^{13}=[3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 21, 17, 1, 1, 1, 1, 8, 1, 7, 2, 1, 2, 2]$ と等しい有理数を目指して試します(WolframAlpha).

120  U=10000000000000#
130  T=31415926535898#

実行結果を示します.

3 / 1         3
22 / 7        3.1428571428571
333 / 106     3.1415094339622
355 / 113     3.141592920354
103993 / 33102 3.1415926530119
104348 / 33215 3.1415926539214
208341 / 66317 3.1415926534674
312689 / 99532 3.1415926536189
833719 / 265381 3.141592653581
1146408 / 364913 3.1415926535914
4272943 / 1360120 3.1415926535893
5419351 / 1725033 3.1415926535897
118079314 / 37585813 3.1415926535897
2012767689 / 640683854 3.1415926535898

MSX-BASIC の正解は,おそらく①で得た $10838702/3450066$ です.これを約分した $5419351/1725033$ は結果に現れていますが,$\pi$ の最良の近似値にはならないため,プログラムはそこでは停止しません.最終的にプログラムは停止しますが,そのときの分母・分子は $10838702/3450066$ のそれよりかなり大きいです.

MSX-BASIC で $10838702/3450066$ を得る方法で,①よりよいものがわかりません(分母・分子をそれぞれ $2$ 倍した場合を調べれば得られますが,恣意的すぎる気がします).