WGC1 第4章 浮動小数点表現 4.6 浮動小数点の例外
IEEE浮動少数点規格では、浮動少数点プロセッサ
がアプリケーションソフトウェアに通知すべき縮退条件
- 無効な演算
- ゼロ除算
- 非正規オペランド
- 数値オーバーフロー
- 数値アンダーフロー
- 不正確な結果
その他の例外(赤字のもの)は、先の2つに比べて深刻な問題を示しているため、無視すべきではありません。
無効な演算
- 負数に対して平方根
- 無限大 - 無限大
- 無限大/無限大
#include <stdlib.h> #include <stdio.h> #include <math.h> #ifdef linux #include <bits/huge_vall.h> #endif int main(int argc, char*argv[]){ float f = 0; printf("sqrt(-1) = %d\n", sqrt((double)-1.0)); printf("INFITY - INFINITY = %e\n", HUGE_VAL - HUGE_VAL); printf("INFITY / INFINITY = %e\n", HUGE_VAL / HUGE_VAL); return 0; }
Visual C++ 9.0
[D:\workspace\C_SandBox\10BOOKs\WGC1\4.6_Floating_Point_Exceptions\WIN]cl ..\invalid_operration.c Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. invalid_operration.c Microsoft (R) Incremental Linker Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. /out:invalid_operration.exe invalid_operration.obj
[D:\workspace\C_SandBox\10BOOKs\WGC1\4.6_Floating_Point_Exceptions\WIN]invalid_operration.exe sqrt(-1) = 0 INFITY - INFINITY = -1.#IND00e+000 INFITY / INFINITY = -1.#IND00e+000
gcc 4.1.2
[oc@centos5 4.6_Floating_Point_Exceptions]$ gcc -lm invalid_operration.c -o Lin/invalid_operration
[oc@centos5 4.6_Floating_Point_Exceptions]$ Lin/invalid_operration sqrt(-1) = 0 INFITY - INFINITY = nan INFITY / INFINITY = nan
あら??
ゼロ除算
#include <stdlib.h> #include <stdio.h> int main(int argc, char*argv[]){ printf("10/0=%d", 10/0); return 0; }
Visual C++ 9.0
コンパイルエラーになる
[D:\workspace\C_SandBox\10BOOKs\WGC1\4.6_Floating_Point_Exceptions\WIN]cl ..\zero_divide.c Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. zero_divide.c ..\zero_divide.c(5) : error C2124: 除算、剰余演算が 0 で行われています。
簡単なのは、コンパイルエラーになる。変数に入れてたりするとコンパイルはできてしまうので、
アプリエケーションエラーが発生する。
数値オーバーフロー
#include <stdlib.h> #include <stdio.h> int main(int argc, char*argv[]){ printf("max = %d\n", INT_MAX); printf("max + 1 = %d\n", INT_MAX + 1); return 0; }
Visual C++ 9.0
[D:\workspace\C_SandBox\10BOOKs\WGC1\4.6_Floating_Point_Exceptions\WIN]cl ..\overflow.c Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. overflow.c Microsoft (R) Incremental Linker Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. /out:overflow.exe overflow.obj
[D:\workspace\C_SandBox\10BOOKs\WGC1\4.6_Floating_Point_Exceptions\WIN]overflow.exe max = 2147483647 max + 1 = -2147483648
gcc 4.1.2
[oc@centos5 4.6_Floating_Point_Exceptions]$ gcc overflow.c -o Lin/overflow overflow.c: In function ‘main’: overflow.c:10: 警告: 式の整数がオーバーフローしました
警告がでる
[oc@centos5 4.6_Floating_Point_Exceptions]$ Lin/overflow max = 2147483647 max + 1 = -2147483648
数値アンダーフロー
結果が正規数で表現できないほどに小さく非0であるが不正確な結果となった場合
#include <stdlib.h> #include <stdio.h> #include <float.h> #ifdef linux #define DBL_RADIX FLT_RADIX #endif int main(int argc, char*argv[]){ int i = 0; float f = 1.0; double d = 1.0; printf("FLT_RADIX = %d, FLT_MIN_EXP = %d, FLT_MAX_EXP= %d, FLT_MANT_DIG = %d, FLT_MIN = %E, FLT_MAX = %E\n", FLT_RADIX, FLT_MIN_EXP, FLT_MAX_EXP, FLT_MANT_DIG, FLT_MIN, FLT_MAX); for ( i= 0 ; i <= -1*(FLT_MIN_EXP - FLT_MANT_DIG)+1 ; i++) { if( i > -1*FLT_MIN_EXP){ printf("float:i = %d, f = %E\n", i, f); } f/=2.0; } printf("\nDBL_RADIX = %d, DBL_MIN_EXP = %d, DBL_MAX_EXP= %d, DBL_MANT_DIG = %d, DBL_MIN = %E, DBL_MAX = %E\n", DBL_RADIX, DBL_MIN_EXP, DBL_MAX_EXP, DBL_MANT_DIG, DBL_MIN, DBL_MAX); for ( i= 0 ; i <= -1*(DBL_MIN_EXP - DBL_MANT_DIG)+1; i++) { if( i > -1*DBL_MIN_EXP){ printf("double:i = %d, d = %E\n", i, d); } d/=2.0; } return 0; }
DBL_RADIXは、VC++だとがあるが、gccではなかった。
[oc@centos5 4.6_Floating_Point_Exceptions]$ gcc underflow.c -o Lin/underflow underflow.c: In function ‘main’: underflow.c:21: error: ‘DBL_RADIX’ undeclared (first use in this function) underflow.c:21: error: (Each undeclared identifier is reported only once underflow.c:21: error: for each function it appears in.)
Visual C++ 9.0
[D:\workspace\C_SandBox\10BOOKs\WGC1\4.6_Floating_Point_Exceptions\WIN]cl ..\underflow.c /MD Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. underflow.c Microsoft (R) Incremental Linker Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. /out:underflow.exe underflow.obj
[D:\workspace\C_SandBox\10BOOKs\WGC1\4.6_Floating_Point_Exceptions\WIN]underflow.exe FLT_RADIX = 2, FLT_MIN_EXP = -125, FLT_MAX_EXP= 128, FLT_MANT_DIG = 24, FLT_MIN = 1.175494E-038, FLT_MAX = 3.402823E+038 float:i = 126, f = 1.175494E-038 float:i = 127, f = 5.877472E-039 float:i = 128, f = 2.938736E-039 float:i = 129, f = 1.469368E-039 float:i = 130, f = 7.346840E-040 float:i = 131, f = 3.673420E-040 float:i = 132, f = 1.836710E-040 float:i = 133, f = 9.183550E-041 float:i = 134, f = 4.591775E-041 float:i = 135, f = 2.295887E-041 float:i = 136, f = 1.147944E-041 float:i = 137, f = 5.739719E-042 float:i = 138, f = 2.869859E-042 float:i = 139, f = 1.434930E-042 float:i = 140, f = 7.174648E-043 float:i = 141, f = 3.587324E-043 float:i = 142, f = 1.793662E-043 float:i = 143, f = 8.968310E-044 float:i = 144, f = 4.484155E-044 float:i = 145, f = 2.242078E-044 float:i = 146, f = 1.121039E-044 float:i = 147, f = 5.605194E-045 float:i = 148, f = 2.802597E-045 float:i = 149, f = 1.401298E-045 float:i = 150, f = 0.000000E+000 DBL_RADIX = 2, DBL_MIN_EXP = -1021, DBL_MAX_EXP= 1024, DBL_MANT_DIG = 53, DBL_MIN = 2.225074E-308, DBL_MAX = 1.797693E+308 double:i = 1022, d = 2.225074E-308 double:i = 1023, d = 1.112537E-308 double:i = 1024, d = 5.562685E-309 double:i = 1025, d = 2.781342E-309 double:i = 1026, d = 1.390671E-309 double:i = 1027, d = 6.953356E-310 double:i = 1028, d = 3.476678E-310 double:i = 1029, d = 1.738339E-310 double:i = 1030, d = 8.691695E-311 double:i = 1031, d = 4.345847E-311 double:i = 1032, d = 2.172924E-311 double:i = 1033, d = 1.086462E-311 double:i = 1034, d = 5.432309E-312 double:i = 1035, d = 2.716155E-312 double:i = 1036, d = 1.358077E-312 double:i = 1037, d = 6.790387E-313 double:i = 1038, d = 3.395193E-313 double:i = 1039, d = 1.697597E-313 double:i = 1040, d = 8.487983E-314 double:i = 1041, d = 4.243992E-314 double:i = 1042, d = 2.121996E-314 double:i = 1043, d = 1.060998E-314 double:i = 1044, d = 5.304989E-315 double:i = 1045, d = 2.652495E-315 double:i = 1046, d = 1.326247E-315 double:i = 1047, d = 6.631237E-316 double:i = 1048, d = 3.315618E-316 double:i = 1049, d = 1.657809E-316 double:i = 1050, d = 8.289046E-317 double:i = 1051, d = 4.144523E-317 double:i = 1052, d = 2.072262E-317 double:i = 1053, d = 1.036131E-317 double:i = 1054, d = 5.180654E-318 double:i = 1055, d = 2.590327E-318 double:i = 1056, d = 1.295163E-318 double:i = 1057, d = 6.475817E-319 double:i = 1058, d = 3.237909E-319 double:i = 1059, d = 1.618954E-319 double:i = 1060, d = 8.094772E-320 double:i = 1061, d = 4.047386E-320 double:i = 1062, d = 2.023693E-320 double:i = 1063, d = 1.011846E-320 double:i = 1064, d = 5.059232E-321 double:i = 1065, d = 2.529616E-321 double:i = 1066, d = 1.264808E-321 double:i = 1067, d = 6.324040E-322 double:i = 1068, d = 3.162020E-322 double:i = 1069, d = 1.581010E-322 double:i = 1070, d = 7.905050E-323 double:i = 1071, d = 3.952525E-323 double:i = 1072, d = 1.976263E-323 double:i = 1073, d = 9.881313E-324 double:i = 1074, d = 4.940656E-324 double:i = 1075, d = 0.000000E+000
gcc 4.1.2
[oc@centos5 4.6_Floating_Point_Exceptions]$ gcc underflow.c -o Lin/underflow [oc@centos5 4.6_Floating_Point_Exceptions]$
[oc@centos5 4.6_Floating_Point_Exceptions]$ Lin/underflow FLT_RADIX = 2, FLT_MIN_EXP = -125, FLT_MAX_EXP= 128, FLT_MANT_DIG = 24, FLT_MIN = 1.175494E-38, FLT_MAX = 3.402823E+38 float:i = 126, f = 1.175494E-38 float:i = 127, f = 5.877472E-39 float:i = 128, f = 2.938736E-39 float:i = 129, f = 1.469368E-39 float:i = 130, f = 7.346840E-40 float:i = 131, f = 3.673420E-40 float:i = 132, f = 1.836710E-40 float:i = 133, f = 9.183550E-41 float:i = 134, f = 4.591775E-41 float:i = 135, f = 2.295887E-41 float:i = 136, f = 1.147944E-41 float:i = 137, f = 5.739719E-42 float:i = 138, f = 2.869859E-42 float:i = 139, f = 1.434930E-42 float:i = 140, f = 7.174648E-43 float:i = 141, f = 3.587324E-43 float:i = 142, f = 1.793662E-43 float:i = 143, f = 8.968310E-44 float:i = 144, f = 4.484155E-44 float:i = 145, f = 2.242078E-44 float:i = 146, f = 1.121039E-44 float:i = 147, f = 5.605194E-45 float:i = 148, f = 2.802597E-45 float:i = 149, f = 1.401298E-45 float:i = 150, f = 0.000000E+00 DBL_RADIX = 2, DBL_MIN_EXP = -1021, DBL_MAX_EXP= 1024, DBL_MANT_DIG = 53, DBL_MIN = 2.225074E-308, DBL_MAX = 1.797693E+308 double:i = 1022, d = 2.225074E-308 double:i = 1023, d = 1.112537E-308 double:i = 1024, d = 5.562685E-309 double:i = 1025, d = 2.781342E-309 double:i = 1026, d = 1.390671E-309 double:i = 1027, d = 6.953356E-310 double:i = 1028, d = 3.476678E-310 double:i = 1029, d = 1.738339E-310 double:i = 1030, d = 8.691695E-311 double:i = 1031, d = 4.345847E-311 double:i = 1032, d = 2.172924E-311 double:i = 1033, d = 1.086462E-311 double:i = 1034, d = 5.432309E-312 double:i = 1035, d = 2.716155E-312 double:i = 1036, d = 1.358077E-312 double:i = 1037, d = 6.790387E-313 double:i = 1038, d = 3.395193E-313 double:i = 1039, d = 1.697597E-313 double:i = 1040, d = 8.487983E-314 double:i = 1041, d = 4.243992E-314 double:i = 1042, d = 2.121996E-314 double:i = 1043, d = 1.060998E-314 double:i = 1044, d = 5.304989E-315 double:i = 1045, d = 2.652495E-315 double:i = 1046, d = 1.326247E-315 double:i = 1047, d = 6.631237E-316 double:i = 1048, d = 3.315618E-316 double:i = 1049, d = 1.657809E-316 double:i = 1050, d = 8.289046E-317 double:i = 1051, d = 4.144523E-317 double:i = 1052, d = 2.072262E-317 double:i = 1053, d = 1.036131E-317 double:i = 1054, d = 5.180654E-318 double:i = 1055, d = 2.590327E-318 double:i = 1056, d = 1.295163E-318 double:i = 1057, d = 6.475817E-319 double:i = 1058, d = 3.237909E-319 double:i = 1059, d = 1.618954E-319 double:i = 1060, d = 8.094772E-320 double:i = 1061, d = 4.047386E-320 double:i = 1062, d = 2.023693E-320 double:i = 1063, d = 1.011846E-320 double:i = 1064, d = 5.059232E-321 double:i = 1065, d = 2.529616E-321 double:i = 1066, d = 1.264808E-321 double:i = 1067, d = 6.324040E-322 double:i = 1068, d = 3.162020E-322 double:i = 1069, d = 1.581010E-322 double:i = 1070, d = 7.905050E-323 double:i = 1071, d = 3.952525E-323 double:i = 1072, d = 1.976263E-323 double:i = 1073, d = 9.881313E-324 double:i = 1074, d = 4.940656E-324 double:i = 1075, d = 0.000000E+00
添削歓迎
ここ間違ってるよ
こうした方がよくないか?
この環境だとこうなるよ
などなど
方法は、コメント、トラックバック、はてブ、Twitter @orange_clover宛 で、お願いしまます。