このページの解説は C99 をベースとしています。
以下は目次です。
ある数値の絶対値を求めたいとします。
絶対値は 0 からの距離です。+3 の絶対値は 3 ですし、-3 の絶対値も 3 です。
絶対値を求める関数は標準に存在していますから、これを使えばいいです。ただし、型の違いによる使い分けが必要です。また、インクルードすべき標準ヘッダも異なります。
【上級】これらのほかに、複素数型を扱う関数が complex.h にあります。また、math.h と complex.h の関数については、型の違いによらず同じ名前が使えるようにする型総称マクロが tgmath.h に定義されています。
いずれの関数も、絶対値を求めたい値を実引数にして呼び出せば、戻り値で結果が返ってきます。
#include <inttypes.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
("%d\n", abs(100));
printf("%ld\n", labs(100L));
printf("%lld\n", llabs(100LL));
printf("%f\n", fabsf(12.3f));
printf("%lf\n", fabs(12.3));
printf("%Lf\n", fabsl(12.3L));
printf("%" PRIdMAX "\n", imaxabs(INTMAX_C(100)));
printf
("---");
puts
("%d\n", abs(-100));
printf("%ld\n", labs(-100L));
printf("%lld\n", llabs(-100LL));
printf("%f\n", fabsf(-12.3f));
printf("%lf\n", fabs(-12.3));
printf("%Lf\n", fabsl(-12.3L));
printf("%" PRIdMAX "\n", imaxabs(INTMAX_C(-100)));
printf}
実行結果:
100
100
100
12.300000
12.300000
12.300000
100
---
100
100
100
12.300000
12.300000
12.300000
100
絶対値を取得する際には1点、重大な落とし穴があります。
数を表現するしくみ上、ある型で表現できる一番小さい数(つまり、表現できる負数の中で一番小さい数)の絶対値は、表現できない可能性があるということです。
ここで取り上げた標準の関数の場合、結果が表現できないときには、未定義の動作📘となります。つまり、そのような値を渡さないようにする責任は我々の側にあります。
具体的には、数の表現に、2の補数表現📘を使う環境で問題になります。この表現方法では、負数の方が正数よりも 1つだけ多くの数を扱えます(たとえば -128~+127のように)。2の補数表現は非常に一般的であり、ほとんどの環境がこの表現方法を使っています(「情報処理技術編>負の数の表現」のページを参照)
たとえば、int型で表現できる一番小さい数は INT_MINマクロで、一番大きい数は INT_MAXマクロで得られますが、abs(INT_MIN)
とした結果は表現できない可能性があります。
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
("%d\n", abs(INT_MIN)); // 未定義の動作になり得る
printf}
絶対値は、元の数が正の数ならそのまま、負の数なら符号を反転する、という単純な操作で求められます。そのため、自力で実装してしまうことも考えられます。
#include <stdio.h>
int main(void)
{
int v1 = 100;
int v2 = -100;
("%d\n", v1 >= 0 ? v1 : -v1);
printf("%d\n", v2 >= 0 ? v2 : -v2);
printf}
実行結果:
100
100
この方法を使う場合も、方法① で取り上げたとおり、表現できる一番小さい数の絶対値は表現できない可能性があることに注意してください。
この方法を使うのなら、関数形式マクロ(第28章)にして用意しておけば、ほかの型でもそのまま使える利点があります。
#define ABS(v) ((v) >= 0 ? (v) : -(v))
関数でできることにマクロを持ち出すのは、あまり良い考えではありませんが(第28章)、このような絶対値マクロはよく使われています。
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#define ABS(v) ((v) >= 0 ? (v) : -(v))
int main(void)
{
("%d\n", ABS(100));
printf("%ld\n", ABS(100L));
printf("%lld\n", ABS(100LL));
printf("%f\n", ABS(12.3f));
printf("%lf\n", ABS(12.3));
printf("%Lf\n", ABS(12.3L));
printf("%" PRIdMAX "\n", ABS(INTMAX_C(100)));
printf
("---");
puts
("%d\n", ABS(-100));
printf("%ld\n", ABS(-100L));
printf("%lld\n", ABS(-100LL));
printf("%f\n", ABS(-12.3f));
printf("%lf\n", ABS(-12.3));
printf("%Lf\n", ABS(-12.3L));
printf("%" PRIdMAX "\n", ABS(INTMAX_C(-100)));
printf}
実行結果:
100
100
100
12.300000
12.300000
12.300000
100
---
100
100
100
12.300000
12.300000
12.300000
100
return 0;
を削除(C言語編全体でのコードの統一)
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
![]() |
管理者情報 | プライバシーポリシー |