■この記事の概要
この記事では、C言語で発生する計算結果の不一致について解説しています。具体例として、0xFFFFffff + 1
の桁あふれや、浮動小数点計算の順序により異なる結果が生じるケースを取り上げています。また、接尾子L
を活用することで桁あふれを回避する方法を詳述し、安全な数値操作を推奨しています。
■16進数と10進数で足し算の結果が変わる
注:LP64-gcc環境とします。
#include <stdio.h>
int main(void){
printf("%lx\n",0xFFFFffff+1);
printf("%lx\n",4294967295+1);
}
●筆者も間違えた実行結果は?こちら
■C言語での桁あふれ対策に接尾子Lを使う
//C言語での桁あふれ対策に接尾子Lを使う
#include <stdint.h>
#include <limits.h>
#include <stdio.h>
int main(void){
uint32_t x = UINT_MAX ;
uint64_t y = x + 2 ;
uint64_t z = x + 2L ;
printf("y = %lx\n",y);
printf("z = %lx\n",z);
}
このプログラムは以下のように表示されます
$ ./a.out
1
100000001
y = x + 2 ;と記述すると右辺をint型で計算するため桁あふれします。
y = x + 2L ;と記述すると右辺をlong型で計算するため桁あふれしません。
■浮動小数点は順番によって足し算の結果が変わる
#include <float.h>
#include <stdio.h>
int main(void)
{
long double ゴジラ = FLT_MAX; // 巨大
long double 人間 = 1.0L; // 比較的小さな数
long double コング = -FLT_MAX; // 巨大
long double 人間踏まれる = ゴジラ + 人間 + コング ;
long double 人間生きてる = ゴジラ + コング + 人間 ;
printf("人間踏まれる = %.20Lf\n", 人間踏まれる);
printf("人間生きてる = %.20Lf\n", 人間生きてる);
}
このプログラムは以下のように表示されます
./a.out
人間踏まれる = 0.00000000000000000000
人間生きてる = 1.00000000000000000000
この例を簡単に例えると、
人間踏まれるの計算では
ゴジラ対人間は、人間が踏まれて誤差に丸め込まれます。
人間生きてるの計算では
ゴジラ対コングは0になり、後から人間を足すので1.0が残ります。