浮動小数点型(Single,Double)の演算

ActiveBasicのバグと思われる不具合を発見された方は、こちらから知らせていただけると助かります。
返信する
メッセージ
作成者
KICO
記事: 57
登録日時: 2005年12月13日(火) 17:42

浮動小数点型(Single,Double)の演算

#1 投稿記事 by KICO »

何時も、お世話に成っています。

浮動小数点型の演算結果がおかしいです。(全バージョン)

 例えば、下記のようにiが0からだと"5.99999999999999"に
1の場合は"6.19999999999999"と云うように正しい値が得られません。

Dim i As Double

For i=0 to 10 Step 0.1
If Len(Str$(i))>3 Then debug: i=10
next


宜しくお願いします。
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

#2 投稿記事 by イグトランス »

それはCPUの都合上の問題でABの問題ではありません。
x86を始めとした現存する多くのCPUでは浮動小数点数も二進法で表現します。
十進法では有限小数だった数でも二進法で表現すると無限小数となることがあり,
無限を扱えない現代のコンピュータでは適当なところで桁を捨てるため誤差を生じることとなります。
そのためそのように一見正しくないような結果となるのです。

通常は画面へ表示するなど文字列として表現する際に,適当な桁数で丸めるなどして
下のほうの桁を見せないといった工夫によって問題を隠し,それが対処法としては最も簡単です。

もし厳密さを求めるとしたら十進法主体で表現すれば良いのです。
二進法の浮動小数点数は通常±x * 2 ^ nという形で表現され,メモリやレジスタ上ではxとnと符号を記録しています。
しかし±x * 10 ^ nの形式で演算すれば,今回の例のような十進法と二進法の違いによる誤差はだいぶ防げるはずです。
あるいはx / yというような有理数(分数)として演算するという手もあります。
いずれにしても自分でそのようなコードを書かなければなりませんし,その他の種類の誤差の発生にも気を付けなければ台無しです。
KICO
記事: 57
登録日時: 2005年12月13日(火) 17:42

浮動小数点型(Single,Double)の演算

#3 投稿記事 by KICO »

イグトランス (egtra)様、何時も ありがとう御座います。
それはCPUの都合上の問題でABの問題ではありません。
 バグではなかったのですか、失礼しました。

でも何故、例のコードの場合iの開始値が違うと演算結果も違ってくるのでしょうか?


宜しくお願いします。
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

#4 投稿記事 by イグトランス »

それはやはりおよそ開始値によって誤差の溜まり方が変わってくるということもあるでしょう。
またABのStr$が浮動小数点数を文字列にする際の処理も関係してきます。
ABのStr$は上から約15桁を文字列にしますが,それ以下の桁は四捨五入します。
値によってはこれで誤差が先程書いたように誤魔化される場合が生じるのです。
誤差が誤魔化せないほどたまってくると四捨五入の網を潜り抜け.999のように目に見えてしまうのです(これは多少不正確な例えですが)。

なお元のコードでは0.1が2を基数とした指数表記で循環小数になってしまう数です。
整数は浮動小数点数でも正確に表現できる数です。
KICO
記事: 57
登録日時: 2005年12月13日(火) 17:42

浮動小数点型(Single,Double)の演算

#5 投稿記事 by KICO »

>それはやはりおよそ開始値によって誤差の溜まり方が変わってくるということもあるでしょう。
 その解決法は、無いのでしょうか?
>またABのStr$が浮動小数点数を文字列にする際の処理も関係してきます。
>ABのStr$は上から約15桁を文字列にしますが,それ以下の桁は四捨五入します。
 Str$、Valに関しては、浮動小数点型に対応出来るよう関数を作ったので、その辺は
問題は無いと思います。


宜しくお願いします。
OverTaker
記事: 231
登録日時: 2005年5月31日(火) 17:14
お住まい: 茨城県

#6 投稿記事 by OverTaker »

その解決法は、無いのでしょうか?
その解決方法ではないのですが、イグトランスさんが仰ったように、十進数で計算するのが最も簡単な回避方法だと思います。

コード: 全て選択

Dim i Dobule
For i = 0 To 10 Step 0.1
	Print i
Next
例えば、このようなものは、下のように10倍した値で計算し、最後に10で割れば、結果的には変わりのないことです。

コード: 全て選択

Dim i Long
For i = 0 To 100 Step 1
	Print i / 10
Next
的外れな回答でしたら申し訳ありません。
KICO
記事: 57
登録日時: 2005年12月13日(火) 17:42

浮動小数点型(Single,Double)の演算

#7 投稿記事 by KICO »

OverTaker様、何時も ありがとう御座います。

>例えば、このようなものは、下のように10倍した値で計算し、最後に10で割れば、結果的には変わりのないことです。
>Code:
>Dim i Long
>For i = 0 To 100 Step 1
> Print i / 10
>Next

>的外れな回答でしたら申し訳ありません。
いいえ、回避方法としては決して的外れな回答ではないと思います。

 ただ、倍した値がLongの有効範囲の10億位を超える値は扱えないと云うように
根本的な解決方法ではないと思うのですが?


宜しくお願いします。
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

#8 投稿記事 by イグトランス »

それだったら,iの型をInt64にしたりDoubleにしたりすればどうでしょうか?
元々Doubleで計算していたものならこれで桁数などは大体間に合うと思います。
KICO
記事: 57
登録日時: 2005年12月13日(火) 17:42

浮動小数点型(Single,Double)の演算

#9 投稿記事 by KICO »

イグトランス (egtra)様、OverTaker様、 ありがとう御座いました。


Int64が有りましたね、Ver3.13でしていたものですから気が付きませんでした。

実数を扱う場合は、目的に合った回避方法で対処するしかない様ですネ。

途中から質問版に成りましたが、お答え頂きましてありがとう御座いました。

また質問の際は、宜しくお願いします。
返信する