
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)
このように「指数部と仮数部の値」によって「無限大」「非数」を表現しています。
あまりに高度すぎてちょっと理解できませんが、状況により結果は変わってくる
ということと捉えました。(かなり大雑把と思いますが。。)
ご回答ありがとうございました。
No.4
- 回答日時:
intel 86系の場合整数でゼロ除算しても SIGFPEが出ますね。
だからこれをつければ落ちない。
signal(SIGFPE, ゼロ除算処理関数のアドレス);
No.3
- 回答日時:
例えば、
#include <stdio.h>
int main()
{
double x = 1.0/0;
printf("%f\n", x);
return 0;
}
といったコードであればxに無限大が格納されますので、プログラムは落ちません。
下記パターンの実験をしました。(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

No.1
- 回答日時:
0除算して落ちる、落ちないプログラムというのは何を示しているのでしょうか?
・同じソースをコンパイルしても、動作が異なる
・ソースは異なる
coreを吐く、吐かない
動作が止まる、止まらない
0除算にならないように通常は演算の前でチェックを入れるようにします。coreファイルを吐く、吐かないというのであればsignalを受け取って終了処理をしているからcoreファイルを吐かないという事になると思います。
この回答への補足
補足いたします。
ソースは異なります。
一方は動作がとまりますが、
一方は継続します。
coreを吐く吐かないでは
ありません。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
0除算を判定したい
C言語・C++・C#
-
C言語を実行すると-infが出てきて困っています。
C言語・C++・C#
-
0除算の例外処理ができない!!助けて!!
Visual Basic(VBA)
-
-
4
関数から配列を返すには?
C言語・C++・C#
-
5
C言語 exitの使い方
C言語・C++・C#
-
6
1 つのヘッダファイルに複数のクラスって?
C言語・C++・C#
-
7
配列を使わずに、変数名を動的にループで回したい
C言語・C++・C#
-
8
char*を初期化したいのですが
C言語・C++・C#
-
9
DWORDの実際の型は何でしょうか
C言語・C++・C#
-
10
C言語 配列の長さの上限
C言語・C++・C#
-
11
fopenで別ディレクトリにファイルをオープンしたい
C言語・C++・C#
-
12
正負を反転させて出力するプログラム
C言語・C++・C#
-
13
構造体のメンバをfor文で回したい
C言語・C++・C#
-
14
unsigned long long 型のフォーマット指定子
C言語・C++・C#
-
15
IG、ACC、+B、ILL
国産バイク
-
16
<unistd.h>をVisualStudioでつかえるようにする
C言語・C++・C#
-
17
【組込み】割り込み中のstatic変数について。
C言語・C++・C#
-
18
エディットボックスの入力制限について
C言語・C++・C#
-
19
C言語の配列のコピーについて
C言語・C++・C#
-
20
C++言語で、構造体のコピーは可能(しても良い)のでしょうか?
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
0除算して、落ちるプログラムと...
-
C++でアボート(Abort)で処理が...
-
C++ で、「)」が必要 というエ...
-
コンパイルできない
-
C言語のワーニングメッセージの...
-
io.hをincludeするとそのような...
-
C言語での変数宣言の場所
-
isnanの取り扱いについて
-
「.c」拡張子でC++文法を使...
-
ABAQUS ユーザーサブルーチン...
-
移植性の高いmakefileの作成
-
どのプログラミング言語ででき...
-
Eclipseの環境設定について
-
何も書いて無いのに警告が出る...
-
fortranでのNaNについて
-
PICマイコンによる乱数の表示に...
-
VBAで仕様書は書きますか?
-
あるプログラムのコマンドライ...
-
正しい五十音順について
-
65536は2の何乗なのでしょうか?
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C++ で、「)」が必要 というエ...
-
0除算して、落ちるプログラムと...
-
コンパイルできない
-
C++でアボート(Abort)で処理が...
-
io.hをincludeするとそのような...
-
volatile修飾について
-
Delphiの逆コンパイル
-
__extension__
-
Eclipseの環境設定について
-
linuxのセキュリティ対策と致し...
-
プリコンパイラとは?
-
fortranでのNaNについて
-
MFC
-
C言語のワーニングメッセージの...
-
関数の戻り値による変数の初期化
-
コンパイラについて
-
FORTRANとC++の連動について
-
Fortran90を使いたい
-
「.c」拡張子でC++文法を使...
-
PICマイコンによる乱数の表示に...
おすすめ情報