オーバーフローせずにINT_MIN
の絶対値を抽出するにはどうすればよいですか?問題については、次のコードを参照してください。
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("INT_MAX: %d\n", INT_MAX);
printf("INT_MIN: %d\n", INT_MIN);
printf("abs(INT_MIN): %d\n", abs(INT_MIN));
return 0;
}
以下を吐き出します
INT_MAX: 2147483647
INT_MIN: -2147483648
abs(INT_MIN): -2147483648
int
値がゼロより大きいかどうかを確認するためにこれが必要です。
この質問が 最大負の整数-2147483648の絶対値がまだ-2147483648である理由 の重複であるということに関しては、これは方法であり、理由の質問ではないため、同意しない必要があります。
printf
のフォーマット文字列の%d
変換指定子は、対応する引数を符号付き10進整数に変換します。この場合、これはint
型に対してオーバーフローします。 C標準では、符号付き整数オーバーフローは未定義の動作であると具体的に言及されています。あなたがすべきことは、フォーマット文字列で%u
を使用することです。また、関数printf
とabs
のプロトタイプには、それぞれヘッダーstdio.h
とstdlib.h
を含める必要があります。
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
// This solves the issue of using the standard abs() function
unsigned int absu(int value) {
return (value < 0) ? -((unsigned int)value) : (unsigned int)value;
}
int main(void) {
printf("INT_MAX: %d\n", INT_MAX);
printf("INT_MIN: %d\n", INT_MIN);
printf("absu(INT_MIN): %u\n", absu(INT_MIN));
return 0;
}
これにより、32ビットマシンで出力が得られます。
INT_MAX: 2147483647
INT_MIN: -2147483648
absu(INT_MIN): 2147483648
最も負の数の絶対値を整数として抽出する移植可能な方法はありません。 ISO C規格によると(§6.2.6.2¶2):
値ビットである各ビットは、対応する符号なしタイプのオブジェクト表現の同じビットと同じ値を持つ必要があります(符号付きタイプにM個の値ビットがあり、符号なしタイプにNがある場合、M≤N)。
<ではなく≤を使用していることに注意してください。
2の補数の符号ビットの値は-(2M)、および各値ビットには、1と2)の間の2の累乗の値があります。M-1、M = Nが2)を表すことができる実装では符号なし整数はありませんN、最大2)までしか表現できませんN-1 = 1 + 2 + ... + 2N-1。
どうですか
_printf ("abs(INT_MIN) = %ld", -((long int) INT_MIN));
_
または、long
がint
より長くない場合:
_printf ("abs(INT_MIN) = %lld", -((long long int) INT_MIN));
_
または、abs(INT_MIN)
が常に_INT_MAX + 1
_であることを受け入れる準備ができている場合:
_printf ("abs(INT_MIN) = %u", ((unsigned int) INT_MAX ) + 1 );
_
Cでは、関数int abs(int j)
のintバージョンのみが存在します。ヘッダー_stdlib.h
_の下で別の関数labs
を使用できます。そのプロトタイプ:long int labs(long int j);
_#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("INT_MAX: %d\n", INT_MAX);
printf("INT_MIN: %d\n", INT_MIN);
printf("abs(INT_MIN): %ld\n", labs((long)INT_MIN));
return 0;
}
_
次に利用可能なより大きな整数型にキャストすると、それが実行されます。ただし、対応するabs-variant(この場合はllabs(...)
)を使用する必要があります。
printf("llabs(INT_MIN): %lld\n", llabs((long long int)INT_MIN));
編集:
INT_MIN
をLONG_MIN
およびLLONG_MIN
と比較することで、次に大きいタイプを確認できます。たぶんあなたの場合、long
へのキャストはすでにそれをしているでしょう。
printf("labs(INT_MIN): %ld\n", labs((long int)INT_MIN));
関数自体が引数を暗黙的にキャストするため、明示的なキャストは実際には不要であることに注意してください