• ベストアンサー

99.98+0.01の誤差

double型での計算を行うとよく誤差が出るのは知っているのですが System.out.println(99.98+0.01); といった簡単な計算ですら数値が狂うのは何故なのでしょうか?-サブ質問1 みなさんは厳密な計算が必要なときどのように処理を行っていますか?-サブ質問2 ちなみに私はできるだけdouble型は使わないことで回避しています。 処理したい有効桁数分10^n倍していってlong型で計算したのち元に戻したりと。 もっとスマートにdouble型だけで正確に計算して使っている方が いらっしゃいましたらその技を伝授していただけませんか?-メイン質問 わかる範囲でいいのでお答えをお持ちの方がいらっしゃいましたらよろしくお願いします。

  • Java
  • 回答数5
  • ありがとう数1

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

  • ベストアンサー
  • arukamun
  • ベストアンサー率35% (842/2394)
回答No.4

こんにちは >といった簡単な計算ですら数値が狂うのは何故なのでしょうか?-サブ質問1 2進数だと無限小数(循環小数)になるから、誤差が大きく出てしまうのですね。 >みなさんは厳密な計算が必要なときどのように処理を行っていますか?-サブ質問2 私は分数の概念を使って計算させています。 結局、我々が入力する数値は整数か有限小数ですよね。 それらの四則演算は有理数同士の四則演算なので、結果が整数、有限小数、循環小数のいずれかになります。 これらを正確に表そうとすると、分母と分子が整数の分数として扱うのが良いですね。 これを使うと、例えば x=1÷3 というようにxに1÷3を入れると、xは0.33333・・・と循環小数になりますが、内部的には3分の1となっているので、 x=x×3 とやると、xは1になってくれます。 >もっとスマートにdouble型だけで正確に計算して使っている方が >いらっしゃいましたらその技を伝授していただけませんか?-メイン質問 スマートには難しいですね。 分数での処理がスマートかと言われると難しいですね。

その他の回答 (4)

  • notnot
  • ベストアンサー率47% (4848/10262)
回答No.5

>ちなみに私はできるだけdouble型は使わないことで回避しています。 >処理したい有効桁数分10^n倍していってlong型で計算したのち元に戻したりと。 少しだけスマートでいうと、10^n倍したんなら整数になっているはずなのでそのままdoubleで計算しても(有効数値15桁を超えたり、整数で割り切れない割り算をしたりしない限り・・・整数計算なので当然)誤差は出ません。 数字文字列に変換するときは10^n倍したまま、いったん文字列に入れて、下からn桁目の左に小数点を割り込ませるように文字列処理すればいいと思います。

  • chi-kon
  • ベストアンサー率43% (58/132)
回答No.3

厳密というか、 そういう困ったチャンなことが起きる場合は BigDecimal使ってこちら側の意図するどおりの桁扱いをするようにしています。 めんどくさいんですけどね。

  • furyfox
  • ベストアンサー率56% (58/103)
回答No.2

doubleは8バイトの浮動小数点です。 http://www.jtw.zaq.ne.jp/kayakaya/new/kihon/text/fudo.htm >もっとスマートにdouble型だけで正確に計算して使っている方が >いらっしゃいましたらその技を伝授していただけませんか?-メイン質問 10進数に換算すると有効桁数は15桁です。 つまり16桁目以降で誤差がでる可能性があります。 double型ではそれ以上の精度の計算は「不可能」です。 計算で誤差をだしたくないなら 整数型で分母と分子を分け、 無理数や定数は別に計算するような クラスを作ってはどうでしょうか? >ちなみに私はできるだけdouble型は使わないことで回避しています。 >処理したい有効桁数分10^n倍していってlong型で計算したのち元に戻したりと。 あまり意味があるものではありません。 結局longも8バイトの整数型なのですから有効桁数に限界があります。 longの限界は9223372036854775807 1桁けずって18桁が有効桁数です。 計算速度を考えればdoubleでやったほうが圧倒的に速いですし、有効桁数が限られている以上、精度には限界があります。

  • ranx
  • ベストアンサー率24% (357/1463)
回答No.1

