小数の連続な加算について

返信する


答えを正確に入力してください。答えられるかどうかでスパムボットか否かを判定します。

BBCode: ON
[img]: ON
[url]: ON
スマイリー: OFF

トピックのレビュー
   

展開ビュー トピックのレビュー: 小数の連続な加算について

by konisi » 2005年9月09日(金) 04:27

あぁ、なるほど。

by イグトランス » 2005年9月07日(水) 07:45

それだったら整数型を使えばより誤差が減ります。
固定小数点数として使うわけです。

誤差が生まれないようにする方法もありますよ。

by konisi » 2005年9月07日(水) 04:10

0.1を100回足す場合

before code

#N88BASIC
Dim A As Double
Dim I As Long
A=0
For I=1 To 100
A=A+0.1
Next I
Print A

結果:A=9.99999999999998

after code

#N88BASIC
Dim A As Double
Dim I As Long
A=0
For I=1 To 100
A=A+(0.1*10)
Next I
A=A/10
Print A

結果:A=10

やっていることの説明
before codeでは、Aに0.1を100回足してる為、誰かが述べたように誤差が生まれて僅かに10に届かない結果になりました。
after codeでは、Aに0.1の10倍を100回足したあと、Aを10で割っているので、整数値を100回足しても誤差は生まれず、それを10で割っても小数にならなければたいした誤差も生まれないという結果になります。(少数になると、いつものように僅かな誤差が生まれます。)

数学の数式で言うと

0.1*100=(0.1*10)*100/10

という等式になるため、理論的にも正しいです。

うまく出来ました?

名前書いてませんでした。

by jacoby » 2005年8月02日(火) 18:55

 すみません。名前書き忘れてました。上のゲストの返信は
質問者jacobyが書きました。改めて。

by ゲスト » 2005年8月02日(火) 18:45

イグトランスさん、Sinryowさん、辻本さん、レクありがとうございます。

 辻本さんが書かれていた通り、
「A の値は 2.5 と表示されてるけど実は 2.5 にめちゃくちゃ近いだけ」
ということなんですね。

 加算を繰り返してどうというのも、たまたま誤差が目に見える形で
蓄積して表示された結果で、それ以前に「0.1」そのものが、人と
コンピュータでは別の数値を見てる。

 Print 0.1=0.1

では、確かに「-1」と返ってくるけど、ただ、自分とコンピュータはそれぞれ
別の数値を比べてる。
 
 内部で数値がどう処理されているか、「0.1」なんて10進の小数は
人間の目にはいかにも明らかな数値なんで、それが二進化されて桁に
収まらない循環小数になり、丸め誤差が生まれて結果に影響するというのは
中々、実数の演算の時は本当に頭に入れとかないといけないですね。
 「浮動小数点数を等しいかどうか判定するのは御法度と言われることもあります。」
 というのが、実感もって思い知ります。

 ありがとうございました。hiraさん、OverTakerさんも改めて。
ようよう気を付けんとなーと念じつつ。
返信遅れてすみません。またよろしくお願いします。

by 辻本一揃 » 2005年8月01日(月) 16:46

Double型の計算は難しくてできないんですけど、こういうことですよね。

~変数Cの計算~
2進数では   10進数では
 1.00000000   1.0
+)1.10000000  +)1.5
------------  -----
10.10000000   2.5

10.10000000 は 2.5 だから予定通りの値

~変数Aの計算~
2進数では   10進数では
 1.00000000   1.0
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
+)0.00011001  +)0.1
------------  -----
10.01110111   2.5?

10.01110111 は 2.46484... だから計算は合わない


Double型はもっと緻密な計算をしてるだろうけどそれでも 2.499999... で 2.5 とはちょっと違う。だから比較すると偽を返す。A の値は 2.5 と表示されてるけど実は 2.5 にめちゃくちゃ近いだけ。 ってことで合ってますか?(-_-;)

by Sinryow » 2005年8月01日(月) 13:16

