• ベストアンサー

数値計算における誤差について

小数点以下5~6桁の数値(整数部は1~5桁)を何度も積算するプログラムをSolaris7とWinXPで動作させたところ、同一データを使ったにもかかわらず誤差が生じました。非常に小さい差(0.2%程度)のものなので実用上は大きな問題はないのですが、何が原因でこうなるのでしょうか。プログラムでは数値を単精度として扱っています。

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

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.6

見つかりました。 以下のリンクが参考になると思います。 Solarisではデフォルトでどうなのかまでは知らないので、 ひょっとして的外れの可能性はありますが参考になれば。 Gauche:拡張浮動小数点演算の謎 http://practical-scheme.net/wiliki/wiliki.cgi?Gauche%3A%E6%8B%A1%E5%BC%B5%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E6%BC%94%E7%AE%97%E3%81%AE%E8%AC%8E FreeBSD QandA 587 http://www.jp.freebsd.org/QandA/HTML/587.html PHPのround関数の謎が少し解けた - hnwの日記 http://d.hatena.ne.jp/hnw/20070603 最初のリンクから。 --- 86系の浮動小数点演算ユニットのレジスタは80bitの拡張浮動小数点数 (仮数部64bit)で、floatでもdoubleでも演算は一度80bitに直してから行われ、結果が単精度または倍精度に丸められる。ところが、ある種の最適化が行われた場合、途中結果が浮動小数点レジスタに置いたままにされるため、80bitのまま演算が進行する。 その値をスタック経由で関数に渡す時にはdoubleに丸められるので、 printfに渡して印字させるだけでは違いがわからなかったのだ。 この現象はコンパイラの最適化に依存する。この例でも、-O2をつけなければ違いは発生しないし、mult10()の呼び出しをただの乗算に置き換えても発生しない。また、FreeBSDなどではプロセスの浮動小数点演算モードを明示的に拡張浮動小数点数を使うように設定してやらねばならないようである。 ---

statisticianjr
質問者

お礼

リンクの件わざわざありがとうございます。 明日会議の席上でこの誤差について説明する予定なので、 とても助かりました。 回答はこれにて打ち切りとさせていただきます。 皆さん本当にありがとうございました。

その他の回答 (5)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.5

Windows xp は x86で間違いないとして、Solarisの方もCPUはx86ですか? #7ってx86版あったっけ? もしそうだったとして、以下のような可能性があります。 x86の浮動小数点数演算は80bitの精度で計算できます。 double と書くと 64bit精度になりますが、CPUの内部では80bitの 精度で計算されています。 これを変数の領域に取り出したりするときに 80bit → 64bitの 変換がかかります。 このとき浮動小数点数の演算をするときに、コンパイラが最適化をして できる限り 80bit→64bitの取り出しをしないで計算するコードを 出力した場合と、いちいちこの変換をしながら計算を進めるコードを 出力した場合に、微妙に最下位の方の値が変る可能性があります。 たしかFreeBSDあたりでこの辺が原因のバグだかなんだかが あったような記憶があります。 #一応調べてみます って、単精度だから32bitか。 アセンブリ言語読める人を捕まえて、コードを解析して貰ったら良いかと。

statisticianjr
質問者

お礼

回答ありがとうございます。 知人から「CPUの最適化がどうこう」ということを聞いたのですが、知人自身も最適化がどういうことかよく分からないと言っていました。 この頂いた回答で最適化の意味が分かりました。 単精度においても「コンパイラが最適化をしてできる限り 80bit→32bitの取り出しをしないで計算する場合とそうでない場合がある」ということがあるとすれば説明が付くような気がします。

  • Donotrely
  • ベストアンサー率41% (537/1280)
回答No.4

#2です。 Solaris7と聞いててっきりSparcと思ってましたが、 質問文を見返すと必ずしもそうではないですね。 もしCPUが違えば#2の通りですが、もし同じならまず実行したコードの差が考えられます。 アルゴリズムやコンパイラ、オプチマイズなどに起因した計算内容の差異です。 演算の順番が違っただけで演算結果は違ってきます。 またもしかしたら数値の標準形式がSolarisとXPで違っているかもしれません。 結果を求めた後でその変換をするとそこで差が出ることもあり得ます。

statisticianjr
質問者

お礼

再度の回答、ご丁寧にありがとうございます。 すみません、私が質問に書き漏らしたのですがプログラムも同一のものなのでアルゴリズムの差ではないと思います。 身近な人に聞いたところ「OS、コンパイラの相違による差異」という答が多く、原因はやはりこの辺らしいです。

  • usokoku
  • ベストアンサー率29% (744/2561)
回答No.3

数値計算の入門書のはじめの頃に乗っているはずですが 計算機eの問題です。 単精度実数は、7.2桁ですから、無限小数(2新法で考えてくたざい)の取り扱いなので、実数部4桁ですと小数部2桁目付近で十進化・二進化の誤差が出てきます。その後の演算で、二進演算の誤差が出てきます。 これも、使っている計算機で変わるので、一概に言えません。 WinXpの使用経験はありませんので、異なっている場合があります。

statisticianjr
質問者

お礼

ご回答ありがとうございました。 この二進演算の誤差がSolaris7とWinXPで異なると言うことですね。

  • Donotrely
  • ベストアンサー率41% (537/1280)
回答No.2

内部データの形式と浮動小数点演算仕様の差に起因すると思います。 丸め誤差は出るかもしれませんが、データの形式と演算仕様が同じなら、 同じ丸め誤差が発生し、差は出ないはずです。 たぶん単精度ということなら両方とも指数1Byte + 仮数3Byteの計4Byteだと思います。 仮数の形式は符号+絶対値だったり、2の補数表現だったりします。 指数は2の補数表現だったり+128のバイアスがかかっていたりし、また基数が2だったり16だったりします。 さらに、演算途中でガードディジットを持ったり持たなかったりで、 精度に差が出ます。 大まかな差異原因はそんなところでしょう。 ちなみに、もしAMDがインテルの完全互換だったら、差は出てはいけないはずです。 もし差が出たら、完全互換とは言えません。

