• ベストアンサー

Double型について

 ずっと疑問でした、教えて下さい。 ついにその疑問を解き明かさなければ 次に行けない事になりました。 型はDoubleで計算をすると 0.7015-0.7=1.50000000000006E-03 という結果になりますが、 最後の6ってなんですか?この結果で比較をすると、 たまにはじかれる処理が出てくるのです。 ホントは0.0015でしょ? 他に良い方法があれば合わせて どうぞ宜しくお願いします。

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

  • ベストアンサー
  • haporun
  • ベストアンサー率40% (230/562)
回答No.8

またまた、話を付け加えますと、DecimalはVariant型の内部処理形式でしか使えません。 Dim X As Decimal '不可 Dim Y As Variant 'もちろんAs Variantは省略可 Y = CDec(0.10000000000000000000000001) Debug.Print Y '0.1が出る Y = CDec(0.1) + CDec(0.00000000000000000000000001) Debug.Print Y '0.10000000000000000000000001が出る Y = CDec("0.10000000000000000000000001") Debug.Print Y '0.10000000000000000000000001が出る 演算はまず、Variant型の内部形式がDecimalであることを認識して、それから適切な演算関数が呼び出されるのと、内部表現が複雑なこともあって、As Currencyで直接宣言した通貨型よりも多少演算速度が遅れます。 また、リテラル値でとして0.10000000000000000000000001と書いた後CDecで変換しても、0.10000000000000000000000001はDouble型ですから、かってに0.1に丸められます。 それもCDecしても0.1のままです。 3つ目の文のように文字列は正確に変換してくれますが、2個目の文のように計算する必要はないものの、文字列という超低速の形式からの変換ですから、速度は最も下です。 割り算をするとDecimal型であっても演算結果がDoubleになってしまったりと障害は多いですが、精度の高さだけがウリです。 演算速度が遅いと言っても、1000回や10000万回の計算では気になるほどではありません。 VB6になって、始めてDecimalを見つけたときは、おもしろくていろいろ遊んでみました。 HUKAHIREさんも、いろいろな式を書いてみて、いろいろ試してみてください。

その他の回答 (7)

  • haporun
  • ベストアンサー率40% (230/562)
回答No.7

>terra5: 16の指数形式は、ミニコン関係 ありゃ、すいません。 いい加減なことを言ってしまったようです。 整数でもいいですけど、DecimalもCurrencyも有効桁数だけならDoubleよりLongより上ですよ。 演算速度遅いですけどね。 もちろん、Longで計算して割り算するのとあんまり変わりません。

HUKAHIRE
質問者

お礼

 みなさん本当にありがとうございました。いろいろな方法で試してみましたがDecimalも不具合が出ないっぽいので採用かなと考えています。いろいろして頂いたのに私からなにもあげれませんが気持ちだけ、、(^-^)/■ チョコレートです。

  • terra5
  • ベストアンサー率34% (574/1662)
回答No.6

>Windows系(x86系CPU) >h × 16^n (16進数×16の自然数乗) 言語によるのかも知れませんが、Cを使っている場合は 2の指数形式、IEEEの形式ですね。 16の指数形式は、ミニコン関係で経験があります。 あと、自然数乗となってますが、正確には整数ですね。 負の値もありますから。 精度が必要で言語でそういう型が無い場合は TAGOSAKU7さんが言うような形で整数として扱います。 また、こういう誤差があるので、 こういう実数を扱うプログラムでは、=で判定せず、 差をとってある値より小さい場合は同じとみなすような プログラムを書くのがよく使う手です.

HUKAHIRE
質問者

お礼

 みなさん本当にありがとうございました。いろいろな方法で試してみましたがDecimalも不具合が出ないっぽいので採用かなと考えています。いろいろして頂いたのに私からなにもあげれませんが気持ちだけ、、(^-^)/■ チョコレートです。

  • haporun
  • ベストアンサー率40% (230/562)
回答No.5

DecimalはVariant型の内部形式でしか使えませんが、0と0.0000000000000000000000000001~79,228,162,514,264,337,593,543,950,335の10進数を扱えるので、Currencyよりびっくりです。 もちろん、doubleのように指数を使って大きな数値を表すことはできませんが。

