WGC1 第4章 浮動小数点表現 4.6 浮動小数点の例外

IEEE浮動少数点規格では、浮動少数点プロセッサ
アプリケーションソフトウェアに通知すべき縮退条件

  • 無効な演算
  • ゼロ除算
  • 非正規オペランド
  • 数値オーバーフロー
  • 数値アンダーフロー
  • 不正確な結果

その他の例外(赤字のもの)は、先の2つに比べて深刻な問題を示しているため、無視すべきではありません。


Visual C++gccで実験

無効な演算

  • 負数に対して平方根
  • 無限大 - 無限大
  • 無限大/無限大
#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 で行われています。

簡単なのは、コンパイルエラーになる。変数に入れてたりするとコンパイルはできてしまうので、
アプリエケーションエラーが発生する。

gcc 4.1.2

コンパイルは警告で、実行時にエラー

[oc@centos5 4.6_Floating_Point_Exceptions]$ gcc zero_divide.c -o Lin/zero_divide
zero_divide.c: In function ‘main’:
zero_divide.c:5: 警告: division by zero
[oc@centos5 4.6_Floating_Point_Exceptions]$ Lin/zero_divide
浮動小数点演算例外です (core dumped)

数値オーバーフロー

#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宛 で、お願いしまます。



環境










Randall Hyde、鵜飼 文敏、まつもと ゆきひろ、後藤 正徳、トップスタジオ