dounle型で計算時の誤差
- VC++(MFC)で15桁の数値まで表示可能な電卓アプリを作成中です。double型で計算する際の誤差の問題について困っています。
- 誤差問題の解決策として、「数値の頭から16桁目を四捨五入する」という方法を試しています。
- しかし、この方法では「0.99 999 999 999 999 ÷ 10」の計算結果が「0.1」になるなど、正しい結果が得られない場合があります。どのように対処すればよいか、アドバイスをいただけないでしょうか。
- ベストアンサー
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桁目を四捨五入しないと誤差をとることはできないし、でも上記の例だと正しい結果 が出力されません。 どうしたらいいのか頭を悩ませています。 何か良い解決法等あれば、ご教授お願いします!!
- smile_yuki
- お礼率12% (7/56)
- C・C++・C#
- 回答数6
- ありがとう数0
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
こんにちは。 他の回答者さんも書かれているように、 まず基本的に、浮動小数点形式の実数値での計算を行う場合は、予め 仕様として、小数点以下桁数を、そのシステム(処理系)の演算精度に 合わせて決めうちで設定しておいて、その桁数を超えた値については、 丸め処理(四捨五入、切り捨て、切り上げ)を行うしかないと思います。 そして可能であれば、実数値は以下のように整数値に変換してから、 計算を行うようにすれば、見かけ上、計算誤差を抑えることが可能だと 思います。 ■浮動小数点形式の実数値の整数化演算 1)計算に使用する値は、全て小数点以下の値を含まない整数値に変換 (小数点位置をずらして整数化)して、整数値のみで計算を行う。 2)計算時の小数点以下の値が発生する場合の処理方法(四捨五入、 切り捨て、切り上げ)は、予め決めておく。 3)値を表示、及び出力する段階で、整数値を実数値に再変換(小数点 位置の復元化)する。 以下は、上記の処理を行うサンプルです。 宜しければ検証してみて下さい。 ■サンプルソース(下記リンク先参照) http://ideone.com/RtxSu ■サンプルの実行結果 == [入力値÷10.0]の計算[1](小数点以下桁数=14桁) == 入力値 (整数値)= 99999999999999.00 出力値1(整数値)= 10000000000000.00 (÷10.0で4捨5入) 出力値2(整数値)= 9999999999999.00 (÷10.0で切り捨て) 出力値3(整数値)= 10000000000000.00 (÷10.0で切り上げ) 入力値 (実数値)= 0.9999999999999900 出力値1(実数値)= 0.1000000000000000(÷10.0で4捨5入) 出力値2(実数値)= 0.0999999999999900(÷10.0で切り捨て) 出力値3(実数値)= 0.1000000000000000(÷10.0で切り上げ) == [入力値÷10.0]の計算[2](小数点以下桁数=14桁) == 入力値 (整数値)= -12345678901234.00 出力値1(整数値)= -1234567890123.00 (÷10.0で4捨5入) 出力値2(整数値)= -1234567890123.00 (÷10.0で切り捨て) 出力値3(整数値)= -1234567890124.00 (÷10.0で切り上げ) 入力値 (実数値)= -0.1234567890123400 出力値1(実数値)= -0.0123456789012300(÷10.0で4捨5入) 出力値2(実数値)= -0.0123456789012300(÷10.0で切り捨て) 出力値3(実数値)= -0.0123456789012400(÷10.0で切り上げ) == [入力値÷10.0]の計算[3](小数点以下桁数=14桁) == 入力値 (整数値)= -12345678901235.00 出力値1(整数値)= -1234567890124.00 (÷10.0で4捨5入) 出力値2(整数値)= -1234567890123.00 (÷10.0で切り捨て) 出力値3(整数値)= -1234567890124.00 (÷10.0で切り上げ) 入力値 (実数値)= -0.1234567890123500 出力値1(実数値)= -0.0123456789012400(÷10.0で4捨5入) 出力値2(実数値)= -0.0123456789012300(÷10.0で切り捨て) 出力値3(実数値)= -0.0123456789012400(÷10.0で切り上げ) 以上です。
その他の回答 (5)
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
直接の回答ではありませんが、 double と long double のデータサイズについて。 手元にある、32bit Windows 用の Borland の処理系(Borland C++ 5.82)の例では、 sizeof(double) は、8 sizeof(long double) は、10 です。 IEEE 754形式を採用している場合、float は単精度、double は倍精度、long double は拡張精度になっているケースが多いかと思いますが。
- yama5140
- ベストアンサー率54% (136/250)
>どうしたらいいのか頭を悩ませています。 「見た目」だけでしょ、悩むこと無いと思います。 >本来は「0.09 999 999 999 999」と15桁まで出力させなくてはいけない 「いけない」んだったら↑このように、「表示」する電卓アプリを作るしかない。 その仕様は、「はみ出た16桁目を★切り捨てる」とすればいい。 「0.1」という電卓での「2桁」ではなく、「15桁まで」が目的だったら、「いろいろなHPなどの情報」どおり「はみ出た16桁目を★四捨五入」し、 「0.10 000 000 000 000」と「表示」する電卓アプリを作ればいいと思います。 数値的に見ると、当然、切り捨てた方が「誤差」は大きくなります。 >16桁目の「9」を四捨五入したせいで「0.1」という表示になってしまう。 Win7 の電卓で .9・・99 と入れられるだけ入れて、/ 10 してみたら同じ結果になりました。 マイクロソフトも、 >「数値の頭(左側)から**桁目を四捨五入する」 という規則を守っているのかな。 ところで、 0.00 000 000 000 009 ÷ 10 = 本来の答えは「0.00 000 000 000 000 9」 なので末尾の 9 を四捨五入して 「0.00 000 000 000 001」 となりますが、これも >正しい結果が出力されません。 となるのですか。すごく「まとも」と思いますが、・・・。 ご質問は、上へ上へと繰り上がっていっただけで、まったくいっしょですよ。 タイトルは、「dounle型で計算時の誤差」より、「15桁電卓の表示方法について」が良かったかも・・。
- sygh
- ベストアンサー率76% (42/55)
long doubleが80bit精度だったのはWin16時代の話です。 Win32/Win64ではlong doubleはdoubleと常に同じ8Byteサイズ・64bit精度であり、仮数部精度は53bitです。 なのでいまさらWindowsでlong doubleを使う意味は無いです。 単純に精度を上げるには、「固定小数点数」を自前で実装して使用するか、.NETのSystem.Decimal型を使う手があります。 // VC++ 2005/2008のC++/CLI用サンプル。 #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { Console::WriteLine("SizeOf(Decimal) = {0}", sizeof(Decimal)); #if 0 Decimal dec = Decimal(0.999999999999999); // double の限界有効桁数。 #else // 文字列から生成する方法。 Decimal dec; Decimal::TryParse("0.9999999999999999999999999", dec); #endif Console::WriteLine("{0}", dec.ToString()); dec /= Decimal(10); Console::WriteLine("{0}", dec.ToString()); Console::WriteLine(L"Press any..."); Console::ReadKey(true); return 0; } MFCアプリに共通言語ランタイム(CLR)のサポートを追加して(/clr)、共通プロパティで適切な参照設定を行なえば、doubleより高精度の10進数用Decimal型を使えるようになりますが、当然doubleと比較して速度性能は犠牲になります。
- notnot
- ベストアンサー率47% (4848/10261)
0.09 999 999 999 999 ___1 234 567 890 123 と、13桁ですけど。これを15桁と思うと言うことは、1の位のゼロから数え始めてますね。先行するゼロを無視して有効数字の最初から数えないと駄目です。
- kopanda116
- ベストアンサー率37% (88/232)
doubleは 32bit機と64bit機では長さが違います。 32bit機で普通のdoubleより長くしたいのであれば、 long double という型があります。 長さが2倍になります。 これを使うと良いと思います。
関連するQ&A
- エクセルで小数点以下3桁を四捨五入して、小数点以下1桁を表示する方法
エクセル2003を使用しています。 計算式から出た結果に対して、小数点以下3桁を四捨五入して、小数点以下2桁ではなく、1桁を表示したいです。 例えば、計算式の結果、 1.145 の場合、普通に四捨五入すると 小数点以下1桁なら、1.1 小数点以下2桁なら、1.15 となってしまいます。 これを小数点以下3桁を四捨五入して、小数点以下1桁表示の1.2と表示させたいのですが、可能でしょうか?
- ベストアンサー
- オフィス系ソフト
- 計算結果値そのものの切り捨て、四捨五入
EXCEL97で割り算の計算結果です。 例えば、5÷3=では、内部数値が、1.666666…となりますが 内部数値を (1)小数点以下2桁と切り捨てたい →1.66になる (2)少数3桁目を四捨五入して小数点以下2桁としたい →1.67になる にするにはどうするのですか? 該当セルの見かけ表示の設定で(1)、または(2)にするのではなく、 値そのものを調整したいのです。
- ベストアンサー
- オフィス系ソフト
- エクセルで数値の桁数を一定の法則で統一したい
E列にA~D列のデータから計算された数値が並んでいます。 たとえば E1:9.9 E2:86.08695652 E3:212.8571429 E4:1158.13953488372 これらを E1:9.90 (整数1桁の場合は四捨五入して小数2桁まで) 1未満の数値も小数2桁で(例、0.96) E2:86.1 (整数2桁の場合は四捨五入して小数1桁まで) E3:213 (整数3桁の場合は四捨五入して小数カット) E4:1158 (整数4桁の場合は四捨五入して小数カット) 上記の法則で見やすく整理したいのです。 整数4桁が最大です。大量のデータをまとめて整理出来る方法は ないでしょうか?よろしくお願いします。
- ベストアンサー
- その他(データベース)
- 有効数字(有効桁)の考え方
小数を含んだ計算ですが,以下の押さえで正しいでしょうか? いくつかサイトを見て,こうなのかな?と思ってまとめてみたのですが... ((1)の「4」,(2)の「5」に関しては誤差を含まない数とする) (1)6.523×4=26.092 (2)6.524×5=32.620 (小数第3位の0は必要) (3)65.23+6.524=71.754 →71.75(四捨五入(各々4桁故)) (4)65.23÷6.524=9.99846719… →9.998(四捨五入) (5)65.23÷6.52=10.00460122… →10.0(四捨五入(6.52が3桁故答えは3桁まで)) (6)6.523×6.524=42.556052 →42.46(四捨五入(各々4桁故)) (7)6.523×6.52=42.52996 →42.5(四捨五入(6.52が3桁故)) 正しいでしょうか?
- 締切済み
- 数学・算数
- iアプリで小数計算するのに困ってます。
iアプリで小数計算するのに困ってます。 たとえば計算結果が0.123456789とある場合、 0.123 と表示する桁を指定したいと思っています。 小数4桁目を四捨五入、もしくわ切り捨てでもいいです。 ご存じの方教えていただけないでしょうか。 開発環境はstar-1.3を使用しています。 よろしくお願いします。
- ベストアンサー
- Java
- 化学での有効数字について(途中計算)
以下についてアドバイスいただけると助かります。 有効数字について 和・差について・・・小数点以下の桁数が少ない方に合わせる 積・商について・・・桁数が少ない方に合わせる については、分かったのですが、有効数字3桁での指定があるときに 19.1、24.5889、0.12553、3.2952の4つの数にたいして ○和を筆算で求める場合 小数第1位に合わせるために、 19.1→19.10(小数第2位表示) 24.5889→24.58(小数第3位切り捨て) 0.12553→0.12(小数第3位切り捨て) 3.2952→3.29(小数第3位切り捨て) として和を求め、小数第1位(小数第2位四捨五入)にする ○積を筆算で求める場合 有効数字3桁に合わせるために、 19.1→19.10(有効数字4桁表示) 24.5889→24.58(5桁目切り捨て) 0.12553→0.1255(5桁目切り捨て) 3.2952→3.295(5桁目切り捨て) として積を求め、有効数字を3桁(4桁目は四捨五入)にする と思っています。 1.このやり方で大学受験では問題ないのでしょうか。 特に気になっているのは、計算をする前の丸め方(すべて切り捨てにしているところ)です。 2.計算ステップがいくつもあり、一度に計算ができない場合、そのステップ毎に得られる数の 丸め方は切り捨て・四捨五入のどちらがよいのでしょうか。 よろしくお願いします。
- ベストアンサー
- 化学
- 四捨五入関数を作りたい
Cでdouble型の数値の四捨五入を考えています。 小数点7桁目を四捨五入したいです。 1000000倍して0.5足して切り捨てる やり方が載っていました。 しかし1000000倍した時に誤差で「.3999999」となる ことがあるようです。 どうやったら回避できるのでしょうか。
- 締切済み
- C・C++・C#
- EXCELで税込税抜き金額を計算する時に発生する、合計金額の誤差について
【教えてください】 エクセルで税込金額から税抜き金額を自動計算し、それぞれ、複数の金額を合計すると、数円の誤差が生じてしましまいす。 合計誤差を0にするためには、(税込合計=税抜き合計×1.05にするためには)どのようにすればよいのでしょうか。 現在は一度自動計算し、誤差を手入力で修正しています。 何かいい方法があれば教えてください。 ちなみに、税抜き金額は税込金額÷1.05で自動計算しています。(小数点一桁で四捨五入し、整数にしています。) よろしくお願い致します。
- 締切済み
- オフィス系ソフト