HUKAHIRE
質問者

補足

 じゃデシマル?は平気なんですよね?

  • TAGOSAKU7
  • ベストアンサー率65% (276/422)
回答No.4

ごめんなさい。きちんと読んでませんでした。 8桁なら1億倍ですね。 それ以前に >CDecすりゃいいよ ? (cdec(0.7015)- cdec(0.7000)) の出力値は確かに0.015でした。大丈夫なのでは? うーん 奥が深い。Cdec。。。考えもしなかった。。。

HUKAHIRE
質問者

お礼

 みなさん本当にありがとうございました。いろいろな方法で試してみましたがDecimalも不具合が出ないっぽいので採用かなと考えています。いろいろして頂いたのに私からなにもあげれませんが気持ちだけ、、(^-^)/■ チョコレートです。

HUKAHIRE
質問者

補足

 大丈夫ですかね?

  • TAGOSAKU7
  • ベストアンサー率65% (276/422)
回答No.3

原因はもう述べられてますね。 >どうしようもないものなのですか、、? 1000倍した値をLong型に収めてから計算。 その値を1000で割ってはだめ?

  • ykkw_2001
  • ベストアンサー率26% (267/1014)
回答No.2

実数演算の宿命です。 ちなみに 「電卓は、10進扱いで、このような誤差はない」 とのたまう人が居ました。 「VBの甘い罠」/実数における誤差 (↓URL)

参考URL:
http://rhodes.fuis.fukui-u.ac.jp/nakata/comp/vb/vb.html
HUKAHIRE
質問者

お礼

 みなさん本当にありがとうございました。いろいろな方法で試してみましたがDecimalも不具合が出ないっぽいので採用かなと考えています。いろいろして頂いたのに私からなにもあげれませんが気持ちだけ、、(^-^)/■ チョコレートです。

HUKAHIRE
質問者

補足

 ご回答ありがとうございました。どうしようもないものなのですか、、?

  • haporun
  • ベストアンサー率40% (230/562)
回答No.1

これはdouble型が利用する記録方式として、 Windows系(x86系CPU) h × 16^n (16進数×16の自然数乗) Unixでよく使われるCPU b × 2^n (2進数×2の自然数乗) という方式を採っているからです。 人間は d × 10^n (10進数×10の自然数乗) という見かたをするので、表示するときは16進数や2進数を10進数に変換しなければなりません。 整数を変換するときは、問題ありません。 しかし、少数はほとんどの場合、10進数を16進数に変換したり、16進数を10進数に変換すると、どちらも無限小数となってしまいます。 たとえば、10進数で0.1という簡単な少数は、16進数では無限小数です。 無限小数を利用すれば、変換は互いに可逆です。 しかし、コンピュータには無限の記憶領域はないので、細かい部分は切り捨て(または繰り上げ)なければなりません。 それが今回の誤差です。 double型はおよそ10進数で15桁程度しか有効数字がありません。 0.7015と書いた場合、有効数字は15桁ですから、 0.7015 = 0.701500000000000 となります。 しかし、15桁目以降は不明です。 今回は保証されていない桁まで考えると 0.7015 = 0.701500000000000xx -) 0.7 = 0.700000000000000yy ------------------------------ 0.0015 = 0.00150000000000006 となってしまったのでしょう。 0.7015と0.7の最初の桁から15桁目まででは6という数字は現れませんでしたが、0.0015の最初の桁から15桁目まででは6が存在してしまうのです。 これを "桁落ち" といいます。 ある程度の科学計算では15桁もあれば十分です。 微妙な部分は切り捨てたり四捨五入します。 しかし、金額計算にdoubleを使ってはいけません。 利子などは数値をなん度もかけ算するので、誤差が無視できないところまでふくれあがります。 15桁などあっというまです。 VBでは金額計算に便利なCurrency型が用意されているので、金額計算をしているようならCurrencyを使います。 もちろん、少数5桁以下は切り捨てられます。 その代わり、精度は19桁ほどあります。

HUKAHIRE
質問者

補足