> System.out.println(99.98+0.01); > といった簡単な計算ですら数値が狂うのは何故なのでしょうか?-サブ質問1 2進数で計算しているからです。99.98、0.01 はいずれも2進数では無限小数になります。 それを有限なコンピュータで計算するのですから、小数点以下のどこかでぶったぎる 必要が生じます。そのための誤差です。 > みなさんは厳密な計算が必要なときどのように処理を行っていますか?-サブ質問2 何をもって厳密と考えるかにもよります。何かの測定値であれば、そもそも最初から 誤差を含んでいますから、10進数での表現と2進数の表現とでどちらが正しいとも 言えないと思います。99ドル98セントといった数値であれば、java.math.BigDecimal等を 使うかもしれません。

関連するQ&A

  • C言語による演算時の誤差について

    C言語初心者でどなたかご教授お願いします。 小数点の演算を行うわけではないのですが、 演算を行う数値が大きすぎるために、double型を使用して以下の計算を行うつもりです。 計算結果はlong型(小数点以下切り捨て)です。 double a,b,c; long x; x = (long)((a*b/c/100) 例)  x=(long)((189000*105000/100000)/100) 上記のような計算を行った際でも誤差が発生する可能性があるのでしょうか?

  • 数値積分の累積誤差

    加速度センサから得られた対象物体の加速度を数値積分し,速度を求めようとすると累積誤差が増加して正確な速度が計算できません.これを回避するにはどうしたらよいのでしょうか?できるだけ簡単な方法をご存知であれば教えて下さい.

  • 矩形法プログラムの計算値と計算誤差の求め方

    下記の矩形法の計算値を求めるプログラムで、区間分割数nを10から100まで10ずつ増やして計算値を求めるプログラムを作成したいのですが、どのようにしたらいいのか分かりません。Java初心者なのでJavaプログラムが詳しい人は至急ご連絡をお願いします。 *ちなみにこの矩形法プログラムのの計算誤差も分かる人はお願いしたいのですが・・・・・・  計算誤差の求め方は    計算誤差=(計算値ー真値)/真値×100(%) (真値=0.68269とする) public class Kukei { static double f(double x) { // ここに任意の被積分関数を記述 double y = Math.exp(- x * x / 2) / Math.sqrt(2.0 * Math.PI); return y; } public static void main(String[] args) { double a = - 1.0, b = 1.0; // 積分範囲 int n = 100; // 区間分割数 double h = (b - a) / (double)n; // 分割幅 double s = 0.0; for (int i=0; i < n; i++) { s += f(a + i * h); } s *= h; System.out.println("区間分割数 =" + n); System.out.println("矩形法による計算値 =" + s); } }

    • ベストアンサー
    • Java
  • dounle型で計算時の誤差

    今、VC++(MFC)で、15桁の数値まで表示可能な電卓アプリを作成しています。 そこで今つまずいているのが、double型で計算したとき(演算結果が小数の場合)の誤差の問題です。 とりあえず、いろいろなHPなどの情報を見たりして、誤差問題解決を下記のようにしました。 「数値の頭(左側)から16桁目を四捨五入する」 小数の場合はほとんど誤差が生じるため、計算後、計算結果が小数ならば、必ず 上記の誤差処理を行っています。 しかしこれでは、以下の場合に不具合が出てしまいます。 ・ 0.99 999 999 999 999 ÷ 10 = 本来の答えは「0.09 999 999 999 999 9」 ⇒ しかし15桁までの表示なので、本来は「0.09 999 999 999 999」と15桁まで出力     させなくてはいけないのに、16桁目の「9」を四捨五入したせいで「0.1」という表示に     なってしまう。 16桁目を四捨五入しないと誤差をとることはできないし、でも上記の例だと正しい結果 が出力されません。 どうしたらいいのか頭を悩ませています。 何か良い解決法等あれば、ご教授お願いします!!

  • 浮動小数点数の誤差範囲を教えてください

    猿より若干頭がいい、冴えないプログラマです。 面積を計算する際は必ず誤差がないように、doubleを使わずcurrencyを使っています。 メートルなら小数点4桁で足りますが、キロメートルとなると通貨型の4桁数では足りません。 doubleを使っても、平方キロを平方センチに変換して集計しても誤差は出ないでしょうか。 実際浮動小数点数はどの程度の誤差を生むのでしょうか。猿でも分かる程度教えてください。 基礎過ぎて動物園に帰れのような批判は勘弁してください。。。

  • 数値積分について

    私が作成した下記のJavaの数値解析の矩形法のプログラムで、区間分割数nを10から100まで10ずつ増やして計算値を求め、面積の計算誤差を(計算値-真値(0.68269))/真値(0.68269)*100 (%)として計算するプログラムがまったくわかりません。Javaで数値解析をするのは初めてなのでどこが足りないのか、どこを直したら動くのか教えてください public class Kukei { static double f(double x) { // ここに任意の被積分関数を記述 double y = Math.exp(- x * x / 2) / Math.sqrt(2.0 * Math.PI); return y; } public static void main(String[] args) { double a = - 1.0, b = 1.0; // 積分範囲 int n = 10; // 区間分割数 double suti= (n-0.68269)/(0.68269*100); for(int j=0; j<n; j++){ double h = (b - a) / (double)n; // 分割幅 double s = 0.0; n=n; for (int i=0; i < n; i++) { s += f(a + i * h); } s *= h; System.out.println("区間分割数 =" + n); System.out.println("矩形法による計算値 =" + s); System.out.println("矩形法による計算誤差 =" +suti+"\n"); } } }

  • おおよその誤差の見積り

     よろしくお願いします。  昨日,竹内薫さんが書いた「白い仮説,黒い仮説」という本を読みました。その中で,視聴率に関することが書いてありました。正確な数字は忘れましたが,24%と23.6%の視聴率で24%の方が高いとはいえない。なぜなら600世帯ぐらいの調査であれば,誤差の簡便な見積りとしては600の平方根である24世帯分ぐらいの誤差 パーセントに直すと24/600で4%ぐらいの誤差がある。(正確に計算すると3.3%ぐらい)とありました。  そこで質問です。 1.誤差の簡便な見積りがサンプル数の平方根でできるのはなぜでしょうか。誤差を標準誤差とするのなら,標準偏差/サンプル数の平方根だと思います。このこととどのような関係があるのでしょうか? 2.正確に計算すると3.3%ぐらいとあった気がするのですが,上記の情報から標準偏差をどのように見積もったのでしょうか?  御回答いただけたら幸いです。

  • 数値解析の矩形法について

    区間分割数nを10から100まで10ずつ増やして計算値を求め、面積の計算誤差が区間分割数によってどのように変化するかを求める矩形法プログラムを下記に作成したのですが、 計算誤差を求める式で ・計算誤差=(計算値ー真値)/真値×100 (%) (真値は0.68269) と計算するのですが、プログラムでは分母の真値×100 (%)を()を付ける場合の計算の答えと()を付けない計算の答えとが全然違います。どうしてこのようなことが起こるのですか? また、この計算誤差の求め方は()を付ける場合とつけない場合のどちらが正しいのですか? public class Kukei { static double f(double x) { // ここに任意の被積分関数を記述 double y = Math.exp(- x * x / 2) / Math.sqrt(2.0 * Math.PI); return y; } public static void main(String[] args) { double a = - 1.0, b = 1.0; // 積分範囲 int n = 10; // 区間分割数 double suti= ((n+10)-0.68269)/0.68269*100; //真値 for(int k=1; k <= 10; k++){ double h = (b - a) / (double)n; // 分割幅 double s = 0.0; n=k*10; for (int i=0; i < n; i++) { s += f(a + i * h); } s *= h; suti= (s-0.68269)/0.68269*100; System.out.println("区間分割数 =" + n); System.out.println("矩形法による計算値 =" + s); System.out.println("矩形法による計算誤差 =" +suti+"\n"); } } }

  • javaのdoubleでの計算による誤差

    宜しくお願いします。 割り算でなくても、足し算の小数点計算で誤差がでます。 public class keisan { public static void main(String[] args) { double a1 = 12.3; double b1 = 45.6; System.out.println(a1 + b1); } } 結果が 57.900000000000006 となります。 きっちり57.9とならないのはなぜでしょう? 他の数字でも数が小数点以下でブレます。 原因に何が考えられるでしょうか? OSはWindowsXP pro ver.2002 SP3 32bit jdk 1.6.0_17 eclipseは Eclipse Platform Version: 3.5.2.R35x_v20100210-0800-9hEiFzmFst-TiEn9hNYgDWg1XN8ulH_JvCNGB Build id: M20100211-1343 を使っています。

    • ベストアンサー
    • Java
  • C#の型について(doubleとdecimal)

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

専門家に質問してみよう