ab.com コミュニティ

ActiveBasicを通したコミュニケーション
現在時刻 - 2024年3月28日(木) 16:59

全ての表示時間は UTC+09:00 です




新しいトピックを投稿する  トピックへ返信する  [ 9 件の記事 ] 
作成者 メッセージ
投稿記事Posted: 2007年2月21日(水) 12:39 
オフライン

登録日時: 2005年12月13日(火) 17:42
記事: 57
何時も、お世話に成っています。

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

 例えば、下記のように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


宜しくお願いします。


通報する
ページトップ
 記事の件名:
投稿記事Posted: 2007年2月21日(水) 14:54 
オフライン

登録日時: 2005年5月31日(火) 17:59
記事: 899
お住まい: 東京都
それはCPUの都合上の問題でABの問題ではありません。
x86を始めとした現存する多くのCPUでは浮動小数点数も二進法で表現します。
十進法では有限小数だった数でも二進法で表現すると無限小数となることがあり,
無限を扱えない現代のコンピュータでは適当なところで桁を捨てるため誤差を生じることとなります。
そのためそのように一見正しくないような結果となるのです。

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

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


通報する
ページトップ
投稿記事Posted: 2007年2月21日(水) 18:58 
オフライン

登録日時: 2005年12月13日(火) 17:42
記事: 57
イグトランス (egtra)様、何時も ありがとう御座います。
引用:
それはCPUの都合上の問題でABの問題ではありません。
 バグではなかったのですか、失礼しました。

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


宜しくお願いします。


通報する
ページトップ
 記事の件名:
投稿記事Posted: 2007年2月21日(水) 21:31 
オフライン

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

なお元のコードでは0.1が2を基数とした指数表記で循環小数になってしまう数です。
整数は浮動小数点数でも正確に表現できる数です。


通報する
ページトップ
投稿記事Posted: 2007年2月21日(水) 22:18 
オフライン

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


宜しくお願いします。


通報する
ページトップ
 記事の件名:
投稿記事Posted: 2007年2月21日(水) 22:46 
オフライン

登録日時: 2005年5月31日(火) 17:14
記事: 231
お住まい: 茨城県
引用:
その解決法は、無いのでしょうか?
その解決方法ではないのですが、イグトランスさんが仰ったように、十進数で計算するのが最も簡単な回避方法だと思います。
コード:
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
的外れな回答でしたら申し訳ありません。


通報する
ページトップ
投稿記事Posted: 2007年2月22日(木) 18:35 
オフライン

登録日時: 2005年12月13日(火) 17:42
記事: 57
OverTaker様、何時も ありがとう御座います。

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

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

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


宜しくお願いします。


通報する
ページトップ
 記事の件名:
投稿記事Posted: 2007年2月22日(木) 19:29 
オフライン

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


通報する
ページトップ
投稿記事Posted: 2007年2月22日(木) 23:32 
オフライン

登録日時: 2005年12月13日(火) 17:42
記事: 57
イグトランス (egtra)様、OverTaker様、 ありがとう御座いました。


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

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

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

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


通報する
ページトップ
期間内表示:  ソート  
新しいトピックを投稿する  トピックへ返信する  [ 9 件の記事 ] 

全ての表示時間は UTC+09:00 です


オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[1人]


トピック投稿:  可
返信投稿:  可
記事編集: 不可
記事削除: 不可
ファイル添付: 不可

検索:
ページ移動:  
Powered by phpBB® Forum Software © phpBB Limited
Japanese translation principally by ocean