• ベストアンサー

VB6.0での小数点の扱いについて

現在、VB6.0を使用しており、小数点の扱いに困っています。 Sub Keisan() Dim A As String Dim B As String Dim C As String A = 1.29033 B = 1.91458 C = CStr(A + CDec((B - A) / 6) * 3) MsgBox C End Sub 上記のプログラムを実行すると、 「1.602455000000001」と表示されますが、 電卓を用いて計算すると、 「1.602454998・・・」となり、微妙に誤差が出てしまいます。 小数点を整数にして計算→元の桁数に戻す、という 処理を行うと、誤差なく求めることが出来ましたが、 「もっとスマートなコードにして」と言われてしまいまして どうしたものかと思っております。 この誤差を解決する方法は無いでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

この問題は、パソコンと電卓との計算の誤差だと考えられます。 1.602455000000001と1.602454998 はとちらも結論から言うと正しいのだが。 問題は、(B-A)/6 が割りきれないところから出ていると思われます。    0.104041666666・・・・=(B-A)/6 電卓は、1演算の都度、小数点指定桁数で切り捨てて計算するみたいです。 これは、電卓の液晶画面が指定桁数しか表示出来ないところから来ている と思われます。 今回の問題は、電卓に合わすとの事なので、合わす為には、演算が入る 度に、電卓と同じ桁数で切捨てればOKとの事になります。 ご質問のプログラムもそこを考慮して、CDec((B - A) / 6) とわざとCDec関数を 間に入れていますが、結局小数点9桁で切り捨てられていないので、切捨てられて いない分だけ計算結果が大きくなります。 下記のプログラムが比較的簡単かなと思います。これでも完璧かどうか わかりませんが、乗算・除算の計算の度に下のfint関数を呼び出す事です。 ここで注意するのは、fint関数の2番目の引き数です。この引数は、電卓の液晶画面の 表示桁数です。下のサンプルは、表示桁数10桁(小数点も含む)にしています。 Sub Sub Keisan()   Dim A As Double   Dim B As Double   Dim C As String   A = 1.29033   B = 1.91458   C = A + fint((B - A) / 6, 10) * 3   MsgBox C End Sub Function fint(cd as double, ck as integer) As Double   cm = Format(cd, "#.000000000000000000")   fint = Left$(cm, ck) End Function 尚、演算の内容によっては、上のプログラムでもごくまれに電卓と誤差が 出る可能性があります。確立的にはどれだけかは分かりませんが0.01% 位の確立で誤差が発生するかもしれません。(推測です)。 100%絶対に合わすのであれば、ご指摘の通り、整数にて処理を するのが確実です。ただ、プログラムが複雑になる分バグも出やすく、 簡潔でそこそこ精度があるのであれば、上のプログラムで充分だと 思います。

mimi200808
質問者

お礼

ありがとうございます!!! 教えて頂いた方法で上手くいきました!!! 電卓の表示桁数で抜き取ればよかったんですね。 言われてみると納得です。 プログラムのこういう瞬間「は」すごく楽しいと思いますw しかし、小数点の演算箇所は相当数あるんですよね・・・ あれ全部修正してテストするのかと思うと怖くなってきましたw

その他の回答 (3)

回答No.4

まず、A, B, CがStringの定義なのがアレですね… 誤差を気にするのなら浮動小数点もダメです。 全てVariantで定義して、 A = CDec(1.29033) とかにしましょう。 あと、計算の中間結果((B-A)/6 とか)も浮動小数点に勝手に変換されると まずいので、 C = A + (B - A) / CDec(6) * CDec(3) とかにしたほうがいいかも。 (検証はしてません、あしからず)

mimi200808
質問者

お礼

回答ありがとうございます。 計算結果は、 A + (B - A) / CDec(6) * CDec(3) = 1.602455 でした(この値でも正しいと思うんですけどねw)。 ちなみにString型で定義してある理由ですが、、、、、不明ですw

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.2

この演算結果は1.602455が正解なのでは? CDec((B - A) / 6) * 3 は CDec((B-A)/2) とほぼ等価考えます 0.62425 / 2 = 0.312125 これに 1.29033 を加算するのですから 1.602455 となると思います CDec((B - A) / 6) * 3部分に関して 有効桁数以下でRound関数で丸めてしまうといった手法も考えられます C = CStr( A + Round( CDec( ( B - A )/ 6 ) * 3, 8 ) ) といった具合です

mimi200808
質問者

お礼

回答が遅くなり申しわけありません。 実は「3」はまた別の式を使って求めているので、正確には、 C = CStr(A + CDec((B - A) / 6) * (3))となります。 質問が正確でなくて本当にすいません。 なので、計算の順序を変えるというのは難しいかなと思っています。 回答頂きました式を実行すると、 CStr( A + Round( CDec( ( B - A )/ 6 ) * 3, 8 ) ) = 1.602455 となりました。 正確な式と、桁数を増やしてみましたが、 CStr(A + Round(CDec((B - A) / 6), 12) * (3)) = 1.602455000001 となり、まだ誤差が出てしまいました。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

除算してから乗算だと誤差が大きくなる可能性は否めないでしょう 逆に 乗算してから除算してやれば期待する結果が得られる場合があります C = CStr( A + CDec((B-A) * 3 ) / 6) といった具合で ・・・

mimi200808
質問者

お礼

回答ありがとうございます。 残念ながらその方法では上手くいかなかったです。。。 (ちなみに「1.602455」と表示されました) 「仕様です」っていって逃げたいです(笑)。

関連するQ&A