• ベストアンサー

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

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

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

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

あります。 浮動小数点数というのは、 a * mのn乗 という形をしています。 例えば 0.2 * 10の5乗 等。このときの a を仮数部、nを指数部といいます。 コンピュータは無限ではありません。aもnも無限の桁があるわけではありません。 仮数の範囲を越えたら、はみ出した分は丸められます。 nの範囲を越えたら、オーバーフローで計算できません。 環境、実装によって詳細は変わってきますが、よく使われる実装を考えます。 http://ja.wikipedia.org/wiki/%E5%80%8D%E7%B2%BE%E5%BA%A6 誤差が無いのは、 値= k * 2^n (k,nは整数) として表現できる場合のみです。 また、仮数部は52ビット(正確には、自動で1を補うので53ビット)の整数です。それを越えるものは丸められて誤差になります。 longが32ビットの場合、long * long は最大64ビットです。53ビットより大きいので、打ち切られる可能性があります。 z / y が割り切れて整数になれば誤差は出ません。 しかし、割り切れずに小数を使うことになったら、誤差が発生すると考えた方がよいでしょう。 (通分して z0/(2^i)の形になるのなら、 z0 * 2^(-i)で誤差の無いものになる可能性があります) ただ ・最終的にlongにするので、小数部は切り捨てられる ・誤差は下位の方に出る ことを考えれば、影響は少ないと思います。 違いが出るのは、結果が0.9999... みたいな値になって、丸め誤差で 切り上がって1.000→(long)で1になるか、切り捨てられて 0.999→(long)で0になるか、というような場合です。

その他の回答 (2)

  • asciiz
  • ベストアンサー率70% (6642/9410)
回答No.2

計算誤差ではなく解釈ミスが発生していると思います。 Cプログラム上で単純に 100 と書いた場合、それは「int」の100です。 floatやdoubleの100だったら「100f」「100.0」あるいは「1.0e+2」と書かなければいけません。 それが原因で、何が起こるかというと。 > x = (long)(a*b/c/100) こちらはまあいいです。a・b・c がdoubleと宣言されているので、(a*b/c/100) の 100 は doubleに昇格して計算され、最終結果が (long) にキャストされます。 >x=(long)((189000*105000/100000)/100) これが問題です。 「(189000*105000/100000)/100)」、これは全て、整数の int で書かれています。 そうすると、この計算は、int の範囲で行われます。 intの演算というのは、intの範囲で納まらなければオーバーフローとなって全く信頼できない物になりますし、割り算では小数点が出ないので、例えば「9/4」の結果は「2」となります。 そうして整数で計算された結果が、(long) にキャストされるのですから、計算結果は整数にしかなり得ません。 解釈が違うのですから、演算誤差どころの話ではないわけです。 後者の式で正しい結果を得たければ、 >x=((long)189000*(long)105000/(long)100000)/(long)100) とするか、 >x=(long)(189000f*105000f/100000f)/100f) のように書けば良いでしょう。

mhitomi9302
質問者

お礼

ありがとうございます。 直接数値を使用すると"f"で明示する必要があるのすね。 ご教授ありがごうございました。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.1

double型のような浮動小数点型を使えば、ほとんどの場合に計算誤差がついて回ります。 ただ、その型で表現できる精度を超えない範囲であれば、正確に結果を出せる可能性はあります。 処理系不明ですので正確なことはいえませんが、多くの場合、double型の仮数部の精度は(ケチビットを含めて)53ビットです。 long double型を使えば、処理系によってはもっと高い精度になることもあります。 また、C99以降に対応した処理系などでは、64ビットの精度を持つlong long型が使えますので、そちらも検討してみてください(64ビットの処理系では、long型が64ビットの場合もあります)。

mhitomi9302
質問者

お礼

ありがとうございます。 long long型なるものがあるのですね。 調べてみます。 ご教授ありがごうございました。

