HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2008
0802
クルト実数値の除算について6解決


クルト

リンク

2008/8/2(Sat) 10:45:50|NO.17822


if 0.000001=0.000002/2 : mes "Yes" : else : mes "No" if 0.000001=0.000003/3 : mes "Yes" : else : mes "No" if 0.000001=0.000005/5 : mes "Yes" : else : mes "No" if 0.000001=0.000007/7 : mes "Yes" : else : mes "No"

上記のように計算させると、0.000001=0.000005/5のときだけNoになるのですが、
何故Yesにならないのでしょうか?
よろしくお願いいたします。



この記事に返信する


たこ

リンク

2008/8/2(Sat) 11:12:42|NO.17823

すいません、まったく原因が分かりませんでした
HSPだけのバグかと思いC言語でも試してみましたが、
結果は同じでした



KENTA

リンク

2008/8/2(Sat) 11:27:43|NO.17824

>0.000001=0.000005/5のときだけNoになるのですが
原因は分かりませんが下のスクリプトの16進数で比べてみると、
なぜか0.000005/5や0.00007/7、0.0003/3の数が他の数と違っています。

pos 10,10 mes "0.001=d2f1a9fc" mes " 0.001 $"+strf("%x",0.001) //$d2f1a9fc mes " 0.002/2 $"+strf("%x",0.002/2) //$d2f1a9fc mes " 0.003/3 $"+strf("%x",0.003/3) //$d2f1a9fc mes " 0.005/5 $"+strf("%x",0.005/5) //$d2f1a9fc mes " 0.007/7 $"+strf("%x",0.007/7) //$d2f1a9fc mes "0.0001=$eb1c432d" mes " 0.0001 $"+strf("%x",0.0001) //$eb1c432d mes " 0.0002/2 $"+strf("%x",0.0002/2) //$eb1c432d mes " 0.0003/3 $"+strf("%x",0.0003/3) //$eb1c432c mes " 0.0005/5 $"+strf("%x",0.0005/5) //$eb1c432d mes " 0.0007/7 $"+strf("%x",0.0007/7) //$eb1c432d mes "0.00001=$88e368f1" mes " 0.00001 $"+strf("%x",0.00001) //$88e368f1 mes " 0.00002/2 $"+strf("%x",0.00002/2) //$88e368f1 mes " 0.00003/3 $"+strf("%x",0.00003/3) //$88e368f1 mes " 0.00005/5 $"+strf("%x",0.00005/5) //$88e368f1 mes " 0.00007/7 $"+strf("%x",0.00007/7) //$88e368f0 mes "0.000001=$a0b5ed8d" mes " 0.000001 $"+strf("%x",0.000001) //$a0b5ed8d mes " 0.000002/2 $"+strf("%x",0.000002/2) //$a0b5ed8d mes " 0.000003/3 $"+strf("%x",0.000003/3) //$a0b5ed8d mes " 0.000005/5 $"+strf("%x",0.000005/5) //$a0b5ed8e mes " 0.000007/7 $"+strf("%x",0.000007/7) //$a0b5ed8d



p

リンク

2008/8/2(Sat) 12:07:10|NO.17825

たぶん計算の誤差が入ってるんじゃないかと。
実数の計算とか、実数の比較などで検索すると
いろいろ出てきます。

解決するには、ある程度の誤差を容認するか、
strfで文字列に変換してから比較すれば
とりあえず正しい結果にはなってくれます。


a = 0.000001 b = 0.000005/5 //誤差が0.00000000001以下なら等しい。 if absf(a - b) < 0.00000000001 : mes "Yes" : else :mes "No" //一旦文字列に変換して等しいなら等しいとする。 if a = strf( "%f",b) : mes "Yes" : else :mes "No"



begriff

リンク

2008/8/2(Sat) 12:16:16|NO.17826

こんにちは、begriffです
浮動小数点数の構造を理解すればわかると思うのですが
小数をコンピュータで扱うときは2進数になります。
そのときに絶対的に誤差が生じます。
たとえば
mes strf("%17.17f",1.0/5.0)

実行すればわかる通り 1/5 すら正しく計算できないのですこれは二進数で処理をしているからです なぜこのようなことが起こるかと言いますと、1→1 5→101 というように二進数に置き換えて計算してください
     0.0011000
101 )1 
     1 000
       101
        110
        101
          1000
           101
            110
            101
              1000
十進数なら0.2と割り切れますが二進数で計算すると0.00110001100011・・・
となり、割り切ることができず、正確な数値を求めることが不可能なのです。
では
0.5/5ぐらいは計算できてしまいそうですが実際計算できません。
そもそも0.5は5/10という値ですまずこの値を二進数で表現しましょう

       0.1 1010)101      1010      1010         0
これは難なくいきました。
では 0.1/101 を計算してみます
  
    0.000110001 101)0.1       1000        101         110         101           1000            101             110             101               1000
やはり割り切れません。



SYAM

リンク

2008/8/3(Sun) 06:07:02|NO.17844

ぷろぐらまには、昔から、「実数は = で判断しない」っていう教えがあります。


a=0.0f *START a = a + 0.1f if (a=20) : end wait 1 goto *START

こんな感じのプログラムが引き合いに出されます。
実行してみると分かりますが、終わりません。
誤差を自動的に補正するような言語でもない限り、Cだろうがなんだろうが同じ事が起きます。

begriffさんの回答にある通り、10進法では表せてるように見える数字が実はコンピュータにとって表しきれない量であることが原因です。

10進法では、 1/3 を小数で表すことが不可能ですよね。 0.33333…になってしまい、無限に続きます。
それでは扱えないからといって、 0.33333333 として扱ってしまうと、本来の 1/3 と比較して 0.0000000033333…の誤差が発生しますよね。

それとまったく同じように、2進法では1/10を小数で表すことができないのです。

= での比較は完全に一致していないと成り立たないので、こうした誤差を含んでしまう実数では使わないようにしましょう。



クルト

リンク

2008/8/4(Mon) 09:46:01|NO.17875

一緒に考えてくれたみなさん、丁寧に説明してくださったみなさん、どうもありがとうございます。
大変勉強になりました。



ONION software Copyright 1997-2023(c) All rights reserved.