statisticianjr
質問者

お礼

ご回答ありがとうございました。 Solaris7とWinXPで違いが発生する可能性のある箇所が具体的に記述されているので、非常に助かりました。

  • nrb
  • ベストアンサー率31% (2227/7020)
回答No.1
statisticianjr
質問者

お礼

迅速な回答、ありがとうございました。 この丸め誤差がSolaris7とWinXPでは異なると言うことですね。

関連するQ&A

  • 計算の丸め誤差の解消について

    プログラム上で計算するときに丸め誤差が発生し、困っています。 丸め誤差が発生している計算は -0.004+0.006+0.002 なのですが、 -0.004+0.006+0.002=0 となるところが、 =8.47E-09 となってしまっています。 オーダーの異なる計算ではないにもかかわらず、どうして誤差が発生するのかが理解できず困っています。 上の数値(左辺の方)の算出は、10^(-1)のオーダーの数値から計算されています。 多分、浮動小数点を使っているからだろうと考えているのですが、どのように解消したらよろしいでしょうか? 固定小数点を用いると、浮動小数点より誤差が少ないとありましたが、Cで固定小数点を用いる方法もわからないです。 よろしくお願いします。

  • 相対誤差,絶対誤差

    相対誤差,または,絶対誤差が 10^-12以下出なければならない とあるのですが これは小数点第12位に誤差があっても大丈夫ということでしょうか? 13位に誤差があっても大丈夫ということでしょうか? そもそもc言語などのDoubleでそんな桁まで精度が出るのでしょうか? よろしくお願いします

  • 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桁目を四捨五入しないと誤差をとることはできないし、でも上記の例だと正しい結果 が出力されません。 どうしたらいいのか頭を悩ませています。 何か良い解決法等あれば、ご教授お願いします!!

  • エクセルで数値の桁数を一定の法則で統一したい

    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)バイト型(0~255の範囲。小数点以下の数値は扱えない) (2)整数型(-32,768~32,767の範囲。小数点以下は扱えない) (3)長整数型(-2,147,483,648~2,147,483,647の範囲。小数点以下は扱えない) (4)単精度浮動小数点型(-3.402823×10^38~3.402823×10^38の範囲。             小数点以下の数値が扱える) (5)倍精度浮動小数点型(-1.79769313486231×10^308~-1.79769313486231×            10^308の範囲。少数点以下の数値が扱える) (6)十進型(-10^28-1~10^28-1の範囲。小数点以下の数値が扱える) と6種類決められますが、それぞれの「選び方の違い」と「その理由」を 教えてください。 たとえば、(1)~(3)くらいなら分かります。 扱える数値の桁数が違うということですよね?で、(1)~(3)を選ぶ時と(4)~(6)を 選ぶときで大きな違いというと、「小数点以下の数値が扱えるかどうか」 ですよね?そういう認識であっているか・・・ということと、上記の(1)~(6)を 「選び分ける必要がある場合」というのを教えてください。 なぜ、このような6種類に分かれているのか、人に説明しないとなりません。 よろしくお願い致します。m(_ _)m

  • Excelで数値の小数点を揃える方法は?

    Excelの数値データで、小数点以下1桁とか2桁とかの表示にした時、整数の小数点以下を表示しない方法はありますか?しかも、小数点を中心に桁を揃えて。   12.2  300   20.4 こんな感じです。

  • Accessクエリの整数型と単精度型の演算について

    Accessのクエリで長整数型と単精度浮動小数点型を 加算すると答えが一致しません。理由を知っている人いますか? ちなみに長整数型と倍精度浮動小数点型を加算したときは答えが一致します。 浮動小数点は誤差がつきものなのは分かりますが、 確か単精度浮動小数点型は有効桁数7桁までのはず。 下記の例では問題ないように見えます。 (例)長整数型と単精度浮動小数型の演算:1000+0.20=1000.20000000298 長整数型と倍精度浮動小数型の演算:1000+0.20=1000.2 それではよろしくお願いします。

  • excelの小数点計算に誤差等について

    EXCELの小数点計算で日々の利息データなどを小数点10数桁まで使って300個以上のデータの標準偏差など求めていると仮定します。 これはもちろん計算誤差がでるものですが、 データさえ同じならいつでも別のパソコンでやってもEXCELのバージョンの違いがあっても 結果としては同じデータ結果が得られるものでしょうか。 それとも違いがでてくるものなのか。

  • accessの数値型のフィールドサイズの規定値

    access2003 迄はオートナンバー型も数値型もフィールドサイズは倍精度浮動小数点型が規定値と記憶しております。 access2010ではオートナンバー型は長整数型、数値型は整数型となっています。 周りの環境はAccess2000~Access2010まで混在しています。 規定値を一つにしたいのですが(できれば倍精度浮動小数点型)

  • UNIX フォートラン 数値計算精度

    フォートランでの数値計算精度に関して困っております。 サンマイクロシステムズ社製、UNIX、Solaris10(64bit)において、 下のフォートランプログラム、 IMPLICIT REAL*8(A-H,O-Z) X=1.0D0 A=SIN(X) WRITE(*,100)A 100 FORMAT(F50.40) STOP END を実行させると、 A=0.8414709848078965048756572286947630345821 となり、16桁以降にも数値が出てきます。 これはなぜでしょうか? UNIXコンパイラの特徴なのでしょうか?