単純な計算の筈が

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
河川屋

単純な計算の筈が

#1 投稿記事 by 河川屋 »

#N88BASIC
dim i1 as integer
dim a1,a2 as single
dim l1,l2 as long
dim q1,q2 as int64
dim x,y as double
i1=3.14
l1=2^50
a1=1+10^-10
a2=10^-100
q1=2^60+1
q2=q1-2^60
x=a1/0

というプログラムの実行結果です。 (AB_4.10.00)

 「デ」はデバッグモード実行、リはリリースコンパイル。

 デ       リ  正しい結果 備考
i1=3.14       3  3     デは、整数なのに小数以下も代入できている。
l1=112589990684262 0 計算エラー longの最大値(2147483647)より大きい数値が代入された。
a1=1.0000000001   -9  1.0 単精度に代入した時点で情報落ちを起こし1.0となる。
                   デは、有効7桁以上保持しているし、
                   リに至っては意味不明。
a2=0        -100 ゼロ    単精度に代入した時点で無限小と判定されゼロとなる。
                   リの計算結果は意味不明。
q1=約4.6e18    ゼロ 2^60+1(約1.15e18) int64以下の範囲内なので整数で表せるはず。 
                   ついでに、print文はintが相手のときは整数表示できる
                   筈なのに実数標記 (fortranでいうE変換標記)になっている。
q2=0       約-1.15e18 1   デは桁落ちしている。リはq1がコケているため異常反応。
                   int64の範囲内なので桁落ちは起こさないはず。       
y=永久ループ    0  ゼロ割りエラー これは、勝手にゼロで置き換えないでほしい。

以上のとおり、計算誤差が生じない筈のところで計算誤差が生じたり、
変数の型からして記憶できない筈の値が記憶されていたり、
デバッグモードとリリースモードでまるで違う計算結果が生じたりと、
悲惨な結果になりました。

おそらく、「数値は全て倍精度で計算している」というような大チョンボをやっている可能性が大きい
ものと思われます。
マティ
記事: 161
登録日時: 2005年8月23日(火) 00:15
お住まい: 沖縄県
連絡する:

#2 投稿記事 by マティ »

こちらの環境では[AB4.1]

全てリリース版と同じ結果になりました。
旧バージョンでは変数定義が上記の通りなら、a1,l1,q1,xはDouble型になります。
(答えの結果が異なるのは問題ですが・・・)

しかし、xの項目をPrintすると、永久ループになりますね!
マティ
記事: 161
登録日時: 2005年8月23日(火) 00:15
お住まい: 沖縄県
連絡する:

#3 投稿記事 by マティ »

[AB]にはOn Error命令が実装されていないので、計算エラーがうまくいかないようです。機能強化に要望します?

あと#strictを付けてデバッグコンパイルすると分かりますが・・・
基本的に数値項目は
 整数:Long
 小数の桁が少ない:Single
 小数の桁が多い :Double
のようです。ヘルプではDouble型って書いてあったような気がします!
一般的に計算は、右辺の最大精度で計算し結果を左辺の型に変換して代入します。

また負のべき乗は、括弧を付けないと正しく式を判定できないようです。
この件も、改善依頼します?
(自分の経験では、計算順番はコンパイラに依存しないようにする為に、式は必ず括弧で囲むってのがあります・・・)

以下のようにコードを書き換えると、エラー以外は実行出来ると思います。

コード: 全て選択


#N88BASIC
#strict
dim i1 as integer 
dim a1 as single , a2 as single 
dim l1 as long   , l2 as long 
dim q1 as int64  , q2 as int64 
dim x  as double , y  as double 
 
i1=3.14
l1=2^50
a1=1+(10^(-10))
a2=(10^(-100))
q1=(2 ^ 60 ) As Int64 +1
q2=q1-(2 ^ 60) As Int64
x=a1/0
Print命令に数値を指定すると、Double型として変換しますのでInt64が正しく表示できるかわかりません。
マティ
記事: 161
登録日時: 2005年8月23日(火) 00:15
お住まい: 沖縄県
連絡する:

#4 投稿記事 by マティ »

いつも的確なアドバイスを頂ける河川屋さんの質問とはしらず「飲みながら」回答しましたが・・・
こんな回答でよかったのでしょうか?

本当は、山本様に修正依頼を行う予定で質問を投げかけたのではないでしょうか?
そうなら、ごめんなさい。
河川屋

#5 投稿記事 by 河川屋 »

>[AB]にはOn Error命令が実装されていないので、計算エラーがうまくいかないようです。機能強化に要望します?
これは、明白な「バグ」であるので書いたのです。

以下、ゼロ割りを例にとります。

理由の1
デバッグモードとコンパイルモードで結果が違うということは、デバッグモードの存在意義が無くなるため。
理由の2
IEEE754の基準に違反しているため。
http://www.ma.is.saga-u.ac.jp/minamoto/doc/kyudai.pdf
9ページ。
まあ、ABはIEEE754準拠とはどこにも書いてないのですが、
準拠していないともどこにも書いてありません。
(この点、十進BASICとは明確に異なる。)
なお、IEEE754では以下の通り。
 ※マニュアル未記載ですが、ABの実数の内部形式はIEEE754です。
 ※※IntesCPUはIEEE754にしたがっているため。
ゼロ割り:±Inf
無効演算(√-1,log(-1)など):NaN(非数値)
※InfやNaNは、特殊な数値であり、以降の計算でInfやNaNを含む演算はInfやNaNとなる。

ですから、
セロ割りが生じた場合、

ゼロ割りエラーで停止(N88Basicの動作)  または
±Infとして計算続行 (当然ながら、Infを含んだ演算はInfやNaNを返すものとする。)

のいずれかなら正しい結果です。
※Print x/0 などについても、Inf として出力されることに注意。

でも、現状は、
・デバッグモードの永久ープ:論外。
・コンパイルモ-ドで答=0:論外。数学として間違っている。
としか言いようがないです。

ON ERROR 文は、こういうチョンボからみればどうでもいいツマラナイ状況です。

※※IEEE754準拠を徹底的につきつめると、
 ・IntelCPUは超越関数に対し1.5bit以内の誤差の計算結果を保証する
  となるけど、ABはここまでの保証ナシ、ですよね?
  (IntelCPUは80bitで計算しているが1.5bit以内の誤差が確保できる程度。
  よって、64bitで計算しているABは1.5bit以上の計算誤差が発生する。)
返信する