Single値は,以下のように表現されます。
<sgn(1bit)>×(2^<pow(8bit)><man(23bit)>
sgnは符号を表す1bit,powは2の何乗かを表す8bit(実際には127が引かれる),manは実際の値の部分を表す23bit(実際は"1.<man>"の形をしている)です。
例えばsgn=0(正),pow=129(2の2乗),man=110000...000(2進法の「1.11」=10進法の「1.75」)とすると,それが表す値は 1×(2^2)×1.75=7.0 ということになります。

ちなみにDoubleでは
<sgn(1bit)>×(2^<pow(11bit)><man(52bit)>
です。

Doubleでは2進法で52桁ぶんしか表現できないわけです。

参考記述:
http://ja.wikipedia.org/wiki/%E6%B5%AE% ... 2.E5.BC.8F

by イグトランス » 2005年8月01日(月) 11:15

 1 ÷ 3 × 3 = 1と思いますよね。
しかしこれを分数を使わずに計算すると
1 / 3 * 3
= 0.333333...... * 3
= 0.333333...... + 0.333333...... + 0.333333......
= 0.999999...... (あれ?
となってしまいます。

 先に皆さんがおっしゃっていましたとおり、0.1をコンピュータが使う2進数で表すと上の0.333333...の如く小数点以下が無限に続く数になってしまいます。
なのでコンピュータで.1を足し続けたときにもこれと同じことが起こり、jacobyさんの場合、5.499999999......のようになってしまうのです。

なので浮動小数点数を等しいかどうか判定するのは御法度と言われることもあります。

追記 11:20頃
 Windowsの電卓は意外と賢く内部では数値を分数の形で保持している(とヘルプに書いてある)ので、1 / 3 * 3は1を返します。

BackSeachABを調べていて…

by jacoby » 2005年8月01日(月) 02:27

AB掲示板の過去ログ、BackSeachABを調べていて、
「0355 - For~Nextについて」がもしかしたら同様のトピックでは
ないかと思ったのですが、違うでしょうか? 
 ただいずれにしても、まだ分かりません…

レクありがとうございます。加えてもう一点なのですが…

by jacoby » 2005年8月01日(月) 01:56

OverTakerさん、hiraさん、レクありがとうございます。

そうですか。うーん、難しいとこですね…

 加えてもう一点、気になることがあるんです。

 前のプログラムをループでまとめて(縦長を縮めて)、
下の様にほぼ同様の内容のプログラムを作りました。

#prompt
Dim I As Long
Dim A,B,C As Double
B=1 '= 初期値
C=B+.1*15 '= 合計値
A=B ' 加算用の変数Aに初期値をセット

For I=0 to 14
A=A+.1
Print A
Next I

Print
Print "A=";A
Print
Print "比較評価 A=";C;"?";A=C

 今度は初期値を「1」にセットして実行してみます。
答えは見事にきっかり「2.5」。
 確認のため予め計算しておいた「2.5」(Cの値)と
比較してみると答えは「0 (偽)」…
「2.5」なのに「2.5」と評価できない?!
この場合、変数Aの中身はどう評価するべきなんでしょう?

 このあたりが、やっぱりまだよく分からないでいるんです。

Re: 小数の連続な加算について

by hira » 2005年7月31日(日) 19:40

こんなプログラムを組んで実験してみました。

コード: 全て選択

#console
Dim a As Double
Dim Div As Long
Dim Bin As String
a=0.1
Bin="0."
For Div=1 To 200
	If a>=2^-Div Then
		Bin=Bin & "1"
		a=a-2^-Div
	Else
		Bin=Bin & "0"
	End If
Next
Print Bin
これは、0.1を2進数表示するプログラムです。
結果は 0.0001100110011… という循環小数になるはずなのですが、有効桁数というものが生じてしまい、表示結果は途中から0ばっかりになってしまいます。
簡単に言ってしまえば、電卓(Windowsのではなくて、現実の電卓です)で 1/3 を計算すると 0.3333333 ぐらいまでしか求まらないのと同じでしょうか(^^;;
これを足していくので誤差が出るものと思われます(完全な循環小数ならば誤差は出ないはずですので)。
※推測が大半です。間違いがあれば指摘してください。

by OverTaker » 2005年7月31日(日) 17:38

コンピューターは、2進法で計算しています。
そのため0.1は2進法で表すことができないために、0.1の近似値を足していっているため計算結果があのようになってしまいます。

私に説明できるのはこれくらいまでです。お互いもっと勉強しなくちゃならないですね~。

小数の連続な加算について

by jacoby » 2005年7月31日(日) 15:53

 初期値 J=4 に 0.1を繰り返し15回
加えるというプログラムを下の様に組みました。

#prompt

Dim J As Double
J=4

J=J+.1
J=J+.1
J=J+.1
J=J+.1
J=J+.1
J=J+.1
J=J+.1
J=J+.1
J=J+.1
J=J+.1
J=J+.1
J=J+.1
J=J+.1
J=J+.1
J=J+.1

Print J
Print 5.5=J

 答えは 4+0.1*15=5.5となりそうに思えたのですが
実行結果は 5.499999999…となり、5.5との比較では
0(偽)となってしまいます。
 元々、For-Nextのループで足していて起こり、念のため
ループを外して15回列記して上のように書いてみたのです
が(リストが縦長になってすみません)、同様の結果でした。
 また、初期値のJ=4ですが、他にも 「5」,「6」,「7」,「8」でも
同じような結果になるようです。
 これらの演算、何故そうなるのか理由をお知りの方が
おられましたら是非教えてください。

             実行環境 AB ver 4.04
(ver 2.62でも確認)
OS Windows Me

ページトップ