パソコン活用研究5番街(Visual Basic、Excel(VBA)、BASIC プログラミング研究)

変数の精度 

これは非常によく指摘される問題ですが、BASICで0.01を100回足すプログラムを作って実行
すると、結果は1になりません。これは、実数を表現するのに、2進数で浮動少数点方式をとりいれ
ているため、少数に関してごくわずか誤差が生じてしまうためです。
浮動小数点についてはUnsigned型と浮動小数点型の内部構造をご参照下さい。
(このページはC言語のデータ型の説明ページですが、浮動小数点についてはBASICでもほぼ同じ
話です)

以下にQBASICでの実例を示します。(このプログラムでは、画面に表示するだけでなく、sum100.dat
というファイルにも結果を出力させています)

sum100.bas (QBASIC用)

CLS
OPEN "sum100.dat" FOR OUTPUT AS #1
sum = 0
FOR i = 0 TO 99
sum = sum + .01
PRINT #1, USING "##.#######"; sum;
PRINT USING "##.#######"; sum;
NEXT
CLOSE #1

sum100.dat (上記プログラムの実行結果を出力したファイル)
0.0100000 0.0200000 0.0300000 0.0400000 0.0500000 0.0600000 0.0700000 0.0800000 0.0900000 0.1000000 0.1100000 0.1200000 0.1300000 0.1400000 0.1500000 0.1600000 0.1700000 0.1800000 0.1900000 0.2000000 0.2100000 0.2200000 0.2300000 0.2400000 0.2500000 0.2600000 0.2700000 0.2800000 0.2900000 0.3000000 0.3100000 0.3200000 0.3300000 0.3399999 0.3499999 0.3599999 0.3699999 0.3799999 0.3899999 0.3999999 0.4099999 0.4199999 0.4299999 0.4399998 0.4499998 0.4599998 0.4699998 0.4799998 0.4899998 0.4999998 0.5099998 0.5199998 0.5299998 0.5399998 0.5499998 0.5599998 0.5699998 0.5799997 0.5899997 0.5999997 0.6099997 0.6199997 0.6299997 0.6399997 0.6499997 0.6599997 0.6699997 0.6799996 0.6899996 0.6999996 0.7099996 0.7199996 0.7299996 0.7399996 0.7499996 0.7599996 0.7699996 0.7799996 0.7899995 0.7999995 0.8099995 0.8199995 0.8299995 0.8399995 0.8499995 0.8599995 0.8699995 0.8799995 0.8899994 0.8999994 0.9099994 0.9199994 0.9299994 0.9399994 0.9499994 0.9599994 0.9699994 0.9799994 0.9899994 0.9999993


さて、他のBASICでも試してみます。
次は、一般的な旧BASIC用のプログラムです。
5 cls
10 sum=0
20 for i=0 to 99
30 sum=sum+0.01
40 print using "##.#######";sum;
50 next i

これを、FM-8(F-Basic)で実行すると、0.9999990になりました。
PC-98(N88BASIC(86))で実行しても結果は同じでした。
ただし、N88互換BASIC For Winでは、1.0000000となりました。(これはどんぴしゃだった)
BASICの種類により多少の結果の違いはありますが、一般には誤差ありと考えたほうがいいと
思います。

なお、これはBASICに限らず、他の言語でも同じことです。試しに、DOS窓で実行するFORTRAN
で2例試してみました。

(1)  BC-FORTRAN77 Vers 1.3b  copyright: Andre Koestli

       WRITE(5,100)
100     FORMAT('FORTRAN **00.1を100回足す**')
       read(6,*)h
       k=0
       a=0
10      k=k+1
       a=a+0.01
       WRITE(5,300)a
300     FORMAT('TOTAL ',f9.7)
       if (k .lt. 100 ) go to 10
       STOP
       END

結果は0.9999993でした。
(このFORTRANはDO ... CONTINUE ループ内で少数をの演算を行うと、正しく実行されない
ため、IF 文でループを作ってます)

(2) Salford FTN77/Win32 Salford Software Ltd  Copyright (c) Salford Software Ltd. 1993-1997

       dimension a(103)
       WRITE(5,100)
100      FORMAT('FORTRAN **0.01を100回足す**')
        read(6,*)h
       do 10 i=1,100
       a(i)=a(i-1)+0.01
10      continue
       WRITE(5,300)(a(i),i=1,100)
300      FORMAT('TOTAL ',100f9.7)
       STOP
       END

これも結果は0.9999993でした。

ということで、パソコンで少数を扱う時は、必ず精度と誤差という問題を念頭に置かなければ
ならないという話でした。
従って、以下のプログラムは下手をすると、無限ループになってしまう可能性が非常に大なわけです。

10 a=0
20 a=a+0.01
30 if a=1 then end else goto 20

これは30行の判定部を
30 if a>=1 then end else goto 20
のようにしないとまずいでしょう。

TOP PAGE >Basic活用研究目次