2つの符号付き整数があり、それらを減算したいと思います。オーバーフローしたかどうかを知る必要があります。
int one;
int two;
int result = two-one;
if (OVERFLOW) {
printf("overflow");
} else {
printf("no overflow");
}
そんな感じ。これを行う良い方法はありますか?
2つの符号付き整数があり、それらを減算したいと思います。オーバーフローしたかどうかを知る必要があります。
int one;
int two;
int result = two-one;
if (OVERFLOW) {
printf("overflow");
} else {
printf("no overflow");
}
そんな感じ。これを行う良い方法はありますか?
それが起こる前に、あなたはオーバーロー(またはアンダーフロー)を捕らえる必要があります。それが起こると、あなたは未定義動作の土地にいて、すべての賭けはオフになります。
#include <limits.h>
#include <stdio.h>
int sum_invokes_UB(int a, int b) {
int ub = 0;
if ((b < 0) && (a < INT_MIN - b)) ub = 1;
if ((b > 0) && (a > INT_MAX - b)) ub = 1;
return ub;
}
int main(void) {
printf("(INT_MAX-10) + 8: %d\n", sum_invokes_UB(INT_MAX - 10, 8));
printf("(INT_MAX-10) + 100: %d\n", sum_invokes_UB(INT_MAX - 10, 100));
printf("(INT_MAX-10) + INT_MIN: %d\n", sum_invokes_UB(INT_MAX - 10, INT_MIN));
printf("100 + INT_MIN: %d\n", sum_invokes_UB(100, INT_MIN));
printf("-100 + INT_MIN: %d\n", sum_invokes_UB(-100, INT_MIN));
printf("INT_MIN - 100: %d\n", sum_invokes_UB(INT_MIN, -100));
return 0;
}
まず、符号付き計算のオーバーフローにより、Cで未定義の動作が発生します。
次に、UBを1秒間忘れて、2の補数マシンの典型的なオーバーフロー動作に固執します。オーバーフローは、結果が最初のオペランドから「間違った方向」に「移動」するという事実によって明らかになります。つまり、結果が大きくなる場合です。正の第2オペランドを持つ第1オペランドよりも大きい(または負の第2オペランドを持つ第1オペランドよりも小さい)。
あなたの場合
int one, two;
int result = two - one;
if ((result < two) != (one > 0))
printf("overflow");
あなたはより高い精度でそれを行い、比較することができます。32ビット整数があるとします。それらを64ビット整数にプロモートし、減算してから、その結果を32ビットにキャストしてから64ビットまでキャストした結果と比較できます。
int
言語はサイズの保証を与えていないので、私はこのようにはしません...多分int32_t
そして(C99int64_t
から)から。<inttypes.h>
Windowsを使用している場合は、etcを使用できますULongSub()
。これにより、オーバーフロー時にエラーコードが返されます。
評価に関して考慮すべき2つのケースがありますa-b
:
a-b
アンダーフローする可能性がb>0 && a<0
ありますa-b < min == a<min+b
a-b
オーバーフローする可能性がb<0 && a>0
ありますa-b > max == -b>max-a
a
これにより、ケースを単純化して
#include <limits.h>
int sub_invokes_UB(int a, int b) {
if ((b > 0) && (a < INT_MIN + b)) ub = 1; // error
if ((b < 0) && (a > INT_MAX + b)) ub = 1; // error
return 0; // ok
}