
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で質問しましょう!
似たような質問が見つかりました
- その他(プログラミング・Web制作) プログラムの勉強のおすすめは 7 2022/12/09 20:09
- その他(プログラミング・Web制作) VBA 1 2023/01/19 16:19
- その他(プログラミング・Web制作) FORTRAN77の配列(除算) 2 2023/02/01 14:34
- その他(趣味・アウトドア・車) Arudino nanoが正常に動作しない原因 1 2022/10/30 18:29
- au(KDDI) 昨日 ヤマダ電機でスマホトクするプログラムを使ってauの端末だけ購入しようとしたら分割の審査に落ちま 2 2023/05/06 02:54
- C言語・C++・C# 1. 仮想CPU「exmini」を使用して,「$dataからn減算する」プログラムを作成してください 2 2022/07/04 17:49
- C言語・C++・C# 【CASLプログラム】 定数(80と55)を確保し、その和をGR1に、その差をGR2に求めるCASL 1 2022/12/16 01:17
- ノートパソコン ソフトアンインストール残存ファイル 3 2022/09/13 18:15
- Windows 10 win 10 でのstartup program を削除したい 3 2022/04/29 09:21
- Visual Basic(VBA) VBAが止まります。 2 2022/09/02 14:02
このQ&Aを見た人はこんなQ&Aも見ています
-
0除算を判定したい
C言語・C++・C#
-
C言語 exitの使い方
C言語・C++・C#
-
C言語を実行すると-infが出てきて困っています。
C言語・C++・C#
-
-
4
関数から配列を返すには?
C言語・C++・C#
-
5
DWORDの実際の型は何でしょうか
C言語・C++・C#
-
6
char*を初期化したいのですが
C言語・C++・C#
-
7
unsigned long long 型のフォーマット指定子
C言語・C++・C#
-
8
1 つのヘッダファイルに複数のクラスって?
C言語・C++・C#
-
9
IG、ACC、+B、ILL
国産バイク
-
10
C++言語で、構造体のコピーは可能(しても良い)のでしょうか?
C言語・C++・C#
-
11
0除算の例外処理ができない!!助けて!!
Visual Basic(VBA)
-
12
C言語 配列の長さの上限
C言語・C++・C#
-
13
配列を使わずに、変数名を動的にループで回したい
C言語・C++・C#
-
14
<unistd.h>をVisualStudioでつかえるようにする
C言語・C++・C#
-
15
実験における誤差範囲の許容範囲の決め方ってどうやればいいんですか? また、一般的には具体的にどこ程度
大学・短大
-
16
C言語での引数の省略方法
C言語・C++・C#
-
17
C++における継続行
その他(プログラミング・Web制作)
-
18
Enterキーを押されたら次の処理に移るという事をしたい。
C言語・C++・C#
-
19
fopenで別ディレクトリにファイルをオープンしたい
C言語・C++・C#
-
20
#define NULL ((void *)0) の弊害
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C++でアボート(Abort)で処理が...
-
C++ で、「)」が必要 というエ...
-
コンパイルできない
-
コンパイラフラグ(compiler fla...
-
Eclipseの環境設定について
-
0除算して、落ちるプログラムと...
-
graph.hがincludeできない
-
C言語のワーニングメッセージの...
-
コンパイラについて
-
変数(関数)名の頭に_
-
IPアドレス表示プログラム
-
プリコンパイラとは?
-
ABAQUS ユーザーサブルーチン...
-
初心者はIDE使わないほうが良く...
-
移植性の高いmakefileの作成
-
関数の戻り値による変数の初期化
-
「.c」拡張子でC++文法を使...
-
不要なインクルードファイルの検出
-
cygwinをインストールしたとこ...
-
バイナリファイルとソースコー...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
0除算して、落ちるプログラムと...
-
C++でアボート(Abort)で処理が...
-
C++ で、「)」が必要 というエ...
-
io.hをincludeするとそのような...
-
コンパイラの制限 : ヒープの領...
-
不要なインクルードファイルの検出
-
どのプログラミング言語ででき...
-
Eclipseの環境設定について
-
コンパイルできない
-
初心者はIDE使わないほうが良く...
-
FORTRAN→Cに翻訳
-
fortranでのNaNについて
-
関数の戻り値による変数の初期化
-
ABAQUS ユーザーサブルーチン...
-
sprintfを用いたフォーマット文...
-
__extension__
-
変数(関数)名の頭に_
-
makeのエラーについて
-
volatile修飾について
-
C言語のワーニングメッセージの...
おすすめ情報