関連するQ&A

  • エクセル浮動小数点演算誤差?が見えない

    エクセル2010です。 BOOK-AのシートBのE7セルに0.822という数値が入っています。 見た目も、数式バー上も0.822です。 BOOK-BのシートCのE7セルにも0.822という数値が入っています。 見た目も、数式バー上も0.822です。 ところがこれを =[B.xlsm]Sheet1!E7=E7 で比較すると、falseが返ります。 これまで浮動小数点演算誤差で、見た目がおなじでも小数点以下かなり下の方で違いケースは経験していましたが、その場合でも小数点以下の表示を20位くらいまで表示させると違いが表れました。ところが今回は小数点以下30位まで表示させても0.822000000000000000000000000000で誤差が見えません。でもfalseになります。 こんなことってあるんでしょうか?

  • 相対誤差,絶対誤差

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

  • C言語で四則演算を使って結果が10になる数式

    C言語のプログラミングについて質問です。 四つの一桁の数字を入力して四則演算を使って結果が10になる数式を作りたいのですが、イメージが湧きません。 教えていただけますか? 例:1234enterkey 答え2*3+1*4 数値の変数はint型でお願いします。int型ですので小数点以下を使って10になる結果は出さなくて宜しいです。お願いします。

  • 1の位に誤差が出ます。

    A×B%=C ※小数点以下切り捨て からの、A-C=D という計算式があった場合、 B%は同一値として Dの値からCを算出するにはどうしたらいいのでしょうか? (AはCを基に算出したい) わかりにくくてすみません。混乱してしまいまして。。。

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

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

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

  • C言語における複素数の四則演算について

    複素数の四則演算(a+biとc+diの四則演算)について、for文を用いて表示するプログラムについて、???の部分に何を入れたらよいかわからず、うまく実行することができません。和・差・積・商の計算種別を入れるみたいなのですが、何を入れたらいいのかわかりません。 #include <stdio.h> void fukuso(double a,double b,double c,double d,double *e,double *f,int keisan); int main(void) { double a=4, b=8, c=4, d=3, e, f; int i; for(i=1;i<5;i++){ fukuso(a,b,c,d,&e,&f,???); if(i==1) printf("和演算\n"); else if(i==2) printf("差演算\n"); else if(i==3) printf("積演算\n"); else printf("商演算\n"); printf("e=%f f=%f i\n",e,f); } return (0); } void fukuso(double a1,double b1,double a2,double b2,double *a3,double *b3,int keisan) { if(keisan==1){ *e=a+c; *f=a+c; } else if(keisan==2){ *e=a-c; *f=b-d; } else if(keisan==3){ *e=a*c-b*d; *f=a*d+c*b; } else{ *e=(a*c+b*d)/(c*c+d*d); *f=(-a*d+c*b)/(c*c+d*d); } }

  • 見えない浮動小数点演算誤差?

    二つのBOOKにある表のデータの数値をVBAで比較していました。 単に各セルのValueとValueが等価かどうか=で比較しただけです。 すると見た目(表示)も数式バー上の値もまったく同じなのに相違があると判定されました。 不思議に思い、二つのBOOKにある表のデータの数値のうち違いがあると出た2つのセルを、そのまま別シートにコピー貼り付けして比較したのが添付の図です。 たとえば、BOOK-AからコピペしたB3セルの値は0.669です。 BOOK-BからコピペしたC3セルの値も0.669です。 両方とも数式バーでみましたが、間違いなく0.669です。 A3セルに =B3=C3 と入れるとTRUEが返ります。 ところが、D3セルに =B3-C3=0 と入れるとFALSEが返ります。 では、0でないなら差額はいくら?と、B11セルに=B3-C3と入れると、0が返ります。 これまで浮動小数点演算誤差で、見た目がおなじでも小数点以下かなり下の方で違いケースは経験していましたが、その場合でも小数点以下の表示を20位くらいまで表示させると違いが表れました。ところが今回は誤差が見えません。 差額確認のためVBAで Sub test01() Debug.Print Range("B3").Value = Range("C3").Value Debug.Print Range("B3").Value - Range("C3").Value Debug.Print Range("B5").Value = Range("C5").Value Debug.Print Range("B5").Value - Range("C5").Value End Sub としてみると、 False 1.11022302462516E-16 False 1.11022302462516E-16 が返りました。 エクセル2010と2016の2つで試しましたが同じ結果でした。 こんなことってあるんでしょうか? 困惑しています。

  • Excelの演算誤差について教えてください。

    1000以下の数値を切り捨てる場合の演算誤差を無くす方法はありますか? ありましたら、教えてください。

  • C言語で。。。。。

    C言語のプログラミングの勉強をしているのですが、 5.4のような小数点以下ありの数値の整数値を表示させる関数ってありますか??ネットを探してみてもよく分からなくて困っています(><)よろしくお願いします。