• ベストアンサー

0除算して、落ちるプログラムと落ちないプログラム

コンパイラ : cc 環境 : Linux 0除算して、落ちるプログラムと落ちないプログラムが あるのですが、何が違いを生んでいるのでしょうか?

  • otaks
  • お礼率53% (270/507)

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

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8526/19383)
回答No.5

>0除算して、落ちるプログラムと落ちないプログラムが >あるのですが、何が違いを生んでいるのでしょうか? 「いつ演算しているか?」と「どうやって演算しているか?」により、複雑に違いを生みます。 ・いつ演算しているか? 「定数同士の演算式」は、コンパイラの最適化によって「計算済みの定数」に置き換わる場合があります。 そしてそれは「処理系依存」なので「それをするコンパイラもあれば、それをしないコンパイラもある」のです。 で、最適化時に「0除算」と判った時に、どういうコードに最適化されるかも「処理系依存」です。 コンパイラによって「0/0」を「除数が何かチェックせず、0は何で割っても0になるから、0/?はすべて0」に最適化してしまう手抜きなコンパイラもあれば「実行時に0除算を行わせ、0で割ったとの実行時例外を、あえて出すようにしている」と言うコンパイラもあります。 つまり「コンパイラによって、コンパイル時に0にされてしまう場合」と「コンパイル時には計算されず、実行時に計算される場合」があるのです。 そしてそれらは「コンパイルオプション」によって変更出来るので、同じプラットフォーム、同じコンパイル環境でも、指定したオプションやデフォルトオプションが何になっているかで、差が出ます。 ・どうやって演算しているか? int同士の割り算、float同士の割り算、double同士の割り算は、すべて「計算の方法」が異なります。 int同士の割り算は、通常、CPUの「除算命令」で実行します。 前述の最適化による「単なる0にする」と言うのが行われていなければ、例外が発生するでしょう。 そして、デフォルトの例外処理ルーチンを書き変えていないなら、ライブラリのデフォルトの例外処理ルーチンが「Floating point exception」などの表示を行ってプログラムを終了します。 float同士の割り算、double同士の割り算は、通常、浮動小数点演算ライブラリが呼ばれます。 ライブラリでは「浮動小数点演算コプロセッサがあるなら、コプロセッサで計算させ、コプロセッサがないならソフトウェアで演算する」と言う処理をします。 コプロセッサに計算させるCPU命令を実行した場合、0除算の演算結果は「0以外/0は無限大(inf)」になり「0/0は非数(nan)」になります。例外は発生しません。 コプロセッサがなく、ソフトウェアで演算した場合も、0除算の演算結果はコプロセッサがある時と同じです(ソフトウェアで「エミュレート」しているのだから、同じにならなくては困る) >・intの場合、分子の値によっても落ちるかどうかが変わる。 数学的には「非0÷0=符号付の無限大」「0÷0=未定義(非数、数ではない)」です。 つまり、被除数(分子)が「非0」か「0」かで、結果が変わります。 そして、C言語の仕様では「intでの0除算の結果は、処理系に依存する」事になっています。つまり「何が起こるか判らない」のです。 しかし、floatやdoubleは「無限大」や「非数」をサポートしているので、例外は発生したりしません。 ちゃんと、数学の通りに「非0÷0=符号付の無限大」「0÷0=非数」と言う計算結果になります。 >floatやdoubleはどうやってこの情報(inf, nan)を持っているのかが次の疑問になりました(- -; IEEE754(IEEE二進化浮動小数点数演算標準)の仕様に従った、浮動小数点の数値は「正負の符号」「指数部」「仮数部」の3つで出来ています。 そして、それぞれ3つの部分の値がどうなっているかで、以下のようになっています。 ・符号が0、指数部が0、仮数部が0=正の0 ・符号が1、指数部が0、仮数部が0=負の0 ・符号が0、指数部が0、仮数部が非0=正の非正規化数 ・符号が1、指数部が0、仮数部が非0=負の非正規化数 ・符号が0、指数部が0以外かつ最大値以外、仮数部が任意=正の正規化数 ・符号が1、指数部が0以外かつ最大値以外、仮数部が任意=負の正規化数 ・符号が0、指数部が最大値、仮数部が0=正の無限大(inf) ・符号が1、指数部が最大値、仮数部が0=負の無限大(inf) ・符号が0、指数部が最大値、仮数部が非0=非数(nan) ・符号が1、指数部が最大値、仮数部が非0=非数(nan) このように「指数部と仮数部の値」によって「無限大」「非数」を表現しています。

otaks
質問者

お礼

あまりに高度すぎてちょっと理解できませんが、状況により結果は変わってくる ということと捉えました。(かなり大雑把と思いますが。。) ご回答ありがとうございました。

その他の回答 (4)

  • eroermine
  • ベストアンサー率18% (83/444)
回答No.4

intel 86系の場合整数でゼロ除算しても SIGFPEが出ますね。 だからこれをつければ落ちない。 signal(SIGFPE, ゼロ除算処理関数のアドレス);

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

例えば、 #include <stdio.h> int main() {  double x = 1.0/0;  printf("%f\n", x);  return 0; } といったコードであればxに無限大が格納されますので、プログラムは落ちません。

otaks
質問者

お礼

下記パターンの実験をしました。(gccでコンパイルしましたが、 ccと全ての結果が同じなのかは不明ですが。。) はじめに自分が落ちると言っていたプログラムはソース2のものでした。 また落ちないと言っていたのはソース6のものでした。 そのため、片方では落ちるし、片方では落ちないとなるようでした。。 この結果からは、 ・型によって0除算しても落ちるかどうかが変わる。 →float, doubleはどんな時でも落ちない。 ・intの場合、分子の値によっても落ちるかどうかが変わる。 ということが分かりました。(?がついているのはcodepadで実験したので あまり自信がないという意味です。) floatやdoubleはどうやってこの情報(inf, nan)を持っているのかが次の疑問に なりました(- -; ■実験 ●ソース1:double, 分子は0でない → inf           →落ちない? ●ソース2:int  , 分子は0でない → Floating point exception →落ちる? ●ソース3:float , 分子は0でない → inf           →落ちない? ●ソース4:double, 分子は0    → nan           →落ちない ●ソース5:int  , 分子は0    → 0            →落ちない ●ソース6:float , 分子は0    → nan           →落ちない ●ソース1: #include <stdio.h> int main() { double x = 1.0/0; printf("%f\n", x); return 0; } 【実行結果】 inf ●ソース2: #include <stdio.h> int main() { int x = 1/0; printf("%d\n", x); return 0; } 【実行結果】 Floating point exception ●ソース3: #include <stdio.h> int main() { float x = 1.0/0; printf("%f\n", x); return 0; } 【実行結果】 inf ●ソース4: #include <stdio.h> int main() { double x = 0.0/0; printf("%f\n", x); return 0; } 【実行結果】 nan ●ソース5: #include <stdio.h> int main() { int x = 0/0; printf("%d\n", x); return 0; } 【実行結果】 0 ●ソース6: #include <stdio.h> int main() { float x = 0.0/0; printf("%f\n", x); return 0; } 【実行結果】 nan

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.2

>0除算して、落ちるプログラムと落ちないプログラムがある それらのソースコードを載せてみる、というお気持ちはありますか?

  • taka37777
  • ベストアンサー率30% (166/544)
回答No.1

0除算して落ちる、落ちないプログラムというのは何を示しているのでしょうか? ・同じソースをコンパイルしても、動作が異なる ・ソースは異なる   coreを吐く、吐かない   動作が止まる、止まらない  0除算にならないように通常は演算の前でチェックを入れるようにします。coreファイルを吐く、吐かないというのであればsignalを受け取って終了処理をしているからcoreファイルを吐かないという事になると思います。

otaks
質問者

補足

補足いたします。 ソースは異なります。 一方は動作がとまりますが、 一方は継続します。 coreを吐く吐かないでは ありません。

関連するQ&A

  • 0除算を判定したい

    0除算とは例えば10を0で割ったら結果が無限大になるように、ある数を0で割った時に起こる現象です。 しばしばこの0除算に悩まされるので、ある式を代入したらそれが0除算であるかどうかを判定できたらと思いました。 そこで下のような関数を作れたらと思っているのですが、 ある式を見てその結果が0除算であるかを判定する方法はありますでしょうか? int isDivide0( float val ) {   if ( val == 0除算 )     return 1;   else     return 0; } int main() {   isDivide0( 10 / 0 ); } 尚、開発環境はVisual Studio2005です。

  • 旧c++のプログラムを動かす方法を教えてください

    c++の実行時にエラーが出てしまいます。 エラーの原因をインターネットで検索しまして、原因は「iostream」ではなく旧バージョンの「iostream.h」をインクルードしているためであることが判明しました。 私はプログラムの記述を変更することなく、旧c++のプログラムを実行したいのですが、やり方が分かりません。 旧c++のコンパイラを探してインストールしようと考えましたが、どれが旧c++のコンパイラなのか分かりませんでした。 解決方法をご存知の方がいらっしゃいましたら、回答よろしくお願いします。 pc環境はVine linux4.2です。

  • JavaでCプログラムをコンパイルするには

    linux環境で、javaによって別に作ってあるCのプログラムをコンパイルしたいのですが、execを使用して、 Runtime.getRuntime().exec("cc sample.c"); とするとコンパイルできません。 恐らくコマンドプロンプトなどを起動して指定してやればできると思うのですが、現在linux環境にないのでわかりません。 gnome-terminalかなにかだったような気がするのですが・・・。 どなたか教えていただければ幸いです。

  • プログラムの開発環境について

    みなさんは開発環境を整えてプログラムに取り掛かってくれと言われたらどのような開発環境を整えますか? 私は開発環境のことに詳しくないので、LinuxかFeeBSD上でemacs使ってプログラムし、バグがあったらgdb使うといった感じです。コンパイラはOSに初めから付属のgccを使っています。UNIX系のOSだとCもC++もデフォルトでプログラムできるので。 最近はEclipsという統合開発環境が雑誌などに取り上げられていて、javaを初めとしてプラグインを入れればCやC++、PHPなどもプログラムできるようなんですが、私もそろそろ便利なものを使っていくべきかなーと考えています。現状ではCしか取り扱っていませんが、javaやC++、PHPなどの多言語を一つの開発環境で取り扱えるとありがたいです。もちろん一切お金をかけずに開発環境を整えられればいいのですが、Windows環境でVisual Stdioなどを導入するなどの意見でも構いません。これから主流になるであろうまたは人気が高いであろう開発環境を紹介していただければ幸いです。

  • .NET エクセルで除算するには?

    いつもお世話になっています。 下記環境でエクセルを出力するシステムをつくっています。 開発環境 : WindowsXP       office2003 言語   : VB.NET 出力時にエクセル上で除算してパーセンテージを表示、 分子または分母がない場合は「0」と表示、 しようとしているのですが、どうしてもエラーをはいてしまいます。 コードは、下記の通りです。 エクセル上ではうまくいくのですが、コードはNGでした。 IF(OR(" & A1 = 0 & "," & A2 = 0 & ",0," & A2 / A1 * 100 & ")" ご存知の方がおりましたら、ご教示御願いいたします。

  • プログラムで得られたdataをfileに書込みたい

    windowsXPで、コンパイラはボーランドのを使用しています。 プログラム中で、 for(i=1;i<10;i++) { printf("%f",x[i]); } と書いておいたら、 コマンドプロンプトにその結果が表示されます。 コマンドプロンプトに結果を書くのではなく、 指定したファイルに結果を書かせるコマンドがUNIXにはあると思うのですが、(学校ではLINUXを使っています) そのコマンドを私の環境で使うようにできるでしょうか? それがどのようなコマンド名だったか覚えていないのですが、 ご存知のかた、よろしくお願いします。

  • WindowsXPでLinux

    WindoswXPでLinuxのTerminalを使用できるようにするにはどうすればよいでしょうか? Terminalに標準仕様のCのコンパイラも使えるようにしたいです。 要はXPでCのプログラムを組みたいのですが、最終的にはLinux環境で使用するので、なるべくLinuxに近づけたいのです。 どなたかいい方法を教えてください。

  • GNUコンパイラとIntelコンパイラの違いについて

    今回fortranとC言語で書かれたWindows用プログラムをLinux用に移植することになりました。GNUのコンパイラを使用し無事コンパイルできたので実行したのですが"Segmentation fault"となりうまく実行できませんでした。そこで試しにIntelのコンパイラを使用しコンパイルしてみたところGNUのときとは違い"Segmentation fault"とは出ず、プログラム内のエラーチェックに引っかかり止ってしまいました。同じソースコードにもかかわらず止まる箇所が異なります。 今まで考えたことがなかったのですがGNUとIntelのコンパイラの違いはなんなのでしょうか?また、この二つ以外にいいコンパイラはあるのでしょうか?

  • MacでC++プログラム

    MacでC++プログラムをやろうと思うのですが、いままでVC++を使っていたので、 なにかそれに似た環境でできないものでしょうか? 実際にやってらっしゃる方がいらっしゃれば教えてください。 あと、CodeWarrier(←スペル?)ってありますよね?あれはいったいどんなものなんでしょうか?C(C++)のコンパイラみたいに考えていいのですか?

  • LinuxOSみたいな巨大なものは統合環境で作られている?

    Linuxは巨大なプログラムだと思うのですが、これを作ったりメンテナンスしているプログラマーの方々は、どういう環境でプログラムしているのでしょうか?(Mozillaについても同じ疑問があります。) Windowsのアプリケーションだと、ほとんどのベンダーはマイクロソフトの統合環境を使って開発していますよね? Linuxは膨大なプログラムコードが必要なので、統合環境みたいな便利なツールがないと厳しいと思うのですが、どうなのでしょうか?統合環境と言っても、そもそも統合環境を作るにはOSが必要だし、不思議です。 それともemacs+コンパイラ+デバッガみたいな基本的組み合わせ?