ご回答ありがとうございます。私の周りの人に「CDecすりゃいいよ」って冷たく言われるんですけど、、。それでは解決しない気がするんです、、私だけ、、?少数桁8桁ぐらいまで正確に計算する方法はないのですかね?

関連するQ&A

  • C#の型について(doubleとdecimal)

    C#でのdoubleとdecimalについて、 ヘルプを読むと丸め誤差の処理が異なっているとの事ですが、 どちらがより正確な計算結果が得られる方なのでしょうか? よろしくお願いします。

  • double型の減算がうまくいかない

    Java初心者です。 今、Javaの勉強中で、double型の計算を行っています。 double型同士の減算を行った結果、思っていた結果と違う値が帰ってきたので、原因、もしくは解決方法をお教え頂ければと思います。 ソースは以下 public static void main(String[] args) { //値A double longitudeA = -73.98289; //値B double longitudeB = -73.98315; BigDecimal aDecimal = new BigDecimal(String.valueOf(longitudeA)); BigDecimal bDecimal = new BigDecimal(String.valueOf(longitudeB)); //減算 BigDecimal decimal = aDecimal.subtract(bDecimal); //小数点以下第5位で四捨五入し、出力 System.out.print(decimal.setScale(5, RoundingMode.HALF_UP).doubleValue()); } 出力される値として、 0.00026 を想定していたのですが、実際に出力されたのは 2.6E-4 でした。 BigDecimalのオブジェクトをそのまま出力すると想定通りの結果が出力されます。 一回Stringに型変換を行った後、Double#parseDoubleを行ったりしてみたのですが、 どうも思った通りの出力がされません。 解決策をお教え頂ければと思います。 よろしくお願いします。

  • 型「double」「decimal」「float」について教えて下さい

    型「double」「decimal」「float」について教えて下さい。 VB2010とSQL Server 2008 R2 で開発を行っている初心者です。 単価が銭単位(例えば0.01円=1銭)の商品の金額計算を するとき、最初に変数を「Double」を使って、最後に小数点以下 のまるめ処理を行っていたところおかしな金額計算されてしまい ました。 具体的には、 Dim intSuryo As Integer Dim dblTanka As Double Dim dblKingaku As Double Dim marumeKingaku As Double If tbSuryoArray(i).Text <> Nothing Then If tbTankaArray(i).Text <> Nothing Then dblKingaku = 0 dblKingaku = intSuryo * dblTanka Select Case intMarumeKubun Case 1 : marumeKingaku = Math.Truncate(dblKingaku) '切り捨て Case 2 : marumeKingaku = Math.Round(dblKingaku, 0, MidpointRounding.AwayFromZero) '四捨五入 Case 3 : marumeKingaku = Math.Ceiling(dblKingaku) '切り上げ End Select のコードを書いて計算すると、(単価)4.31×(数量)5000 の計算が、 本来「21550」にならなければいけないのに「21549」になってしまいます。 いろいろ調べてみた結果、変数の型を「Double」にするのがいけなくて、 「Decimal」にすると誤差がなくなるということで、変数をすべて「Decimal」 に直したところ、誤差の現象がでなくなったので問題は解決しました。 問題がもうひとつおきました。 データベースの単価の型も変える必要があるかと思い、 SQL Server内のテーブルの単価のカラムを「float」から「decimal(18,0)」に 変えたところ、既に格納されている値がすべて整数に変わってしまいました。 何やらわけがわからず戸惑っていますが、同じ「Decimal」でもVBとSQL Server では利用方法が異なるのでしょうか? またVBでの「Double」と「Decimal」の使い分け、 SQL Serverでの「float」と「decimal」の使い分け、 について教えて下さい。 よろしくお願いします。

  • ダブルクォーテーションの吐き出し

    プログラムの素人の質問ですが、知ってる方教えてください。 VB6(SP5)にて、MSCommを使ってRS-232Cポートへデータを 送る処理をしています。そこで、ダブルクォーテーションを 吐き出さなければいけないのですが、「Chr(34)」だとエラーが 起きてしまいます。他にダブルクォーテーションを表示する方法は ありませんか。本当に素人くさい質問ですがよろしくお願いします。

  • long doubleの表示方法

    long doubleの型を使いたいのですが、出力するとき、 printf("%e\n", A); とすると、8桁しか出力されません。 これを16桁まで出力させる方法はないでしょうか。

  • double型で収まりきれない小数の値を求めたい。

    下記のようなプログラムを作っています。 int num = 1000; double d1 = 12345.6; double d2 = 0.0: for(int i=0;i<num;i++){   d2 += Math.pow(d1,(double)i); } d2の値を求めたいのですが、これをこのまま実行すると、得られる数値が大きすぎてd2の値がInfinityになってしまいます。 小数を格納できる最大の型はdouble型ですよね? それに収まりきらないということは、私の求めたい数値はJavaでは求めることが出来ないのでしょうか? それとも何かInfinityになってしまうのを回避する手段はあるのでしょうか? d2で得られた値はそのまま他の計算式で利用するのでどうしてもすべて小数値でなくてはならないのです。 どなたかお知恵をお貸しください。 よろしくお願いします!!

    • ベストアンサー
    • Java
  • 文字列からダブルクオートの削除

    お世話になります、 CSVからデータを取得してDBに書き込む処理を行っているのですが、CSVデータで型が文字のものはダブルクオート(")でくくっています。 (例) "りんご",100,"円" "ばなな",200,"ドル" このままデータをStringTokenizerクラスを使用して取得した場合りんごは("りんご")のようにダブルクオートがついた状態で取得されてしまいます。 ダブルクオートを取り外す方法またはメソッドを教えていただきたいのですが、よろしくお願いします。

    • ベストアンサー
    • Java
  • 【C++】double の計算結果がおかしくなる

    ouble の計算結果が状況によっておかしくなる場合があるのですが、 理由がなかなか分からないので心当たりがあれば教えてもらえませんか。 問題のコードを簡略化したのが以下です。 ------------------------------------ void calc(double *result) {   const double mPI2 = 1.5707963267948966;   double b_arc;   b_arc の計算 … (1)   // printf("test"); … (2)   *result = mPI2 - b_arc; … (3) } ------------------------------------ おかしくなるのは(3)の *result の値です。 (3)での b_arc、mPI2 の値を出力してみると b_arc: [1.57079632679489660000000000000000000000] mPI2: [1.57079632679489660000000000000000000000] となり、mPI2 == b_arc の結果も true になります。 さらに、バイナリで見ても二つは全く同じ値でした。 なので *result は 0 になるはずなのですが、これが 0 にならない場合があります。 色々な状態で試したところ結果は以下のようになりました。 1. Windows7 : 0 2. WindowsXP : -0.000000000000000001951563910473908 3. WindowsXPのデバッグビルド : 0 4. WindowsXPで(2)(2)のコメントアウトを外し printf をいれる : 0 WindowsXPのリリースビルドだけ 0 にならず、 -0.000000000000000001951563910473908 になります。 4は理由が分からないのですが、(2)の位置になんらかの処理をいれると結果が 0 になります。 ちなみにVC++ではなくQTというFrameworkを使って作っています。 よろしくお願いします。

  • ダブルクリックになってしまう?

    よろしくお願いします win2000 IE6 を利用してます 最近クリックすると、ダブルクリックしたときのような状態が起きます 一番困ってるのは、メールを見るときなのですが 読んだ後いらないメールは削除をしてますが 次のメールまで削除されてしまうことがたびたびあります まだサイトを見てるときですが プルダウンされた項目を選択するとき すぐに閉じられてしまい、選択できないことも時々あります メールのほうは本当に困っております ちなみにコントロールパネルでマウスを選んで ダブルクリックの速さを一番遅くしてますが、変わりありませんでした 解決方法がありましたら、教えてください お願いいたします

  • プログラムする言語によって精度は変わる?

    当たり前のことかもしれませんが 同じ計算をするプログラムを作っても double型の計算をした場合 計算結果が変わるものでしょうか? CとCOBOLを比較した結果違いがでました。 なんで違うのか説明が載っているものは どこかにあるでしょうか?

専門家に質問してみよう